创建型模式
- 封装了系统使用哪些类
- 隐藏了这些类类的实例是如何创建和放在一起的
建造者
将复杂对象的构建与表示相分离,同样的构建过程可以创建不同的表示
classDiagram
    class Builder {
        +buildPart()
    }
    class ConcreteBuilder {
        +buildPart()
        +getResult()
    }
    Builder <|-- ConcreteBuilder
    ConcreteBuilder --> Product
    class Director {
        +construct()
    }
    Director o--> Builder
- 可以改变一个产品内部表示
- 构造代码与表示代码分离
- 对构造进行更细粒度的控制
interface Builder{
    Builder process1();
    Builder process2();
    Builder process3();
    Product build();
}
class ConcreteBuilder implements Builder{
    // 方法实现...
}
class ProductDirector{
    public Product constructProduct(Builder builder){
        builder.process1();
        builder.process2();
        builder.process3();
        return builder.build();
    }
}
// 使用
ProductDirector director = new ProductDirector();
Product product = director.constructProduct(new ConcreteBuilder());
工厂模式
简单工厂
客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可
class Factory{
    public Product get(int condition){
        switch(condition){
            case 1:
                return new Product1();
            case 2:
                return new Product2();
        }
        return null;
    }
}
但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护
工厂方法
定义一个接口,让子类创建该接口的实例,也就是将实例化延迟到工厂的子类

- 工厂方法模式适合于构造同属于同一个类别的不同产品,所有的产品属于同一个系列中
模板方式和工厂模式的核心思想非常类似, 都是把一些操作留给子类去实现。模板方法经常使用工厂方法作为其算法的一部分
abstract class AbstractCreator{
    abstract Product get();
    public void doSomething(){
        // do something
        Product product = get();
        // do something
    }
}
class Creator1 extends AbstractCreator{
    Product get(){...}
}
class Creator2 extends AbstractCreator{
    Product get(){...}
}
// 使用
Factory factory = new Creator2();
Product product = factory.doSomething();
抽象工厂
提供一个创建一系列相关或相互依赖对象的接口,而无需指定具体类

- 分离了具体的类
- 使得产品改变变得容易
- 利于维护产品的一致性
- 扩展产品种类困难
abstract class Factory{
    abstract Product get(int condition);
}
class ProductAFactory extends Factory{
    ProductA get(int condition){...}
}
class ProductBFactory extends Factory{
    ProductB get(int condition){...}
}
// 使用
Factory factory = new ProductAFactory();
Product product = factory.get(condition);
在实践中,每个工厂一般都会是单例。工厂内部可使用原型模式来实现
原型
通过一个原型对象创建新的对象
classDiagram
    class Prototype {
        +clone()
    }
    class ConcretePrototype1 {
        +clone()
    }
    class ConcretePrototype2 {
        +clone()
    }
    Prototype <|-- ConcretePrototype1
    Prototype <|-- ConcretePrototype2
    Client --> Prototype
- 可以在运行时刻动态改变产品种类
- 改变值或结构就能获得新对象
- 动态配置
class Product {
    Part1 part1;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Product product = (Product) super.clone();
        product.part1 = (Part1)part1.clone();
        return product;
    }
}
单例
一个类仅有一个实例,并只拥有一个全局访问点
问题:谁来销毁单例对象?什么时候销毁?
- 单例模式适用于生命周期很长的对象 一般不会显式销毁
- 使用SingletonDestroyer在程序关闭时进行销毁- 对于相互依赖的单例对象 需要注意顺序
 
饿汉式
- 类初始化时,会立即加载该对象,线程天生安全,调用效率高
public class Singleton {
    private static final Singleton SINGLETON = new Singleton();
    private Singleton() { }
    
    public static Singleton getInstance(){
        return SINGLETON;
    }
}
懒汉式
- 类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能
public class Singleton {
    private static Singleton SINGLETON ;
    private Singleton() { }
    // 线程不安全
    public static Singleton getInstance(){
        if (SINGLETON == null){
            SINGLETON = new Singleton();
        }
        return SINGLETON;
    }
}
静态内部类方式
- 结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的
public class Singleton {
    
    private Singleton() { }
    private static class SingletonClass{
        public static final Singleton SINGLETON = new Singleton();
    }
    
    public static Singleton getInstance(){
        return SingletonClass.SINGLETON;
    }
}
枚举单例
- 使用枚举实现单例模式 优点:实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞, 缺点没有延迟加载
public class Singleton {
    private Singleton() { }
    private enum  SingletonEnum{
        INSTANCE;
        private Singleton singleton;
        SingletonEnum() {
            singleton = new Singleton();
        }
        public Singleton getSingleton() {
            return singleton;
        }
    }
    public static Singleton getInstance(){
        return SingletonEnum.INSTANCE.getSingleton();
    }
}
双重检测加锁
public class Singleton {
    private static volatile Singleton SINGLETON; // 如果没有volatile JVM的指令重排序很有可能导致实例化多个对象
    private Singleton() { }
    public static Singleton getInstance(){
        if (SINGLETON == null){
            synchronized (Singleton.class){
                if (SINGLETON == null){
                    SINGLETON = new Singleton();
                }
            }
        }
        return SINGLETON;
    }
}
// SINGLETON = new Singleton() 可以分解为以下三个步骤
1 memory=allocate();// 分配内存 相当于c的malloc
2 ctorInstanc(memory) //初始化对象
3 s=memory //设置s指向刚分配的地址
// 上述三个步骤可能会被重排序为 1-3-2,也就是:
1 memory=allocate();// 分配内存 相当于c的malloc
3 s=memory //设置s指向刚分配的地址
2 ctorInstanc(memory) //初始化对象