创建型设计模式

87 阅读4分钟

工厂模式

简单工厂模式

概念: Simple Factory Pattern, 由一个工厂对象决定创建出哪一种产品类的实例, 不属于GOF23种设计模式。适用于工厂类创建的对象较少的场景,客户端需要传入工厂类的参数,对于创建的逻辑并不关心。

源码示例: Calendar, LoggerFactory, DateFormat

经典写法:

public ICource create(String className){
    try{
        if(StringUtils.isNotBlank(className)){
           return (ICource)Class.forName(className).newInstance();
        }
    }catch(Exception e){
        e.printStackTrace();
    }
    return null;
}

工厂方法模式

概念: Factory Method Pattern, 定义一个创建对象的接口, 让实现这个接口的类来决定实例化哪个类, 工厂方法让类的实例化推迟到子类中进行。主要解决的是产品扩展的问题。

源码示例: ILogggerFactory, Logger

抽象工厂模式

概念: 创建一系列相关或相互依赖对象的接口,无须指定它们具体的类。主要理解产品等级结构和产品族两个概念。产品族增加了系统的抽象性和理解难度。

单例模式

概念: Singleton Pattern, 是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

源码示例: ServletContext, ServletContextConfig, ApplicationContext

饿汉式

类加载时立即初始化创建单例对象,绝对线程安全,不存在访问安全问题。

优点在于保证绝对线程安全,执行效率高。缺点在于所有对象类加载的时候就实例化, 浪费内存空间。所以饿汉式适用于单例对象较少的情况。

经典写法:

public static Hungry{
    private static final Hungry hungry = new Hungry();
    private Hungry(){}
    public static Hungry getInstance(){
        return hungry;
    }
}
懒汉式

单例对象在要被使用时才会初始化。

经典写法:

public class Lazy{
    private Lazy(){}
    private volatile static Lazy lazy = nullpublic static Lazy getInstance(){
        if(null == lazy){
            synchronized(Lazy.class){
                if(null == lazy){
                   lazy = new Lazy(); 
                }
            }
        }
        return lazy;
    }
}

这是双重检验锁(DCL)。之所以要加volatile,是为了防止指令重排序。在lazy = new Lazy();代码中,分成分配内存给对象; 初始化对象; 设置lazy指向分配的内存地址。而后两个step可能会重排序,所以需要使用volatile禁止重排序。

静态内部类

在类初始化时进行对象初始化, 这种方法兼顾了饿汉式的内存浪费和懒汉式同步的性能问题。

public class LazyInner{
    private LazyInner(){}
    public static final LazyInner getInstance(){
        return LazyHolder.LAZY;
    }
    private static class LazyHolder{
        private static final LazyInner LAZY = new LazyInner();
    }
}

注册式单例

将每个实例都注册到某个容器中,使用唯一标识获取单例。主要有两种: 一种是枚举式单例模式, 一种是容器式单例模式。

枚举式单例模式,就是利用枚举

容器式单例模式案例:

public class Container{
    private Container(){}
    private static Map<String, Object> ioc = new ConcurrentHashMap<String,Object>();
    public static Object getBean(String className){
        synchronized (ioc){
            if(!ioc.containsKey(className)){
                Object obj = null;
                try{
                    obj = Class.forName(className).newInstance();
                    ioc.put(className, obj);
                } catch (Exception e){
                    e.printStackTrace();
                }
                return obj;
            }
            return ioc.get(className);
        }
    }
}

ThreadLocal线程单例

ThreadLocal将所有的对象都放在ThreadLocalMap中, 为每个线程都提供一个对象,以空间换时间实现线程隔离。

两种破坏单例的情况: 反射破坏&序列化破坏

反射破坏通过构造方法中抛异常可以防止, 序列化破坏是要增加readResolve方法可以防止

原型模式

概念: Prototype Pattern, 原型实例指定创建对象的种类, 通过拷贝这些原型创建新的对象。主要包含三个角色: 客户, 抽象原型, 具体原型。

主要适用于

  • 类初始化消耗资源较多
  • new产生的一个对象需要非常繁琐的过程
  • 构造函数比较复杂
  • 循环体中生产大量对象

一般用序列化实现深克隆。

建造者模式

概念: Builder Pattern, 将一个复杂对象的构建过程和它的表示分离,使同样的构建过程可以创建不同的表示,属于创建型模式。主要包含产品,建造者抽象,建造者, 调用者四个角色。

适用于创建对象需要很多步骤, 但是步骤的顺序不一定固定。

建造者模式可以用来校验必填项,设置各属性的依赖关系,设置不可变对象。