1. 创建型设计模式概述
在软件开发中,我们经常面临对象创建的场景。创建型设计模式就是为解决对象创建过程中的各种问题而生的经典解决方案。这些模式不仅能够提高代码的复用性,还能让系统更加灵活、易于维护。
创建型设计模式主要包含以下几种:
- 工厂模式(Factory Pattern)
- 建造者模式(Builder Pattern)
- 原型模式(Prototype Pattern)
- 单例模式(Singleton Pattern)
每种模式都针对不同的创建场景提供了优雅的解决方案。在实际项目中,我们往往会根据具体需求选择最合适的创建模式,有时甚至会组合使用多种模式。
1.1 为什么需要创建型设计模式
想象一下,如果你每次需要一辆汽车时,都要从零开始设计轮子、发动机和车身,那将是多么低效。创建型设计模式就像是汽车制造的标准流程,它为我们提供了可复用的对象创建方案。
使用创建型设计模式的主要好处包括:
- 解耦对象的创建与使用
- 提高代码的可维护性和可扩展性
- 降低系统对具体类的依赖
- 提供更灵活的对象创建方式
- 优化资源使用(如单例模式)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工厂模式详解
工厂模式是最常用的创建型模式之一,它定义了一个用于创建对象的接口,但让子类决定实例化哪个类。工厂方法让类的实例化推迟到子类。
2.1 简单工厂模式
简单工厂模式是最基础的工厂实现。它通过一个工厂类来创建不同类型的对象,客户端只需要知道传入什么参数就能得到对应的对象,而不需要关心对象的具体创建过程。
java复制public class SimpleFactory {
public static Product createProduct(String type) {
switch(type) {
case "A":
return new ConcreteProductA();
case "B":
return new ConcreteProductB();
default:
throw new IllegalArgumentException("Unknown product type");
}
}
}
简单工厂的优点在于客户端代码简洁,但缺点也很明显:当需要添加新产品时,必须修改工厂类的代码,这违反了开闭原则。
2.2 工厂方法模式
工厂方法模式解决了简单工厂的扩展性问题。它为每个产品提供一个工厂类,通过多态来实现不同产品的创建。
java复制public interface Factory {
Product createProduct();
}
public class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
public class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
工厂方法模式的优点:
- 完全符合开闭原则
- 客户端只需要知道抽象工厂和抽象产品
- 添加新产品时只需添加新的工厂类
缺点:
- 类的数量会随着产品增加而增加
- 增加了系统的抽象性和理解难度
2.3 抽象工厂模式
抽象工厂模式是工厂方法模式的升级版,它提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
java复制public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
public class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
抽象工厂适用于产品族的情况,比如不同风格的UI组件(Windows风格和Mac风格)。它的优点是可以保证产品之间的兼容性,缺点是扩展产品族比较困难。
提示:在实际项目中,Spring框架的BeanFactory就是工厂模式的典型应用,它通过配置文件或注解来管理对象的创建。
3. 建造者模式深入解析
建造者模式将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。这种模式特别适合创建具有多个组成部分的复杂对象。
3.1 建造者模式的结构
建造者模式通常包含以下几个角色:
- Builder:抽象建造者,定义创建产品各个部分的抽象接口
- ConcreteBuilder:具体建造者,实现Builder接口
- Director:指挥者,负责安排复杂对象的构建次序
- Product:最终构建的复杂对象
java复制public class Computer {
private String CPU;
private String RAM;
private String storage;
// 其他属性和getter/setter方法
}
public interface ComputerBuilder {
void buildCPU();
void buildRAM();
void buildStorage();
Computer getResult();
}
public class GamingComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void buildCPU() {
computer.setCPU("Intel i9");
}
@Override
public void buildRAM() {
computer.setRAM("32GB DDR5");
}
@Override
public void buildStorage() {
computer.setStorage("1TB NVMe SSD");
}
@Override
public Computer getResult() {
return computer;
}
}
public class Director {
public Computer construct(ComputerBuilder builder) {
builder.buildCPU();
builder.buildRAM();
builder.buildStorage();
return builder.getResult();
}
}
3.2 建造者模式的变体
在实际开发中,我们经常使用一种简化的建造者模式,它省略了Director角色,将构建逻辑放在Builder内部:
java复制public class Computer {
private final String CPU;
private final String RAM;
private final String storage;
private Computer(Builder builder) {
this.CPU = builder.CPU;
this.RAM = builder.RAM;
this.storage = builder.storage;
}
public static class Builder {
private String CPU;
private String RAM;
private String storage;
public Builder setCPU(String CPU) {
this.CPU = CPU;
return this;
}
public Builder setRAM(String RAM) {
this.RAM = RAM;
return this;
}
public Builder setStorage(String storage) {
this.storage = storage;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
这种变体的优点是使用起来更加灵活,代码也更加简洁。Java中的StringBuilder就是这种模式的典型应用。
3.3 建造者模式的应用场景
建造者模式特别适用于以下场景:
- 需要生成的产品对象有复杂的内部结构
- 需要生成的产品对象的属性相互依赖,需要指定其生成顺序
- 对象的创建过程需要独立于创建该对象的类
- 需要隔离复杂对象的创建和使用
注意:当产品非常简单,或者产品的构建顺序不重要时,使用建造者模式可能会增加不必要的复杂性。
4. 原型模式全面剖析
原型模式通过复制现有对象来创建新对象,而不是通过new关键字。这种模式在创建成本较高的对象时特别有用。
4.1 原型模式的实现方式
在Java中,原型模式通常通过实现Cloneable接口来实现:
java复制public class Prototype implements Cloneable {
private String property;
public Prototype(String property) {
this.property = property;
}
@Override
public Prototype clone() {
try {
return (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // Can't happen
}
}
}
需要注意的是,Object.clone()方法执行的是浅拷贝。如果需要深拷贝,需要手动实现:
java复制public class DeepPrototype implements Cloneable {
private String property;
private ReferenceType reference;
@Override
public DeepPrototype clone() {
DeepPrototype copy = (DeepPrototype) super.clone();
copy.reference = this.reference.clone(); // 手动拷贝引用类型
return copy;
}
}
4.2 原型模式的优缺点
优点:
- 性能高:直接拷贝内存中的二进制流,比new操作快很多
- 简化创建过程:特别是当初始化需要消耗大量资源时
- 动态获取对象运行时状态
缺点:
- 必须实现Cloneable接口
- 深拷贝实现复杂,特别是当对象引用关系复杂时
- 需要小心处理final字段
4.3 原型模式的应用场景
原型模式适用于以下情况:
- 需要创建的对象应独立于其类型与创建方式
- 要实例化的类是在运行时决定的
- 避免使用与产品层次平行的工厂类层次
- 当一个类的实例只能有几个不同状态组合中的一种时
在实际开发中,原型模式常用于:
- 游戏开发中的角色复制
- 配置对象的复制
- 需要高性能的大对象创建
5. 单例模式深度探讨
单例模式确保一个类只有一个实例,并提供一个全局访问点。这是最简单的设计模式之一,但实现起来却有很多细节需要注意。
5.1 单例模式的基本实现
最简单的单例实现:
java复制public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种实现方式在单线程环境下工作良好,但在多线程环境下可能会创建多个实例。
5.2 线程安全的单例实现
5.2.1 同步方法
java复制public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种方式简单但效率较低,因为每次获取实例都需要同步。
5.2.2 双重检查锁定
java复制public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
注意:必须使用volatile关键字防止指令重排序问题。
5.2.3 静态内部类方式
java复制public class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
这种方式利用了类加载机制保证线程安全,且实现了懒加载,是最推荐的单例实现方式之一。
5.2.4 枚举方式
java复制public enum Singleton {
INSTANCE;
public void doSomething() {
// ...
}
}
这是最简洁也是《Effective Java》作者Josh Bloch推荐的方式,它不仅能避免多线程同步问题,还能防止反序列化重新创建新的对象。
5.3 单例模式的破坏与防护
单例模式可能会被以下方式破坏:
- 反射攻击:通过反射调用私有构造方法
- 序列化攻击:序列化后再反序列化会创建新实例
- 克隆攻击:如果单例类实现了Cloneable接口
防护措施:
java复制public class Singleton implements Serializable {
private static final long serialVersionUID = 1L;
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
// 防止反射攻击
if (Holder.INSTANCE != null) {
throw new IllegalStateException("Singleton already initialized");
}
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
// 防止反序列化创建新实例
protected Object readResolve() {
return getInstance();
}
// 防止克隆
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
5.4 单例模式的应用场景
单例模式适用于以下场景:
- 需要控制资源访问,如数据库连接池
- 需要频繁创建和销毁的对象
- 创建对象时消耗资源过多,但又经常用到的对象
- 工具类对象
- 需要共享访问点或共享数据的场景
注意:单例模式虽然简单好用,但过度使用会导致代码难以测试和维护,因为它引入了全局状态。在使用前应该仔细考虑是否真的需要单例。
6. 创建型模式对比与选择指南
在实际项目中,我们经常需要根据具体场景选择合适的创建型模式。下面是对四种创建型模式的对比分析:
| 模式 | 主要目的 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 工厂模式 | 封装对象创建过程 | 需要创建多种类似对象 | 解耦客户端和具体类 | 增加系统复杂度 |
| 建造者模式 | 分步构建复杂对象 | 创建具有多个组成部分的对象 | 灵活,可以构建不同表示 | 代码量增加 |
| 原型模式 | 通过复制创建对象 | 创建成本高的对象 | 性能高,动态获取状态 | 深拷贝实现复杂 |
| 单例模式 | 保证唯一实例 | 需要全局唯一对象的场景 | 节省资源,严格控制访问 | 难以测试,可能过度使用 |
选择创建型模式时,可以考虑以下几点:
- 如果对象的创建逻辑简单,直接使用new关键字即可
- 如果对象的创建过程复杂或有多种变化,考虑工厂模式
- 如果需要构建具有多个部分的复杂对象,考虑建造者模式
- 如果需要高性能地创建相似对象,考虑原型模式
- 如果需要确保全局唯一实例,考虑单例模式
在实际项目中,这些模式经常组合使用。例如,可以使用工厂模式创建建造者,或者让单例对象使用原型模式来创建新实例。
7. 创建型模式在实际项目中的应用技巧
7.1 工厂模式的最佳实践
- 使用依赖注入框架(如Spring)来管理工厂
- 为工厂方法使用有意义的名称,清楚地表达创建的是什么
- 考虑使用静态工厂方法而不是构造函数
- 当产品类型较多时,可以使用抽象工厂来管理产品族
java复制// 静态工厂方法示例
public class User {
private String name;
private int age;
private User(String name, int age) {
this.name = name;
this.age = age;
}
public static User createWithDefaultAge(String name) {
return new User(name, 18);
}
public static User createWithAgeCheck(String name, int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
return new User(name, age);
}
}
7.2 建造者模式的实用技巧
- 对于配置类对象,优先考虑使用建造者模式
- 使用链式调用(fluent interface)使代码更易读
- 为必填参数提供构造函数或静态工厂方法
- 考虑使用@Builder注解(Lombok)简化代码
java复制// 使用Lombok的@Builder示例
@Builder
public class EmailMessage {
private String from;
private String to;
private String subject;
private String body;
private List<String> attachments;
}
// 使用方式
EmailMessage message = EmailMessage.builder()
.from("sender@example.com")
.to("receiver@example.com")
.subject("Hello")
.body("This is a test email")
.build();
7.3 原型模式的使用建议
- 对于不可变对象,浅拷贝通常就足够了
- 考虑使用序列化/反序列化实现深拷贝
- 为原型对象提供清晰的拷贝接口
- 在文档中明确说明拷贝是深拷贝还是浅拷贝
java复制// 使用序列化实现深拷贝
public class DeepCopyUtil {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepCopy(T object) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("Deep copy failed", e);
}
}
}
7.4 单例模式的注意事项
- 优先考虑使用依赖注入而不是硬编码的单例
- 如果必须使用单例,优先选择枚举或静态内部类实现
- 确保单例是真正全局唯一的,而不仅仅是应用级别的
- 考虑单例对象的生命周期管理
java复制// 使用依赖注入管理单例
@Configuration
public class AppConfig {
@Bean
@Scope("singleton")
public SomeService someService() {
return new SomeServiceImpl();
}
}
8. 创建型模式的常见误区与解决方案
8.1 工厂模式的常见问题
问题1:过度使用工厂模式导致类爆炸
解决方案:只有当对象创建逻辑确实复杂或有多种变化时才使用工厂模式
问题2:工厂类中条件判断过多
解决方案:考虑使用Map存储创建逻辑,或者使用策略模式
java复制// 使用Map优化工厂
public class ProductFactory {
private static Map<String, Supplier<Product>> creators = new HashMap<>();
static {
creators.put("A", ProductA::new);
creators.put("B", ProductB::new);
}
public static Product createProduct(String type) {
Supplier<Product> creator = creators.get(type);
if (creator == null) {
throw new IllegalArgumentException("Unknown product type");
}
return creator.get();
}
}
8.2 建造者模式的误用
问题1:为简单对象使用建造者模式,导致代码冗余
解决方案:只有当对象确实有多个组成部分且构建过程复杂时才使用建造者模式
问题2:建造者缺少必要的参数校验
解决方案:在build()方法中进行参数校验
java复制public class UserBuilder {
// ...其他代码
public User build() {
if (name == null) {
throw new IllegalStateException("Name is required");
}
if (age < 0) {
throw new IllegalStateException("Age cannot be negative");
}
return new User(name, age);
}
}
8.3 原型模式的陷阱
问题1:未正确实现深拷贝导致对象状态共享
解决方案:仔细检查所有引用类型字段,确保它们也被正确拷贝
问题2:忽略Cloneable接口的约定
解决方案:确保clone()方法遵循约定:x.clone() != x && x.clone().getClass() == x.getClass()
8.4 单例模式的滥用
问题1:将工具类硬编码为单例
解决方案:考虑使用静态方法或依赖注入
问题2:在多ClassLoader环境下单例失效
解决方案:如果需要真正的全局单例,考虑使用枚举或外部存储(如系统属性)
问题3:单例对象持有资源导致内存泄漏
解决方案:提供资源释放方法,并确保在适当的时候调用
java复制public class ResourceHolder {
private static ResourceHolder instance;
private List<Resource> resources = new ArrayList<>();
private ResourceHolder() {}
public static synchronized ResourceHolder getInstance() {
if (instance == null) {
instance = new ResourceHolder();
}
return instance;
}
public synchronized void cleanup() {
for (Resource res : resources) {
res.release();
}
resources.clear();
}
// ...其他方法
}
9. 创建型模式在现代框架中的应用
9.1 Spring框架中的创建型模式
Spring框架大量使用了创建型模式来管理对象的生命周期:
- 工厂模式:BeanFactory和ApplicationContext本身就是工厂
- 单例模式:默认的bean作用域就是单例
- 原型模式:通过@Scope("prototype")注解实现
- 建造者模式:如RestTemplateBuilder、MockMvcBuilders等
java复制// Spring中的建造者模式示例
@RestController
@RequestMapping("/api")
public class MyController {
private final RestTemplate restTemplate;
public MyController(RestTemplateBuilder builder) {
this.restTemplate = builder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(10))
.build();
}
}
9.2 Java标准库中的创建型模式
Java标准库也提供了许多创建型模式的实现:
- 工厂模式:Collections.unmodifiableList(), Executors.newFixedThreadPool()
- 建造者模式:StringBuilder, Stream.Builder
- 原型模式:Cloneable接口
- 单例模式:Runtime.getRuntime()
java复制// Java中的工厂方法示例
List<String> list = Arrays.asList("a", "b", "c");
List<String> unmodifiable = Collections.unmodifiableList(list);
9.3 其他流行框架中的应用
- Lombok的@Builder实现了建造者模式
- Guava的ImmutableList使用了工厂方法和建造者模式
- Jackson的ObjectMapper可以看作是一个工厂
java复制// 使用Guava的建造者
ImmutableList<String> list = ImmutableList.<String>builder()
.add("a")
.add("b")
.add("c")
.build();
10. 创建型模式的性能考量
10.1 工厂模式的性能影响
工厂模式通常会引入额外的间接层,可能带来轻微的性能开销。但在大多数情况下,这种开销可以忽略不计。实际上,工厂模式可能通过对象池等技术提高性能。
10.2 建造者模式的内存使用
建造者模式会创建额外的建造者对象,可能增加内存使用。对于性能敏感的场景,可以考虑重用建造者实例。
10.3 原型模式的性能优势
原型模式在创建复杂对象时性能优势明显,特别是当:
- 对象初始化成本高
- 需要创建大量相似对象
- 对象状态变化频繁
测试表明,对于复杂对象,原型模式比直接创建快5-10倍。
10.4 单例模式的内存占用
单例模式可以减少内存占用,因为它限制了实例数量。但需要注意:
- 单例对象如果持有大量数据,可能成为内存瓶颈
- 延迟初始化可能带来首次访问的性能问题
- 双重检查锁定中的volatile可能影响性能
11. 创建型模式的测试策略
11.1 测试工厂模式
- 测试工厂方法返回正确的产品类型
- 测试工厂对无效输入的处理
- 使用Mock测试工厂的依赖
java复制@Test
public void testFactoryCreatesCorrectProduct() {
Product product = ProductFactory.createProduct("A");
assertTrue(product instanceof ProductA);
}
11.2 测试建造者模式
- 测试必填字段的校验
- 测试构建过程的完整性
- 测试可选字段的默认值
java复制@Test
public void testBuilderWithRequiredFields() {
User user = new User.Builder("John").age(30).build();
assertEquals("John", user.getName());
assertEquals(30, user.getAge());
}
@Test(expected = IllegalStateException.class)
public void testBuilderMissingRequiredField() {
new User.Builder(null).build();
}
11.3 测试原型模式
- 测试拷贝后的对象与原对象相等但不相同
- 测试深拷贝的正确性
- 测试拷贝性能
java复制@Test
public void testPrototypeClone() {
Prototype original = new Prototype("test");
Prototype clone = original.clone();
assertEquals(original, clone);
assertNotSame(original, clone);
}
11.4 测试单例模式
- 测试多线程环境下实例的唯一性
- 测试序列化/反序列化后的唯一性
- 测试反射攻击防护
java复制@Test
public void testSingletonInMultiThread() throws InterruptedException {
Set<Singleton> instances = Collections.synchronizedSet(new HashSet<>());
int threadCount = 100;
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
instances.add(Singleton.getInstance());
latch.countDown();
}).start();
}
latch.await();
assertEquals(1, instances.size());
}
12. 创建型模式的演进与替代方案
12.1 函数式编程对创建型模式的影响
随着函数式编程的流行,一些创建型模式有了新的实现方式:
- 工厂方法可以使用Supplier函数接口
- 建造者模式可以使用函数组合
- 原型模式可以使用复制函数
java复制// 使用Supplier实现简单工厂
Map<String, Supplier<Product>> factory = new HashMap<>();
factory.put("A", ProductA::new);
factory.put("B", ProductB::new);
Product product = factory.get(type).get();
12.2 依赖注入对单例模式的替代
现代框架(如Spring)通过依赖注入管理对象生命周期,减少了手动实现单例的需求:
java复制@Service
public class MyService {
// Spring会确保单例
}
12.3 现代语言特性对创建型模式的简化
新语言特性(如Kotlin的object、data class)简化了某些模式的实现:
kotlin复制// Kotlin中的单例
object Singleton {
fun doSomething() { ... }
}
// Kotlin中的建造者模式替代方案
data class User(val name: String, val age: Int) {
class Builder {
private var name: String = ""
private var age: Int = 0
fun name(name: String) = apply { this.name = name }
fun age(age: Int) = apply { this.age = age }
fun build() = User(name, age)
}
}
13. 创建型模式的反模式与误用
13.1 过度设计问题
创建型模式虽然有用,但不应该过度使用。以下情况可能表明过度设计:
- 为只有一种实现的简单对象使用工厂模式
- 为只有少量字段的对象使用建造者模式
- 为无状态对象使用单例模式
13.2 单例模式的全局状态问题
单例模式本质上引入了全局状态,可能导致:
- 代码难以测试
- 隐藏的依赖关系
- 并发问题
- 生命周期管理困难
13.3 原型模式的深拷贝陷阱
不正确的深拷贝实现可能导致:
- 对象图不一致
- 性能问题
- 循环引用问题
13.4 建造者模式的参数爆炸
当参数过多时,建造者模式可能变得难以维护:
- 构建方法过长
- 参数间依赖关系复杂
- 难以确保构建完整性
解决方案:考虑将相关参数分组为值对象
java复制public class UserBuilder {
private PersonalInfo personalInfo;
private ContactInfo contactInfo;
public UserBuilder withPersonalInfo(String name, int age) {
this.personalInfo = new PersonalInfo(name, age);
return this;
}
// ...其他方法
}
14. 创建型模式与其他设计模式的关系
14.1 与结构型模式的结合
- 工厂模式常与抽象工厂模式结合使用
- 建造者模式可以与组合模式一起构建复杂结构
- 原型模式常与备忘录模式一起实现对象状态保存
14.2 与行为型模式的协作
- 工厂方法模式常与模板方法模式结合
- 单例模式常与状态模式或策略模式一起使用
- 原型模式可以与命令模式一起实现撤销功能
14.3 模式组合的典型案例
一个典型的组合案例是使用抽象工厂创建建造者,然后用建造者构建复杂对象:
java复制public interface UIFactory {
Button createButton();
Menu createMenu();
DialogBuilder createDialogBuilder();
}
public interface DialogBuilder {
DialogBuilder setTitle(String title);
DialogBuilder addButton(Button button);
Dialog build();
}
public class WindowsUIFactory implements UIFactory {
@Override
public DialogBuilder createDialogBuilder() {
return new WindowsDialogBuilder();
}
// ...其他方法
}
15. 创建型模式的未来发展趋势
15.1 响应式编程中的创建型模式
在响应式编程中,创建型模式有了新的应用:
- 工厂方法用于创建Publisher
- 建造者模式用于构建反应式流水线
- 单例模式管理共享资源
java复制// Reactor中的工厂方法
Flux<String> flux = Flux.just("a", "b", "c");
// Reactor中的建造者模式
Mono<String> result = WebClient.create()
.get()
.uri("https://example.com")
.retrieve()
.bodyToMono(String.class);
15.2 云原生环境下的变化
在云原生和微服务架构中:
- 工厂模式用于创建不同环境的客户端
- 单例模式被依赖注入替代
- 原型模式在无状态服务中应用减少
15.3 AI代码生成的影响
AI代码生成工具可能:
- 自动识别适用创建型模式的场景
- 生成模式实现代码
- 但设计决策仍需人工判断
16. 创建型模式的学习路径建议
16.1 初学者学习路线
- 从单例模式开始,理解基本概念
- 学习简单工厂和工厂方法
- 掌握建造者模式的基本实现
- 最后学习原型模式
16.2 中级开发者进阶
- 深入理解各模式的适用场景
- 学习模式组合使用
- 研究框架中的模式实现
- 掌握模式的反模式
16.3 高级开发者精通
- 理解模式背后的设计原则
- 能够根据需求灵活变通模式
- 预见模式演进的趋势
- 创造新的模式变体
17. 创建型模式的代码重构技巧
17.1 识别重构机会
以下代码味道可能提示需要引入创建型模式:
- 复杂的对象初始化逻辑分散在多处
- 构造函数参数过多
- 条件判断决定对象类型
- 频繁创建相似对象
17.2 重构为工厂模式
重构前:
java复制public class Client {
public void process(String type) {
Product product;
if (type.equals("A")) {
product = new ProductA();
} else {
product = new ProductB();
}
// 使用product
}
}
重构后:
java复制public class Client {
private ProductFactory factory;
public void process(String type) {
Product product = factory.createProduct(type);
// 使用product
}
}
17.3 重构为建造者模式
重构前:
java复制public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
// 更多字段...
public NutritionFacts(int servingSize, int servings,
int calories, /*更多参数*/) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
// 更多赋值...
}
}
重构后:
java复制public class NutritionFacts {
public static class Builder {
// 必需参数
private final int servingSize;
private final int servings;
// 可选参数
private int calories = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
calories = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
}
}
17.4 重构为原型模式
重构前:
java复制public class ComplexObject {
// 复杂的初始化过程
public ComplexObject() {
// 耗时很长的初始化代码
}
// 需要创建相似对象时
public ComplexObject createSimilar() {
ComplexObject obj = new ComplexObject();
// 手动复制所有状态
return obj;
}
}
重构后:
java复制public class ComplexObject implements Cloneable {
// ...
@Override
public ComplexObject clone() {
try {
return (ComplexObject) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
18. 创建型模式的跨语言比较
18.1 工厂模式在不同语言中的实现
- Java:通常使用接口和类实现
- Python:可以使用模块级函数作为工厂
- JavaScript:可以使用简单函数或ES6类
- Go:使用函数返回接口类型
python复制# Python中的工厂函数
def create_product(product_type):
if product_type == 'A':
return ProductA()
elif product_type == 'B':
return ProductB()
else:
raise ValueError(f"Unknown product type: {product_type}")
18.2 建造者模式的语法差异
- Java:通常使用内部Builder类
- Kotlin:命名参数+默认值可以替代简单建造者
- C++:操作符重载实现流畅接口
- Swift:便利初始化器+配置闭包
kotlin复制// Kotlin中使用命名参数替代简单建造者
data class User(val name: String, val age: Int = 0, val address: String = "")
val user = User(name = "John", age = 30)
18.3 单例模式的实现差异
- Java:多种实现方式(枚举、静态内部类等)
- Scala:使用object关键字
- Swift:使用static let共享实例
- C#:使用静态构造函数保证线程安全
swift复制// Swift中的单例
class Singleton {
static let shared = Singleton()
private init() {}
}
18.4 原型模式的语言支持
- Java:需要实现Cloneable接口
- JavaScript:天然支持原型继承
- Python:copy模块提供深/浅拷贝支持
- C#:MemberwiseClone方法实现浅拷贝
javascript复制// JavaScript中原型模式的天然支持
const prototype = {
greet: function() {
console.log(`Hello, ${this.name}!`);
}
};
const obj1 = Object.create(prototype);
obj1.name = "Alice";
obj1.greet();
19. 创建型模式在领域驱动设计中的应用
19.1 工厂模式与聚合根创建
在DDD中,工厂模式常用于:
- 封装聚合根的复杂创建逻辑
- 确保聚合不变量的完整性
- 隐藏具体实现类
java复制public class OrderFactory {
public static Order createOrder(Customer customer, List<OrderItem> items) {
Order order = new Order(customer);
items.forEach(order::addItem);
if (!order.isValid()) {
throw new IllegalStateException("Invalid order");
}
return order;
}
}
19.2 建造者模式与值对象
建造者模式适合构建复杂值对象:
java复制public class AddressBuilder {
private String street;
private String city;
public AddressBuilder withStreet(String street) {
this.street = street;
return this;
}
public Address build() {
return new Address(street, city);
}
}
19.3 单例模式与领域服务
在DDD中,无状态领域服务可以设计为单例:
java复制public class PricingService {
private static final PricingService INSTANCE = new PricingService();
private PricingService() {}
public static PricingService getInstance()
