创建型模式

posted
read
891 words · 3 min
contents

创建型模式 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 已存在,实际调用前应处理未命中缓存的情况。