创建型模式
- 封装了系统使用哪些类
- 隐藏了这些类类的实例是如何创建和放在一起的
建造者
将复杂对象的构建与表示相分离,同样的构建过程可以创建不同的表示
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) //初始化对象