创建型设计模式

340 阅读6分钟

创建型设计模式顾名思义负责对象创建和管理的。单例模式和原型模式比较好理解,单例模式内存中只有一个对象的实例。原型模式是要求通过复制的方式产生一个新的对象。 工厂方法模式,抽象工厂模式和建造者模式这几个概念比较容易混淆。

1 工厂模式

工厂模式分为:简单工厂模式,工厂方法模式和抽象工厂模式。不过在GOF《设计模式》一书中将简单工厂看成工厂方法模式的一种特例.

1.1. 简单工厂

简单工厂也叫静态工厂,一般是具体产品的继承类或是接口的实现.

/**
 * 产品
 */
public interface Car {

    public void run();
}
/**
 * 具体产品的工厂
 */
public class AodiCar implements Car{
    @Override
    public void run() {
        System.out.println("i  am aodi car");
    }
}
/**
 * 具体产品的工厂
 */
public class BaomaCar implements Car {
    @Override
    public void run() {
        System.out.println("i  am baoma car");
    }
}
/**
 * 核心工厂类
 */
public class CarFactory {

    public static Car createCar(String name) {
        if (name.equals("aodi")) {
            return new AodiCar();
        } else if (name.equals("baoma")) {
            return new BaomaCar();
        }
        return null;
    }
}

image.png

上面可以看出来,简单工厂模式是违反了开闭原则的,每新加一种车型需要修改核心工厂类的if 分支逻辑。其实我们平时应用也主要看具体的业务场景,比如你的产品类型就只有3种,简单工厂完全满足,就没有必要去做过度的设计。

1.2. 工厂方法模式

1.2.1 定义

工厂方法模式Factory Method,又称多态性工厂模式。
Define an interface for creating an object,but let subclasses decide witch class to instantiate. Factory Method lets a class defer instantiation to subclasses. 在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节
image.png

抽象产品类,具体的产品可以有多个,都继承抽象的产品 image.png

抽象工厂类,负责定义产品对象的生产. image.png

具体一个产品如何产生对象,是有具体的工厂类来实现的. image.png

上面的简单工厂我们可以改造一下

image.png

image.png

image.png

1.3. 抽象工厂模式

1.3.1 定义

  • 抽象工厂(Abstract Factory pattern)是一种比较常见的设计模式.
    Provider an interface for creating families of relate or dependent objects without specifying their concrete classes.
    为创建一组相关或相互依赖的对象提供一个接口,而无需指定他们的具体类.

image.png

image.png

2. 建造者模式

2.1 定义

建造者模式(Build Pattern)也叫生成器模式.
Separate the construction of complex object from its representation so that the same construction process can create different representations.
是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的方式进行创建.

image.png

在建造者模式中有如下4个角色

    1. builder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
    1. ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。
    1. Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
    1. Product:要创建的复杂对象。

2.2 使用场景

比如我们常见的工具类中,hutool 工具类包中线程池的创建都是用的建造者模式.

  1. 需要生成的对象具有复杂的内部结构。
  2. 需要生成的对象内部属性本身相互依赖。

2.3 代码案例

image.png 这样创建一个线程池是不是很清晰,使用的人也不容易出错.上面是基于hutool对于线程池二次封装,其实这个思想我们自己中间件的一些二方库包可以采取这种设计模式.

3. 单例模式

3.1 定义

单例模式(Singleton Pattern) 是一个比较简单的设计模式.
Ensure a class has only one instance,and provide a gloable point of access to it.
确保一个类只有一个实例,而且自行实例化并向整个系统提供整个实例.

image.png

3.2 使用场景

  1. 网站的计数器,一般也是采用单例模式实现,否则难以同步。
  2. 应用程序的日志应用,一般都是单例模式实现,只有一个实例去操作才好,否则内容不好追加显示。
  3. 多线程的线程池的设计一般也是采用单例模式,因为线程池要方便对池中的线程进行控制
  4. Windows的(任务管理器)就是很典型的单例模式,他不能打开俩个
  5. windows的(回收站)也是典型的单例应用。在整个系统运行过程中,回收站只维护一个实例。

3.3 单例的创建方式

  1. 饿汉式
  2. 懒汉式
  3. 静态内部类
  4. 枚举
  5. DCL单例模式

3.3 代码案例

image.png

image.png

image.png

image.png

4. 原型模式

4.1 定义

原型模式(Prototype Pattern)
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying the prototype.
用原型实例指定创建类的种类,并且通过拷贝这些原型创建新的对象.

image.png

4.2 使用场景

  1. 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。这时我们就可以通过原型拷贝避免这些消耗。
  2. 通过new产生的一个对象需要非常繁琐的数据准备或者权限,这时可以使用原型模式。
  3. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。

Spring框架中的多例就是使用的原型设计模式.

使用方法:

  • 实现Cloneable接口
  • 重写Object类中的clone方法. 原型模式有分为浅拷贝和深拷贝

4.3 代码案例

AdvTemplate 活动通知模板

public class AdvTemplate {

    private String subject = "xxx银行国庆抽奖活动";

    private String context = "国庆抽奖活动通知";

    public String getContext() {
        return context;
    }
    public String getSubject() {
        return subject;
    }
}

Mail 类

@Data
public class Mail implements Cloneable {

    /**
     * 邮件接收者
     */
    private String receiver;

    /**
     * 主题
     */
    private String subject;

    /**
     * 昵称
     */
    private String nickName;

    /**
     * 内容
     */
    private String context;

    /**
     * 结尾
     */
    private String tail;

    public Mail(AdvTemplate template) {
        this.context = template.getContext();
        this.subject = template.getSubject();
    }

    @Override
    public Mail clone() {
        Mail mail = null;
        try {
            mail = (Mail) super.clone();
        } catch (Exception e) {

        }
        return mail;
    }
}

复制的时候存在一个潜在的坑,默认引用类型为浅复制,所以我们在写colone函数的时候需要注意.

参考

《设计模式之禅》
《GOF23种设计模式》

其他代码中的案例可以参考我的github上的例子
github.com/liuyichun/d…