设计模式专栏(二):创建型设计模式(Creational Design Patterns)(关注“Beyond Code 程序员”订阅号查看更多文章)
模式介绍
创建型设计模式主要关注如何实例化对象,即解决“对象如何被创建”的问题。它们将对象的创建过程与使用过程分离,通过不同的设计方案实现灵活、高效和可复用的对象创建方式。
通过创建型模式,可以:
- 降低系统与具体类的耦合度
- 提高系统的灵活性和可扩展性
- 方便对象的复用和管理
主要包含五种模式
- 单例模式(Singleton):保证一个类只有一个实例,并提供全局访问点。
- 工厂方法模式(Factory Method):定义一个创建对象的接口,由子类决定具体实例化的类。
- 抽象工厂模式(Abstract Factory):提供创建一系列相关对象的接口,而无需指定具体类。
- 建造者模式(Builder):将复杂对象的构建与表示分离,使同样的构建过程可以创建不同的表示。
- 原型模式(Prototype):通过复制已有对象来创建新对象,减少重复初始化成本。
⚠️ 提示:设计模式是一种编程思想,其实现方式并非唯一。本文示例代码仅作为参考,并不意味着设计模式必须按照示例中的方式实现。
1. 单例模式(Singleton Pattern)
模式解释
单例模式的核心思想是:
一个类只允许创建一个实例,并提供全局访问点。
适用场景:
- 配置管理类(全局只有一份配置)
- 数据库连接池(避免重复创建连接池)
- 日志管理器(全局统一日志入口)
代码示例(Java,懒汉式 + 双重检查锁,含测试代码)
// 单例类
public class Singleton {
// 1. 私有构造方法,禁止外部创建
private Singleton() {
System.out.println("单例对象被创建");
}
// 2. 使用 volatile 保证多线程可见性
private static volatile Singleton instance = null;
// 3. 提供全局访问点(线程安全)
public static Singleton getInstance() {
// 第一次检查,如果是全局第一次创建,才需要同步加锁创建对象,避免不必要的同步加锁
if (instance == null) {
synchronized (Singleton.class) {
// 当多线程同时到达这里,只有一个线程能获取到锁,该线程创建好单例对象后,会释放锁;
// 第二个线程获取锁时,由于单例对象已经被第一个线程创建,如果不再次判断,会导致重复创建;
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
// 业务方法
public void doSomething() {
System.out.println("单例方法执行中...");
}
// 测试入口
public static void main(String[] args) {
// 第一次调用会创建实例
Singleton s1 = Singleton.getInstance();
s1.doSomething();
// 第二次调用不会创建新实例
Singleton s2 = Singleton.getInstance();
// 验证两个对象是否相同
System.out.println("两个实例是否相同:" + (s1 == s2));
}
}
运行效果
单例对象被创建
单例方法执行中...
两个实例是否相同:true
总结
优点:
- 节省系统资源(避免重复创建对象)
- 全局统一访问点(方便管理)
缺点:
- 多线程下需小心处理(本例用双重检查锁解决)
- 可能隐藏类间依赖关系(调试时不易发现)
2. 工厂方法模式(Factory Method Pattern)
模式解释
工厂方法模式核心思想是:
定义一个创建对象的接口,但由子类决定实例化哪一个类。使一个类的实例化延迟到子类。
适用场景:
- 需要灵活创建不同类型对象的场景
- 客户端不关心具体产品实现,只关心接口
代码示例(Java,含测试代码)
// 产品接口
interface Product {
void use();
}
// 具体产品A
class ConcreteProductA implements Product {
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品B
class ConcreteProductB implements Product {
public void use() {
System.out.println("使用产品B");
}
}
// 工厂接口
interface Factory {
Product createProduct();
}
// 具体工厂A
class ConcreteFactoryA implements Factory {
public Product createProduct() {
return new ConcreteProductA();
}
}
// 具体工厂B
class ConcreteFactoryB implements Factory {
public Product createProduct() {
return new ConcreteProductB();
}
}
// 测试代码
public class FactoryMethodDemo {
public static void main(String[] args) {
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.use();
Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.use();
}
}
运行效果
使用产品A
使用产品B
总结
优点:
- 遵循单一职责原则,封装了具体产品创建过程
- 扩展性好,添加新产品只需新建工厂和产品类
缺点:
- 类数量增加,系统复杂度上升
- 增加了系统的抽象性,理解和维护成本提升
3. 抽象工厂模式(Abstract Factory Pattern)
模式解释
抽象工厂模式核心思想是:
提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定具体类。
适用场景:
- 需要创建多个产品族的对象,且这些对象之间有相互依赖关系
- 需要确保同一产品族的产品一起使用
代码示例(Java,含测试代码)
// 抽象产品A
interface ProductA {
void use();
}
// 抽象产品B
interface ProductB {
void eat();
}
// 具体产品A1
class ConcreteProductA1 implements ProductA {
public void use() {
System.out.println("使用产品A1");
}
}
// 具体产品A2
class ConcreteProductA2 implements ProductA {
public void use() {
System.out.println("使用产品A2");
}
}
// 具体产品B1
class ConcreteProductB1 implements ProductB {
public void eat() {
System.out.println("吃产品B1");
}
}
// 具体产品B2
class ConcreteProductB2 implements ProductB {
public void eat() {
System.out.println("吃产品B2");
}
}
// 抽象工厂
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA1();
}
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA2();
}
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
// 测试代码
public class AbstractFactoryDemo {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA a1 = factory1.createProductA();
ProductB b1 = factory1.createProductB();
a1.use();
b1.eat();
AbstractFactory factory2 = new ConcreteFactory2();
ProductA a2 = factory2.createProductA();
ProductB b2 = factory2.createProductB();
a2.use();
b2.eat();
}
}
运行效果
使用产品A1
吃产品B1
使用产品A2
吃产品B2
总结
优点:
- 保证同一产品族的产品一起使用,避免混用
- 易于产品族的整体替换和扩展
缺点:
- 系统扩展困难,增加新的产品族需要修改抽象工厂接口
- 结构复杂,增加设计难度
4. 建造者模式(Builder Pattern)
模式解释
建造者模式核心思想是:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
适用场景:
- 需要构建复杂对象,且构建过程独立于组成部分的创建和组合方式
- 需要多个不同的表示
代码示例(Java,含测试代码)
// 产品类
class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) { this.partA = partA; }
public void setPartB(String partB) { this.partB = partB; }
public void setPartC(String partC) { this.partC = partC; }
public void show() {
System.out.println("产品组成:");
System.out.println("部件A:" + partA);
System.out.println("部件B:" + partB);
System.out.println("部件C:" + partC);
}
}
// 抽象建造者
abstract class Builder {
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public Product getResult() {
return product;
}
}
// 具体建造者1
class ConcreteBuilder1 extends Builder {
public void buildPartA() {
product.setPartA("具体建造者1的部件A");
}
public void buildPartB() {
product.setPartB("具体建造者1的部件B");
}
public void buildPartC() {
product.setPartC("具体建造者1的部件C");
}
}
// 具体建造者2
class ConcreteBuilder2 extends Builder {
public void buildPartA() {
product.setPartA("具体建造者2的部件A");
}
public void buildPartB() {
product.setPartB("具体建造者2的部件B");
}
public void buildPartC() {
product.setPartC("具体建造者2的部件C");
}
}
// 指挥者
class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
public Product getProduct() {
return builder.getResult();
}
}
// 测试代码
public class BuilderDemo {
public static void main(String[] args) {
Builder builder1 = new ConcreteBuilder1();
Director director1 = new Director(builder1);
director1.construct();
Product product1 = director1.getProduct();
product1.show();
Builder builder2 = new ConcreteBuilder2();
Director director2 = new Director(builder2);
director2.construct();
Product product2 = director2.getProduct();
product2.show();
}
}
运行效果
产品组成:
部件A:具体建造者1的部件A
部件B:具体建造者1的部件B
部件C:具体建造者1的部件C
产品组成:
部件A:具体建造者2的部件A
部件B:具体建造者2的部件B
部件C:具体建造者2的部件C
总结
优点:
- 将复杂对象的构建过程封装,易于控制构建细节
- 具体建造者之间独立,便于扩展和维护
- 客户端不需要知道产品内部组成细节
缺点:
- 产生多余的Builder类,系统更复杂
- 建造者和产品之间关系紧密,需协调设计
5. 原型模式(Prototype Pattern)
模式解释
原型模式核心思想是:
通过复制已有的实例来创建新的实例,而不是通过 new 关键字创建,减少创建对象的成本。
适用场景:
- 对象创建成本较高,需要大量相似对象
- 希望通过拷贝现有对象快速创建新对象
代码示例(Java,含测试代码)
// 原型接口
interface Prototype extends Cloneable {
Prototype clone();
}
// 具体原型类
class ConcretePrototype implements Prototype {
private String name;
public ConcretePrototype(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void show() {
System.out.println("对象名称:" + name);
}
// 实现clone方法,浅拷贝
public Prototype clone() {
try {
return (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
// 测试代码
public class PrototypeDemo {
public static void main(String[] args) {
ConcretePrototype prototype1 = new ConcretePrototype("原型对象1");
prototype1.show();
ConcretePrototype prototype2 = (ConcretePrototype) prototype1.clone();
prototype2.setName("克隆对象2");
prototype2.show();
System.out.println("prototype1和prototype2是否是同一个对象?" + (prototype1 == prototype2));
}
}
运行效果
对象名称:原型对象1
对象名称:克隆对象2
prototype1和prototype2是否是同一个对象?false
总结
优点:
- 通过克隆对象,避免了重新初始化资源消耗
- 运行时动态决定创建哪种类型的对象,灵活性好
缺点:
- 需要实现 Cloneable 接口,clone() 可能带来浅拷贝风险
- 对复杂对象需要实现深拷贝,增加复杂度
📌 下一篇: 《设计模式专栏(三):结构型模式全解》
扫码关注订阅号