创建型模式

Wu Jun 2020-01-06 08:43:49
Categories: > Tags:

1. Factory(工厂)

1 简单工厂(Simple Factory)

根据参数的不同返回不同类的实例。

在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。

简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。

这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节。而且一旦子类发生改变,例如增加子类,那么所有的客户类都要进行修改。

模式应用

java.text.DateFormat

public final static DateFormat getDateInstance(int style);

2 工厂方法(Factory Method)

不传参数,而是分别建立工厂,使用工厂方法

模式应用

JDBC 中的工厂方法

Connection conn = DriverManager.getConnection("jdbc:……");
Statement statement = conn.createStatement();

3 抽象工厂(Abstract Factory)

系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

模式应用

在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变。

3.1 增加工厂

  1. 新增一个工厂子类
  2. 并增加相应产品子类

3.2 增加产品

  1. 新增一个产品父类
  2. 再增加对应每个工厂的产品子类
  3. 最后在工厂父类、子类中新增产品方法

2. Builder(建造者)

使用多个简单的对象一步一步构建成一个复杂的对象。

工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象,多个部分

MealBuilder mealBuilder = new MealBuilder();
Meal vegMeal = mealBuilder.prepareVegMeal();
Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
模式应用

3. Prototype(原型)

当直接创建对象的代价比较大时,创建当前对象的克隆

原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。

//原型角色:定义用于复制现有实例来生成新实例的方法;
// 1.(抽象类或者接口)实现 java.lang.Cloneable 接口
// 2.定义复制现有实例来生成新实例的方法
public abstract class Shape implements Cloneable {
    public Object clone() {
    }
}
//具体原型角色:实现用于复制现有实例来生成新实例的方法
// 1.实现复制现有实例来生成新实例的方法(也可以由超类完成)
public class Rectangle extends Shape {
}
//使用者角色:维护一个注册表,并提供一个找出正确实例原型的方法。最后,提供一个获取新实例的方法,用来委托复制实例的方法生成新实例。
public class ShapeCache {
   //维护一个注册表
   private static Hashtable<String, Shape> shapeMap 
      = new Hashtable<String, Shape>();
      
   public static Shape getShape(String shapeId) {
      Shape cachedShape = shapeMap.get(shapeId);
      return (Shape) cachedShape.clone();
   }
   
   public static void loadCache() {
      Circle circle = new Circle();
      circle.setId("1");
      shapeMap.put(circle.getId(),circle);
   }
}
模式应用

一个对象需要在一个高代价的数据库操作之后被创建,可以缓存该对象,在下一个请求时返回它的克隆

4. Singleton(单例)

单例类只有一个实例,而且自行实例化并向整个系统提供这个实例

构造函数私有

模式应用

几种实现方式

建议使用饿汉方式。只有在要明确实现懒加载效果时,才使用静态内部类方式。如果涉及到反序列化创建对象时,可以尝试使用枚举方式。如果有其他特殊的需求,可以考虑使用双检锁方式。

饿汉式

类加载时就初始化

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
        return instance;  
    }  
}

静态内部类

延迟加载,类加载线程互斥

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}

枚举

支持序列化,最佳方法

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

双重校验锁

singleton = new Singleton();可能被优化为先分配空白空间给singleton,再初始化。所以synchronized里有可能singleton == null为true,但还未初始化,会出错。

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
        if (singleton == null) {  
            synchronized (Singleton.class) {  
                if (singleton == null) {  
                    singleton = new Singleton();  
                }  
            }  
        }  
        return singleton;  
    }  
}