创建型模式 Creational Patterns
- 创建型模式关注如何创建对象,将对象的实例化和声明相分离。
- 关注于对象的创建过程,目的是将对象的实例化与客户端的使用分离。
- 通过这种方式,系统中的具体类的实例化不会使代码变得僵硬,增加了系统的灵活性和可维护性。
- 更有效地封装和抽象化对象的创建过程。
创建型模式包括:
- 单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点。
- 工厂方法模式(Factory Method):定义一个创建对象的接口,让子类决定实例化哪一个类。
- 抽象工厂模式(Abstract Factory):提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。
- 建造者模式(Builder):使用多个简单的对象一步一步构建成一个复杂的对象。
- 原型模式(Prototype):通过复制现有的实例来创建新的实例,而不是通过新建实例。
单例模式
保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
懒汉式双重校验锁(DCL,即 double-checked locking):
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; }}volatile: 这是 Java 语言的一个关键字,用于指示 JVM(Java 虚拟机),这个变量可能会被多个线程同时访问和修改,但是它不会被线程缓存(每次访问变量时都要从主内存中读取),并且每次修改都会立即写入主内存。这个关键字的主要作用是确保变量的可见性和防止指令重排序优化,这对于多线程环境下安全创建单例至关重要。
工厂方法模式
- 在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
- 如果无法预知对象确切类别及其依赖关系时, 可使用工厂方法。
- 如果你希望用户能扩展你软件库或框架的内部组件, 可使用工厂方法。
- 如果你希望复用现有对象来节省系统资源, 而不是每次都重新创建对象, 可使用工厂方法。
public interface Shape { void draw();}////////////////////////////////public class Rectangle implements Shape { @Override public void draw() { System.out.println(); }}//////////////public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象 public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if ... return null; }}抽象工厂模式
- 创建一系列相关的对象
- 无需指定其具体类。
- 其他工厂的工厂。
//定义抽象工厂
public interface GUIFactory { Button createButton(); Checkbox createCheckbox();}
// 接着,定义 Button 和 Checkbox 接口:
public interface Button { void paint();}
public interface Checkbox { void paint();}
// 然后,实现具体的工厂类 WinFactory 和 MacFactory:
public class WinFactory implements GUIFactory {82 collapsed lines
@Override public Button createButton() { return new WinButton(); }
@Override public Checkbox createCheckbox() { return new WinCheckbox(); }}
public class MacFactory implements GUIFactory { @Override public Button createButton() { return new MacButton(); }
@Override public Checkbox createCheckbox() { return new MacCheckbox(); }}
// 定义具体产品类 WinButton, WinCheckbox, MacButton, 和 MacCheckbox:
public class WinButton implements Button { @Override public void paint() { System.out.println("Rendering a button in Windows style."); }}
public class MacButton implements Button { @Override public void paint() { System.out.println("Rendering a button in macOS style."); }}
public class WinCheckbox implements Checkbox { @Override public void paint() { System.out.println("Rendering a checkbox in Windows style."); }}
public class MacCheckbox implements Checkbox { @Override public void paint() { System.out.println("Rendering a checkbox in macOS style."); }}
// 最后,实现客户端代码 Application 和 ApplicationConfigurator:
public class Application { private GUIFactory factory; private Button button;
public Application(GUIFactory factory) { this.factory = factory; }
public void createUI() { this.button = factory.createButton(); }
public void paint() { button.paint(); }}
public class ApplicationConfigurator { public static void main(String[] args) { GUIFactory factory; String OS = System.getProperty("os.name");
if (OS.contains("Windows")) { factory = new WinFactory(); } else if (OS.contains("Mac")) { factory = new MacFactory(); } else { throw new RuntimeException("Error! Unknown operating system."); }
Application app = new Application(factory); app.createUI(); app.paint(); }}Application 依赖 GUIFactory 和 Button 抽象;切换产品家族仍需在配置入口选择对应工厂。新增产品种类则需要修改工厂接口及各具体工厂。
建造者模式
- AKA生成器模式
- 分步骤创建复杂对象
- 使用相同的创建代码生成不同类型和形式的对象。
- 链式编程
- 只有当产品较为复杂且需要详细配置时,使用生成器模式才有意义。
public class Car { // 假设这里有一些属性和方法来表示汽车的各种特性}
public class Manual { // 假设这里有一些属性和方法来表示手册的各种特性}
// 接下来是 `Builder` 接口的定义,包括创建产品对象不同部件的方法:
public interface Builder { void reset(); void setSeats(int number); void setEngine(String engine); void setTripComputer(boolean present); void setGPS(boolean present);}
// 然后,我们实现具体的生成器类 `CarBuilder` 和 `CarManualBuilder`:
102 collapsed lines
public class CarBuilder implements Builder { private Car car;
public CarBuilder() { this.reset(); }
@Override public void reset() { this.car = new Car(); }
@Override public void setSeats(int number) { // 实现设置座位数的逻辑 }
@Override public void setEngine(String engine) { // 实现设置引擎的逻辑 }
@Override public void setTripComputer(boolean present) { // 实现设置行车电脑的逻辑 }
@Override public void setGPS(boolean present) { // 实现设置GPS的逻辑 }
public Car getProduct() { Car product = this.car; this.reset(); return product; }}
public class CarManualBuilder implements Builder { private Manual manual;
public CarManualBuilder() { this.reset(); }
@Override public void reset() { this.manual = new Manual(); }
@Override public void setSeats(int number) { // 实现添加关于座椅的文档逻辑 }
@Override public void setEngine(String engine) { // 实现添加关于引擎的介绍逻辑 }
@Override public void setTripComputer(boolean present) { // 实现添加关于行车电脑的介绍逻辑 }
@Override public void setGPS(boolean present) { // 实现添加关于GPS的介绍逻辑 }
public Manual getProduct() { Manual product = this.manual; this.reset(); return product; }}
// 接着,实现 `Director` 类,它负责定义构建过程的不同步骤:
public class Director { public void constructSportsCar(Builder builder) { builder.reset(); builder.setSeats(2); builder.setEngine("SportEngine"); builder.setTripComputer(true); builder.setGPS(true); }
// 这里可以添加更多的方法来构建不同类型的汽车}
// 最后是客户端代码,它演示了如何使用这些类来构建产品:
public class Application { public static void main(String[] args) { Director director = new Director();
CarBuilder carBuilder = new CarBuilder(); director.constructSportsCar(carBuilder); Car car = carBuilder.getProduct();
CarManualBuilder manualBuilder = new CarManualBuilder(); director.constructSportsCar(manualBuilder); Manual manual = manualBuilder.getProduct();
// 在这里,car 和 manual 是根据相同的构建过程创建的, // 但它们是完全不同的产品。 }}此处 setter 省略了实际赋值逻辑,只展示构建步骤与产品表示的分离;用于业务代码前需补全产品属性及校验。
原型模式
-
复制已有对象
-
当直接创建对象的代价比较大时,则采用这种模式。
-
Java 中,原型模式通常通过实现
Cloneable接口并重写Object类的clone()方法来实现。
import java.util.HashMap;import java.util.Map;
// 抽象类实现 Cloneable 接口abstract class Shape implements Cloneable { private String id; protected String type;
abstract void draw();
public String getType() { return type; }
public String getId() { return id; }
public void setId(String id) { this.id = id;60 collapsed lines
}
public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; }}
// 具体的形状类class Rectangle extends Shape { public Rectangle() { type = "Rectangle"; }
@Override void draw() { System.out.println("Inside Rectangle::draw() method."); }}
class Circle extends Shape { public Circle() { type = "Circle"; }
@Override void draw() { System.out.println("Inside Circle::draw() method."); }}
// 缓存类class ShapeCache { private static Map<String, Shape> shapeMap = new HashMap<>();
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);
Rectangle rectangle = new Rectangle(); rectangle.setId("2"); shapeMap.put(rectangle.getId(), rectangle); }}
// 客户端代码public class PrototypePatternDemo { public static void main(String[] args) { ShapeCache.loadCache();
Shape clonedShape1 = ShapeCache.getShape("1"); System.out.println("Shape : " + clonedShape1.getType());
Shape clonedShape2 = ShapeCache.getShape("2"); System.out.println("Shape : " + clonedShape2.getType()); }}super.clone() 是浅拷贝:以后若增加可变引用字段,克隆对象会共享这些引用,需按业务需要实现深拷贝。getShape() 假设 ID 已存在,实际调用前应处理未命中缓存的情况。