创建型设计模式
一、概述
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
- 单例模式(Singleton Pattern)
- 工厂模式(Factory Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
- 原型模式(Prototype Pattern)
- 建造者模式(Builder Pattern)
二、单例模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,让某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
使用场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等);Spring 默认注入对象都是单例模式的。
单例模式有多种实现方式,这里提供三种实现方式:
实现的选择:一般可用饿汉式,涉及反序列化用枚举,要求懒加载用静态内部类
- 饿汉式:无懒加载效果,缺点:无懒加载,无法防止反序列化
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return INSTANCE;
}
}
- 枚举实现:确保了单例,且能防止反序列化,缺点:无法懒加载
public enum SingletonEnum {
INSTANCE;
public void func() {
System.out.println("只能通过INSTANCE枚举执行我");
}
}
- 静态内部类:确保多线程下也能保持单例懒加载,缺点:无法防止反序列化创建对象
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
三、工厂模式
在工厂模式中,在创建对象时不会对调用方暴露创建逻辑,而是通过使用一个共同的接口来指向新创建的对象。
3.1 简单工厂模式(静态工厂模式)
看一个披萨项目:要便于披萨种类的扩展,要便于维护。
- 披萨的种类很多(比如 GreekPizza、CheesePizza 等)
- 披萨的制作有 prepare,bake, cut, box
- 完成披萨店订购功能PizzaOrder
传统方式:
public void orderPizza(String type) {
Pizza pizza = null;
if ("greek".equals(type)) {
pizza = new GreekPizza();
} else if ("cheese".equals(type)) {
pizza = new CheesePizza();
} else if ("paper".equals(type)) {
pizza = new PepperPizza();
} else {
throw new RuntimeException("No such pizza!");
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
上面设计违反了开闭原则,当需要增加一个披萨种类时,调用端也必须修改代码增加判断逻辑。用简单工厂模式实现,则可以将调用方与披萨接口的实现解耦,代码如下,此时增加品种,调用方也无需修改代码。
public class PizzaFactory {
public static Pizza getPizza(String type) {
Pizza pizza = null;
if ("greek".equals(type)) {
pizza = new GreekPizza();
} else if ("cheese".equals(type)) {
pizza = new CheesePizza();
} else if ("paper".equals(type)) {
pizza = new PepperPizza();
} else {
throw new RuntimeException("No such pizza!");
}
return pizza;
}
}
public void orderPizza(String type) {
Pizza pizza = PizzaFactory.getPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
3.2 工厂方法模式
披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒 pizza 或者是伦敦的奶酪 pizza、伦敦没有胡椒 pizza。
传统方式:将工厂分为北京的和伦敦的,分别生产不同口味的披萨
工厂方法模式:在上个工厂类中,新增两个方法,分别代表北京的披萨和伦敦的披萨,对应方法中再创建不同口味的实现类,这种方式即工厂方法模式。
3.3 抽象工厂模式
模式如其名,抽象工厂即超级工厂,用来进行统一工厂的创建,将分类进一步解耦。
3.3 工厂模式小结
注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
四、原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。需要克隆一个对象时,尽量不要创建新的对象,然后一个个设置值。
- Java中可以通过实现Cloneable接口,复写clone方法调用父类Object中的clone方法实现,注意:这种方式对于该类中引用数据类型会进行浅拷贝
- 通过序列化与反序列化的方式深拷贝克隆原型对象
原理结构图说明
- Prototype : 原型类,声明一个克隆自己的接口
- ConcretePrototype: 具体的原型类, 实现一个克隆自己的操作
- Client: 让一个原型对象克隆自己,从而创建一个新的对象(属性一样)
五、建造者模式
建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
主要解决在软件系统中,有时候面临着 “一个复杂对象” 的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
原理图中,创建过程由 Director 指定,也就是构建 Builder 的整体流程被抽象出来了,当需要根据情况,先执行 C 再执行 B时,只需要更改 Director 中的执行顺序即可。