一、设计模式的认识
二、设计模式的分类
根据其目的 根据范围
三、设计模式的优点
四、设计模式中关键点
五、创建型模式
简单(静态)工厂模式 工厂方法模式 抽象工厂模式 单例模式 原型模式 建造者模式
六、个人体会
一、设计模式的认识
设计模式(Design Pattern)是前辈们经过相当长的一段时间的试验和错误总结出来的,是软件开发过程中面临的通用问题的解决方案。这些解决方案使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
二、设计模式的分类
(1)根据其目的
即模式是用来做什么的,可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种:①创建型模式主要用于创建对象。②结构型模式主要用于处理类或对象的组合。③行为型模式主要用于描述对类或对象怎样交互和怎样分配职责。
(2) 根据范围
即模式主要是用于处理类之间关系还是处理对象之间的关系,可分为类模式和对象模式两种:类模式处理类和子类之间的关系,这些关系通过继承建立,在编译时刻就被确定下来,是属于静态的。对象模式处理对象间的关系,这些关系在运行时刻变化,更具动态性。
nerror="javascript:errorimg.call(this);"/>
UML说明:苹果手机和红米手机继承了手机这个抽象类,工厂类里根据客户端传入的参数生成相应的对象,如,客户说要红米,工厂给客户一个红米手机,客户说要苹果,工厂给客户一个苹果手机。
简单工厂有三个对象:①抽象产品类:提供抽象方法供具体产品类实现 ②具体产品类:提供具体的产品 ③工厂:根据内部逻辑返回相应的产品
3.代码实现
(1)抽象产品类Phone 这里可以是类,也可以是接口或者抽象类,千万不要思维定式。我比较喜欢面向接口编程,所以我这里用了接口。
public interface Phone {
void produce();
}(2)具体产品类
在这里插入代码片public class ApplePhoneImpl implements Phone{
@Override
public void produce() {
System.out.println("生产苹果手机");
}
}public class RedmiPhoneImpl implements Phone{
@Override
public void produce() {
System.out.println("生产了红米手机");
}
}(3)工厂类
public class Factory {
public Phone getPhone(String type){
Phone phone = ;
if("红米".equals(type)){
phone = new RedmiPhoneImpl();
}else if("苹果".equals(type)){
phone = new ApplePhoneImpl();
}//.....
return phone;
}
}(4)客户端使用
@Test
public void test1(){
Factory factory = new Factory();
Phone redmiPhone = factory.getPhone("红米");
System.out.println(redmiPhone);
redmiPhone.produce();
Phone applePhone = factory.getPhone("苹果");
System.out.println(applePhone);
applePhone.produce();
}运行结果如下:
nerror="javascript:errorimg.call(this);"/>
6.再升级(重要)
(1)工厂类:
public class FactoryPlusPlus {
private static String className="com.wander.design.simplefactory.product.ApplePhoneImpl";
public static Phone getPhone() throws Exception {
return (Phone) Class.forName(className).newInstance();
}
}nerror="javascript:errorimg.call(this);"/>
UML说明:苹果手机和红米手机实现了手机这个抽象类,苹果工厂和红米工厂实现了抽象工厂,苹果工厂当然要生产(依赖)苹果手机,红米工厂当然要生产(依赖)红米。客户要买苹果手机要去问苹果工厂要苹果手机,客户要买红米手机当然要去问红米工厂要红米手机。
工厂方法有四个对象:抽象产品类:提供抽象方法供具体产品类实现 具体产品类:提供具体的产品 抽象工厂:提供抽象方法供具体工厂实现 具体工厂:提供具体的工厂
3.代码实现
(1)抽象产品类和简单工厂的抽象产品类一样
(2)具体产品类和简单工厂的具体产品类一样
(3)抽象工厂
public interface Factory {
Phone getPhone();
}(4)具体工厂
public class AppleFactoryImpl implements Factory{
@Override
public Phone getPhone() {
return new ApplePhoneImpl();
}
}
public class RedmiFactoryImpl implements Factory{
@Override
public Phone getPhone() {
return new RedmiPhoneImpl();
}
}(5)客户端
@Test
public void test1(){
Factory applePhoneFactory = new AppleFactoryImpl();
Factory redmiPhoneFactory = new RedmiFactoryImpl();
Phone applePhone = applePhoneFactory.getPhone();
Phone redmiPhone = redmiPhoneFactory.getPhone();
System.out.println(applePhone);
System.out.println(redmiPhone);
applePhone.produce();
redmiPhone.produce();
}执行结果如下:
nerror="javascript:errorimg.call(this);"/>
工厂方法有四个对象:
①抽象产品类:为每种具体产品声明接口,如图中Phone手机抽象类和Charger充电器抽象类
②具体产品类:定义了工厂生产的具体产品对象,实现抽象产品接口声明的业务方法,如图中ApplePhoneImpl、RedmiPhoneImpl,AppleChargerImpl,RedmiChargerImpl
③抽象工厂:它声明了一组用于创建一种产品的方法,每一个方法对应一种产品,如上述类图中的Factory就定义了两个方法,分别创建Phone和Charger
④具体工厂:它实现了在抽象工厂中定义的创建产品的方法,生产一组具体产品,这组产品构件成了一个产品种类,每一个产品都位于某个产品等级结构中,如上述类图中的AppleFactoryImpl和RedmiFactoryImpl
3.代码实现
(1)抽象的产品
public interface Phone {
void produce();
}
public interface Charger {
void produce();
}(2)具体的产品
① 苹果具体的产品
public class AppleChargerImpl implements Charger{
@Override
public void produce() {
System.out.println("生产苹果充电器");
}
}
public class ApplePhoneImpl implements Phone {
@Override
public void produce() {
System.out.println("生产苹果手机");
}
}② 红米具体的产品
public class RedmiChargerImpl implements Charger{
@Override
public void produce() {
System.out.println("生产红米充电器");
}
}
public class RedmiPhoneImpl implements Phone {
@Override
public void produce() {
System.out.println("生产了红米手机");
}
}(3)抽象工厂
public interface Factory {
Phone getPhone();
Charger getCharger();
}(4)具体的工厂
public class AppleFactoryImpl implements Factory {
@Override
public Phone getPhone() {
return new ApplePhoneImpl();
}
@Override
public Charger getCharger() {
return new AppleChargerImpl();
}
}
public class RedmiFactoryImpl implements Factory {
@Override
public Phone getPhone() {
return new RedmiPhoneImpl();
}
@Override
public Charger getCharger() {
return new RedmiChargerImpl();
}
}(5)执行结果
nerror="javascript:errorimg.call(this);"/>
UML说明:1.构造方法私有化:可以使得该类不被实例化即不能被new 2.在类本身里创建自己的对象 3.提供一个公共的方法供其他对象访问
3.代码实现
(1)饿汉式
①第一种:
public class Singleton {
private static final Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getSingleton() {
return singleton;
}
}②第二种
public class SingletonStatic {
private static final SingletonStatic singletonStatic;
static {
singletonStatic = new SingletonStatic();
}
private SingletonStatic() {}
public static SingletonStatic getSingletonStatic(){
return singletonStatic;
}
}注:这里有两个小知识点:
a.如果是final非static成员,必须在构造器、代码块、或者直接定义赋值
b.如果是final static 成员变量,必须直接赋值 或者在静态代码块中赋值
(2)懒汉式
public class Singleton {
private static Singleton singleton = ;
private Singleton(){}
public static Singleton getSingleton() {
if(singleton == ){
singleton = new Singleton();
}
return singleton;
}
}说明:Spring ioc 单例 是懒汉式 枚举上的升级
(9)ThreadLocal单例
nerror="javascript:errorimg.call(this);"/>
UML说明:实体类实现Cloneable接口,重写clone方法
3.代码实现
(1)Prototype类:
public class Prototype implements Cloneable {
private Integer id;
private String name;
private Map<String, Double> map;
@Override
protected Prototype clone() throws CloneNotSupportedException {
//浅拷贝方式
Prototype prototype = (Prototype) super.clone();
//深拷贝方式:对每一个复杂类型分别进行克隆
//测试浅拷贝的时候注释下面代码
prototype.map = (Map<String, Double>) ((HashMap)this.map).clone();
return prototype;
}
public Prototype(Integer id, String name, Map<String, Double> map) {
this.id = id;
this.name = name;
this.map = map;
}
}(3)执行结果:浅拷贝:
nerror="javascript:errorimg.call(this);"/>
改变其中一个对象map的值,该对象的map内容发生了变化,另一个对象map的内容没有发生变化
4.总结
优点:①提高了性能,在需要短时间创建大量的对象和创建对象很耗时的情况下,原型模式比通过new对象大大提高了时间效率。
② 逃避构造函数的约束。
缺点:
1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、实现原型模式每个派生类都必须实现 Clone接口。
5.应用场景
1.通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。比如,向数据库表插入多条测试数据,可以用到。
2.在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为浑然一体,大家可以随手拿来使用。
(6)建造者模式
1.认识:
①一句话来说:封装一个复杂对象的构建过程,并可以按步骤构造。因为需要对对象一步步建造起来,所以称为建造者模式。
②将复杂产品的构建过程封装分解在不同的方法中,使得创建过程非常清晰,能够让我们更加精确的控制复杂产品对象的创建过程,同时它隔离了复杂产品对象的创建和使用,使得相同的创建过程能够创建不同的产品。但是若内部变化复杂,会有很多的建造类。
2.UML类图:
3.具体建造者
public class ConcreteBuilder extends Builder {
@Override
public void buildPart1() {
System.out.println("建造part1");
}
@Override
public void buildPart2() {
System.out.println("建造part2");
}
@Override
public void buildPart3() {
System.out.println("建造part3");
}
}5.客户端
public class Client {
@Test
public void test() {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.build();
}
}6.执行结果
nerror="javascript:errorimg.call(this);"/>
4.总结
优点:1、建造者独立,易扩展。将复杂产品的构建过程封装分解在不同的方法中,使得创建过程非常清晰,能够让我们更加精确的控制复杂产品对象的创建过程。
2、便于控制细节风险。它隔离了复杂产品对象的创建和使用,使得相同的创建过程能够创建不同的产品。
缺点:1、产品必须有共同点,范围有限制。
2、如内部变化复杂,会有很多的建造类,导致系统庞大。
应用场景1、需要生成的对象具有复杂的内部结构。2、需要生成的对象内部属性本身相互依赖。
5.应用场景
JAVA 中的 StringBuilder。
六、个人体会
设计模式是一种解决问题的思维和方式,不要生搬硬套,为了设计模式而模式。本文作者:王德印,欢迎复制下方链接关注博主动态。
链接:https://blog.csdn.net/qq_41889508/article/details/105953114nerror="javascript:errorimg.call(this);"/>

