你有没有想过,为什么有些数字会反复出现在完全不同的领域?23这个数字,在生物学中是染色体的对数,在软件工程中是经典设计模式的数量,在几何学中是欧几里得定义的数量,甚至在宗教哲学中也有特殊含义。这仅仅是巧合,还是背后有更深层的规律?
作为一名长期关注软件架构和系统设计的开发者,我发现这些看似无关的"23现象"其实揭示了一个重要规律:复杂系统的构建往往遵循相似的模块化原则。无论是生物遗传、软件设计还是数学体系,当系统复杂度达到一定程度时,都会自然演化出20-30个核心构建模块。
今天,我们不讨论神秘学,而是从工程实践的角度,深入分析这种"23模块定律"在软件设计中的具体体现。本文将重点解析GoF的23种设计模式如何成为构建复杂软件的DNA,并给出在实际项目中应用这些模式的实用指南。
1. 为什么23个设计模式能统治软件工程30年?
1994年,Erich Gamma等四位作者(GoF)在《设计模式:可复用面向对象软件的基础》中提出了23种设计模式。近30年过去,尽管编程语言、框架、架构风格发生了翻天覆地的变化,但这23个模式依然是软件设计的基石。
根本原因在于,这23个模式解决了面向对象设计中最本质的复杂度管理问题。它们不是随意列举的,而是针对对象间关系的几种基本场景的完整覆盖:
- 创建型模式(5个):处理对象实例化过程的复杂度
- 结构型模式(7个):处理类与对象组合的复杂度
- 行为型模式(11个):处理对象间职责分配的复杂度
这种分类方式与生物学中23对染色体承载遗传信息的功能惊人相似。染色体是生物体的基础构建模块,而设计模式是软件系统的基础构建模块。两者都在20-30这个数量级上达到了一种平衡:足够覆盖基本场景,又不会过于复杂难以掌握。
2. 设计模式与染色体:模块化思维的跨领域验证
为了更好地理解23这个数字的意义,我们先看看其他领域中类似的模块化现象:
| 领域 | 核心模块数量 | 功能描述 | 与软件设计的类比 |
|---|---|---|---|
| 生物学 | 23对染色体 | 承载人类遗传信息 | 设计模式承载软件构建知识 |
| 几何学 | 23个定义 | 欧几里得《几何原本》的基础 | 软件设计的基础概念定义 |
| 质数理论 | 23(第一个非孪生质数) | 质数分布中的关键节点 | 设计模式在软件架构中的关键作用 |
这种跨领域的一致性说明,当系统复杂度达到某个阈值时,20-30个核心模块往往是最优解。太少则无法覆盖所有场景,太多则增加学习和使用成本。
在软件工程中,这23个模式形成了一个完整的知识体系。比如,当你需要解耦对象创建过程时,你会想到工厂模式;当需要为子系统提供统一接口时,会想到外观模式;当需要定义算法家族时,会想到策略模式。
3. 环境准备:现代Java开发中的模式实践
在深入具体模式之前,我们先搭建一个现代化的开发环境。与1994年GoF成书时相比,现在的工具链和最佳实践已经有了很大变化。
3.1 基础环境配置
# 使用Maven创建项目 mvn archetype:generate -DgroupId=com.example.designpatterns \ -DartifactId=design-patterns-demo \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false # 项目结构 src/ ├── main/ │ └── java/ │ └── com/ │ └── example/ │ └── designpatterns/ │ ├── creational/ # 创建型模式 │ ├── structural/ # 结构型模式 │ └── behavioral/ # 行为型模式 └── test/ └── java/3.2 依赖管理配置
<!-- pom.xml --> <project> <modelVersion>4.0.0</modelVersion> <groupId>com.example.designpatterns</groupId> <artifactId>design-patterns-demo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <junit.version>5.8.2</junit.version> </properties> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> </project>3.3 现代IDE配置要点
与20年前相比,现代IDE如IntelliJ IDEA已经内置了对设计模式的深度支持:
- 模式识别:IDE能自动识别代码中的模式使用情况
- 重构工具:提供将代码重构为特定模式的重构选项
- 代码模板:内置常用模式的代码模板
4. 创建型模式实战:控制对象创建的复杂度
创建型模式的核心价值在于将对象创建与使用分离,从而提高系统的灵活性和可维护性。我们重点分析三个最常用的模式。
4.1 工厂方法模式:灵活的对象创建
工厂方法模式解决了直接调用构造函数带来的耦合问题。在实际项目中,当创建逻辑比较复杂或可能变化时,这个模式特别有用。
// 文件路径:src/main/java/com/example/designpatterns/creational/factory/LoggerFactory.java public interface Logger { void log(String message); } public class FileLogger implements Logger { @Override public void log(String message) { // 写入文件的实现 System.out.println("File Logger: " + message); } } public class ConsoleLogger implements Logger { @Override public void log(String message) { System.out.println("Console Logger: " + message); } } // 工厂接口 public interface LoggerFactory { Logger createLogger(); } // 具体工厂实现 public class FileLoggerFactory implements LoggerFactory { @Override public Logger createLogger() { // 这里可以包含复杂的初始化逻辑 return new FileLogger(); } } public class ConsoleLoggerFactory implements LoggerFactory { @Override public Logger createLogger() { return new ConsoleLogger(); } } // 使用示例 public class Client { public static void main(String[] args) { LoggerFactory factory = new FileLoggerFactory(); Logger logger = factory.createLogger(); logger.log("这是一个测试消息"); } }工厂模式的关键优势:
- 将对象创建代码集中管理,便于维护
- 支持开闭原则,新增产品类型时不需要修改客户端代码
- 可以隐藏复杂的创建逻辑,如缓存、池化等
4.2 单例模式:全局唯一实例的陷阱与正确用法
单例模式是最容易被误用的模式之一。很多人只记得"保证一个类只有一个实例",却忽略了其带来的测试困难和潜在的内存泄漏问题。
// 文件路径:src/main/java/com/example/designpatterns/creational/singleton/SafeSingleton.java public class SafeSingleton { // 使用 volatile 确保多线程环境下的可见性 private static volatile SafeSingleton instance; private SafeSingleton() { // 防止外部实例化 if (instance != null) { throw new IllegalStateException("单例实例已存在"); } } // 双重检查锁定实现线程安全 public static SafeSingleton getInstance() { if (instance == null) { synchronized (SafeSingleton.class) { if (instance == null) { instance = new SafeSingleton(); } } } return instance; } // 业务方法 public void doSomething() { System.out.println("单例方法执行"); } } // 更现代的实现:枚举单例(推荐) public enum EnumSingleton { INSTANCE; public void doSomething() { System.out.println("枚举单例方法执行"); } } // 使用示例 public class SingletonClient { public static void main(String[] args) { // 传统单例使用 SafeSingleton singleton1 = SafeSingleton.getInstance(); singleton1.doSomething(); // 枚举单例使用(推荐) EnumSingleton.INSTANCE.doSomething(); } }单例模式使用注意事项:
- 优先考虑依赖注入而不是单例
- 如果必须使用单例,推荐枚举实现方式
- 注意单例对象的生命周期管理,避免内存泄漏
- 单例模式会使单元测试变得困难,需要额外考虑测试策略
4.3 建造者模式:复杂对象的逐步构建
当对象的构造过程复杂,且需要多种配置选项时,建造者模式比重叠构造器或JavaBean模式更加优雅。
// 文件路径:src/main/java/com/example/designpatterns/creational/builder/Computer.java public class Computer { private final String cpu; // 必需参数 private final String ram; // 必需参数 private final String storage; // 必需参数 private final String graphicsCard; // 可选参数 private final String monitor; // 可选参数 private Computer(Builder builder) { this.cpu = builder.cpu; this.ram = builder.ram; this.storage = builder.storage; this.graphicsCard = builder.graphicsCard; this.monitor = builder.monitor; } // 静态建造者类 public static class Builder { // 必需参数 private final String cpu; private final String ram; private final String storage; // 可选参数 - 使用默认值 private String graphicsCard = "集成显卡"; private String monitor = "无显示器"; public Builder(String cpu, String ram, String storage) { this.cpu = cpu; this.ram = ram; this.storage = storage; } public Builder graphicsCard(String graphicsCard) { this.graphicsCard = graphicsCard; return this; } public Builder monitor(String monitor) { this.monitor = monitor; return this; } public Computer build() { return new Computer(this); } } // getter 方法 @Override public String toString() { return String.format("Computer[CPU=%s, RAM=%s, Storage=%s, Graphics=%s, Monitor=%s]", cpu, ram, storage, graphicsCard, monitor); } } // 使用示例 public class BuilderClient { public static void main(String[] args) { Computer gamingComputer = new Computer.Builder("Intel i9", "32GB", "1TB SSD") .graphicsCard("RTX 3080") .monitor("27寸4K") .build(); Computer officeComputer = new Computer.Builder("Intel i5", "16GB", "512GB SSD") .build(); // 使用默认可选参数 System.out.println("游戏电脑: " + gamingComputer); System.out.println("办公电脑: " + officeComputer); } }建造者模式的优势:
- 构造过程清晰,参数意义明确
- 支持链式调用,代码可读性强
- 可以确保对象构造完成后的不可变性
- 灵活处理可选参数,避免构造器重载爆炸
5. 结构型模式实战:对象组合的艺术
结构型模式关注如何组合类和对象形成更大的结构。它们主要处理两种关系:类之间的继承关系和对象之间的组合关系。
5.1 适配器模式:解决接口不兼容问题
适配器模式在系统集成、第三方库使用时特别有用。它就像电源插头转换器一样,让不兼容的接口能够协同工作。
// 文件路径:src/main/java/com/example/designpatterns/structural/adapter/AdapterDemo.java // 目标接口:我们系统期望的接口 interface MediaPlayer { void play(String audioType, String fileName); } // 被适配的类:已有的实现,但接口不兼容 class AdvancedMediaPlayer { public void playVlc(String fileName) { System.out.println("Playing vlc file: " + fileName); } public void playMp4(String fileName) { System.out.println("Playing mp4 file: " + fileName); } } // 适配器:让AdvancedMediaPlayer适配MediaPlayer接口 class MediaAdapter implements MediaPlayer { private AdvancedMediaPlayer advancedMusicPlayer; public MediaAdapter(String audioType) { if (audioType.equalsIgnoreCase("vlc")) { advancedMusicPlayer = new AdvancedMediaPlayer(); } else if (audioType.equalsIgnoreCase("mp4")) { advancedMusicPlayer = new AdvancedMediaPlayer(); } } @Override public void play(String audioType, String fileName) { if (audioType.equalsIgnoreCase("vlc")) { advancedMusicPlayer.playVlc(fileName); } else if (audioType.equalsIgnoreCase("mp4")) { advancedMusicPlayer.playMp4(fileName); } } } // 客户端代码使用适配器 public class AudioPlayer implements MediaPlayer { private MediaAdapter mediaAdapter; @Override public void play(String audioType, String fileName) { // 内置支持mp3格式 if (audioType.equalsIgnoreCase("mp3")) { System.out.println("Playing mp3 file: " + fileName); } // 使用适配器支持其他格式 else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) { mediaAdapter = new MediaAdapter(audioType); mediaAdapter.play(audioType, fileName); } else { System.out.println("Invalid media type: " + audioType); } } } // 使用示例 public class AdapterClient { public static void main(String[] args) { AudioPlayer audioPlayer = new AudioPlayer(); audioPlayer.play("mp3", "song.mp3"); audioPlayer.play("mp4", "movie.mp4"); audioPlayer.play("vlc", "video.vlc"); audioPlayer.play("avi", "video.avi"); // 不支持的类型 } }5.2 装饰器模式:动态扩展功能
装饰器模式提供了比继承更灵活的功能扩展方式。它在Java I/O库中有经典应用。
// 文件路径:src/main/java/com/example/designpatterns/structural/decorator/DecoratorDemo.java // 组件接口 interface Coffee { double getCost(); String getDescription(); } // 具体组件 class SimpleCoffee implements Coffee { @Override public double getCost() { return 1.0; } @Override public String getDescription() { return "简单咖啡"; } } // 装饰器抽象类 abstract class CoffeeDecorator implements Coffee { protected Coffee decoratedCoffee; public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee = coffee; } @Override public double getCost() { return decoratedCoffee.getCost(); } @Override public String getDescription() { return decoratedCoffee.getDescription(); } } // 具体装饰器 class MilkDecorator extends CoffeeDecorator { public MilkDecorator(Coffee coffee) { super(coffee); } @Override public double getCost() { return super.getCost() + 0.5; } @Override public String getDescription() { return super.getDescription() + ", 加牛奶"; } } class SugarDecorator extends CoffeeDecorator { public SugarDecorator(Coffee coffee) { super(coffee); } @Override public double getCost() { return super.getCost() + 0.2; } @Override public String getDescription() { return super.getDescription() + ", 加糖"; } } // 使用示例 public class DecoratorClient { public static void main(String[] args) { // 简单咖啡 Coffee coffee = new SimpleCoffee(); System.out.println(coffee.getDescription() + " ¥" + coffee.getCost()); // 加牛奶的咖啡 Coffee milkCoffee = new MilkDecorator(new SimpleCoffee()); System.out.println(milkCoffee.getDescription() + " ¥" + milkCoffee.getCost()); // 加牛奶和糖的咖啡 Coffee sweetMilkCoffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee())); System.out.println(sweetMilkCoffee.getDescription() + " ¥" + sweetMilkCoffee.getCost()); } }6. 行为型模式实战:对象间的交互与职责分配
行为型模式主要关注对象之间的通信和职责分配。它们帮助对象更好地协作,同时保持低耦合。
6.1 策略模式:算法的自由切换
策略模式让算法可以独立于使用它的客户端变化,这在需要支持多种业务规则或计算方式的场景中特别有用。
// 文件路径:src/main/java/com/example/designpatterns/behavioral/strategy/StrategyDemo.java // 策略接口 interface PaymentStrategy { void pay(int amount); } // 具体策略实现 class CreditCardStrategy implements PaymentStrategy { private String cardNumber; private String name; public CreditCardStrategy(String cardNumber, String name) { this.cardNumber = cardNumber; this.name = name; } @Override public void pay(int amount) { System.out.println(amount + "元使用信用卡支付,卡号:" + cardNumber); } } class WeChatPayStrategy implements PaymentStrategy { private String wechatId; public WeChatPayStrategy(String wechatId) { this.wechatId = wechatId; } @Override public void pay(int amount) { System.out.println(amount + "元使用微信支付,微信号:" + wechatId); } } class AlipayStrategy implements PaymentStrategy { private String alipayAccount; public AlipayStrategy(String alipayAccount) { this.alipayAccount = alipayAccount; } @Override public void pay(int amount) { System.out.println(amount + "元使用支付宝支付,账号:" + alipayAccount); } } // 上下文类 class ShoppingCart { private List<String> items = new ArrayList<>(); private PaymentStrategy paymentStrategy; public void addItem(String item) { items.add(item); } public void setPaymentStrategy(PaymentStrategy strategy) { this.paymentStrategy = strategy; } public void checkout(int amount) { if (paymentStrategy == null) { throw new IllegalStateException("请先设置支付策略"); } paymentStrategy.pay(amount); } } // 使用示例 public class StrategyClient { public static void main(String[] args) { ShoppingCart cart = new ShoppingCart(); cart.addItem("商品1"); cart.addItem("商品2"); int totalAmount = 200; // 使用信用卡支付 cart.setPaymentStrategy(new CreditCardStrategy("1234-5678-9012-3456", "张三")); cart.checkout(totalAmount); // 切换为微信支付 cart.setPaymentStrategy(new WeChatPayStrategy("wx_zhangsan")); cart.checkout(totalAmount); // 切换为支付宝支付 cart.setPaymentStrategy(new AlipayStrategy("zhangsan@alipay.com")); cart.checkout(totalAmount); } }6.2 观察者模式:对象间的消息通知
观察者模式在事件驱动架构、GUI编程中广泛应用,它建立了对象间的一对多依赖关系。
// 文件路径:src/main/java/com/example/designpatterns/behavioral/observer/ObserverDemo.java import java.util.ArrayList; import java.util.List; // 主题接口 interface Subject { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(); } // 观察者接口 interface Observer { void update(String message); } // 具体主题:天气预报系统 class WeatherStation implements Subject { private List<Observer> observers = new ArrayList<>(); private String weatherData; @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers() { for (Observer observer : observers) { observer.update(weatherData); } } public void setWeatherData(String weatherData) { this.weatherData = weatherData; notifyObservers(); // 数据变化时通知所有观察者 } } // 具体观察者:手机显示 class PhoneDisplay implements Observer { private String weatherInfo; @Override public void update(String weatherData) { this.weatherInfo = weatherData; display(); } public void display() { System.out.println("手机显示:当前天气 - " + weatherInfo); } } // 具体观察者:电视显示 class TVDisplay implements Observer { private String weatherInfo; @Override public void update(String weatherData) { this.weatherInfo = weatherData; display(); } public void display() { System.out.println("电视显示:当前天气 - " + weatherInfo); } } // 使用示例 public class ObserverClient { public static void main(String[] args) { WeatherStation station = new WeatherStation(); PhoneDisplay phone = new PhoneDisplay(); TVDisplay tv = new TVDisplay(); // 注册观察者 station.registerObserver(phone); station.registerObserver(tv); // 更新天气数据,自动通知所有观察者 station.setWeatherData("晴天,25°C"); System.out.println("=== 天气变化 ==="); station.setWeatherData("多云,22°C"); // 移除一个观察者 station.removeObserver(tv); System.out.println("=== 移除电视显示后的变化 ==="); station.setWeatherData("小雨,18°C"); } }7. 设计模式在实际项目中的综合应用
单独理解每个模式很重要,但真正发挥价值的是在项目中组合使用多种模式。我们通过一个电商系统的订单处理模块来展示模式的实际组合应用。
7.1 订单处理系统的模式组合
// 文件路径:src/main/java/com/example/designpatterns/realworld/OrderProcessingSystem.java // 订单类使用建造者模式 class Order { private final String orderId; private final String customerId; private final List<String> items; private final double totalAmount; private final String status; private Order(Builder builder) { this.orderId = builder.orderId; this.customerId = builder.customerId; this.items = builder.items; this.totalAmount = builder.totalAmount; this.status = builder.status; } public static class Builder { private final String orderId; private final String customerId; private List<String> items = new ArrayList<>(); private double totalAmount = 0.0; private String status = "PENDING"; public Builder(String orderId, String customerId) { this.orderId = orderId; this.customerId = customerId; } public Builder items(List<String> items) { this.items = items; return this; } public Builder totalAmount(double amount) { this.totalAmount = amount; return this; } public Builder status(String status) { this.status = status; return this; } public Order build() { return new Order(this); } } // getter方法 public String getOrderId() { return orderId; } public String getCustomerId() { return customerId; } public List<String> getItems() { return items; } public double getTotalAmount() { return totalAmount; } public String getStatus() { return status; } } // 支付策略接口 interface PaymentStrategy { boolean processPayment(double amount, String orderId); } // 订单处理器使用模板方法模式 abstract class OrderProcessor { // 模板方法 public final void processOrder(Order order, PaymentStrategy paymentStrategy) { validateOrder(order); if (processPayment(order, paymentStrategy)) { updateInventory(order); notifyCustomer(order); logOrder(order); } else { handlePaymentFailure(order); } } protected abstract void validateOrder(Order order); protected abstract boolean processPayment(Order order, PaymentStrategy strategy); protected abstract void updateInventory(Order order); protected abstract void notifyCustomer(Order order); protected abstract void logOrder(Order order); protected abstract void handlePaymentFailure(Order order); } // 具体订单处理器 class StandardOrderProcessor extends OrderProcessor { @Override protected void validateOrder(Order order) { System.out.println("验证订单: " + order.getOrderId()); } @Override protected boolean processPayment(Order order, PaymentStrategy strategy) { System.out.println("处理支付,金额: " + order.getTotalAmount()); return strategy.processPayment(order.getTotalAmount(), order.getOrderId()); } @Override protected void updateInventory(Order order) { System.out.println("更新库存"); } @Override protected void notifyCustomer(Order order) { System.out.println("通知客户订单完成"); } @Override protected void logOrder(Order order) { System.out.println("记录订单日志"); } @Override protected void handlePaymentFailure(Order order) { System.out.println("处理支付失败"); } } // 使用观察者模式处理订单事件 class OrderEventManager { private Map<String, List<EventListener>> listeners = new HashMap<>(); public OrderEventManager(String... operations) { for (String operation : operations) { listeners.put(operation, new ArrayList<>()); } } public void subscribe(String eventType, EventListener listener) { List<EventListener> users = listeners.get(eventType); users.add(listener); } public void unsubscribe(String eventType, EventListener listener) { List<EventListener> users = listeners.get(eventType); users.remove(listener); } public void notify(String eventType, String data) { List<EventListener> users = listeners.get(eventType); for (EventListener listener : users) { listener.update(data); } } } interface EventListener { void update(String data); } // 使用示例 public class OrderSystemDemo { public static void main(String[] args) { // 创建订单 Order order = new Order.Builder("ORDER_001", "CUST_123") .items(Arrays.asList("商品A", "商品B")) .totalAmount(199.99) .status("PROCESSING") .build(); // 设置支付策略 PaymentStrategy paymentStrategy = new PaymentStrategy() { @Override public boolean processPayment(double amount, String orderId) { System.out.println("模拟支付处理: 订单 " + orderId + " 金额 " + amount); return true; // 模拟支付成功 } }; // 处理订单 OrderProcessor processor = new StandardOrderProcessor(); processor.processOrder(order, paymentStrategy); } }8. 设计模式常见误区与最佳实践
在实际项目中使用设计模式时,开发者容易陷入几个常见误区。了解这些陷阱能帮助你更好地运用模式。
8.1 常见误区分析
误区1:过度设计
- 问题:在简单场景中使用复杂模式,增加不必要的复杂度
- 解决:YAGNI原则(You Ain't Gonna Need It),只在真正需要时引入模式
误区2:模式强迫症
- 问题:试图在代码中强行套用模式,而不是让模式自然涌现
- 解决:先写可工作的代码,再考虑重构为模式
误区3:忽视语言特性
- 问题:在支持函数式编程的语言中仍然使用传统的OOP模式
- 解决:了解现代语言特性,如Java的Lambda、Stream API等
8.2 最佳实践指南
// 文件路径:src/main/java/com/example/designpatterns/bestpractices/PatternBestPractices.java // 1. 优先使用组合而不是继承 class NotificationService { private MessageSender sender; private Logger logger; // 通过组合获得灵活性 public NotificationService(MessageSender sender, Logger logger) { this.sender = sender; this.logger = logger; } } // 2. 面向接口编程,而不是具体实现 interface MessageSender { void send(String message); } class EmailSender implements MessageSender { @Override public void send(String message) { System.out.println("发送邮件: " + message); } } class SMSSender implements MessageSender { @Override public void send(String message) { System.out.println("发送短信: " + message); } } // 3. 使用依赖注入管理对象创建 class ServiceFactory { public static NotificationService createNotificationService() { MessageSender sender = new EmailSender(); // 可配置 Logger logger = new ConsoleLogger(); // 可配置 return new NotificationService(sender, logger); } } // 4. 保持类的单一职责 // 不好的做法:一个类做太多事情 class BadOrderProcessor { public void processOrder() { /* 处理订单 */ } public void sendEmail() { /* 发送邮件 */ } public void updateInventory() { /* 更新库存 */ } public void generateReport() { /* 生成报告 */ } } // 好的做法:职责分离 class OrderProcessor { public void processOrder() { /* 只处理订单逻辑 */ } } class EmailService { public void sendOrderConfirmation() { /* 专门处理邮件 */ } } class InventoryService { public void updateStock() { /* 专门处理库存 */ } }8.3 设计模式选择决策树
当面临设计问题时,可以按照以下流程选择合适的设计模式:
需要创建对象吗?
- 创建过程复杂?→建造者模式
- 需要控制实例数量?→单例模式
- 需要解耦创建逻辑?→工厂模式
需要组合对象或类吗?
- 接口不兼容?→适配器模式
- 需要动态添加功能?→装饰器模式
- 需要简化复杂接口?→外观模式
需要管理对象行为吗?
- 算法需要切换?→策略模式
- 对象状态变化需要通知?→观察者模式
- 需要封装请求?→命令模式
9. 设计模式的演进与现代化实践
随着编程语言和开发范式的发展,设计模式也在不断演进。了解这些变化能帮助你在现代项目中更好地应用模式。
9.1 函数式编程对传统模式的影响
在支持函数式编程的语言中,很多模式可以用更简洁的方式实现:
// 文件路径:src/main/java/com/example/designpatterns/modern/FunctionalPatterns.java import java.util.function.Function; import java.util.function.Predicate; // 传统策略模式 vs 函数式实现 class TraditionalStrategy { interface ValidationStrategy { boolean validate(String text); } class LengthValidator implements ValidationStrategy { @Override public boolean validate(String text) { return text.length() > 5; } } } // 函数式实现:使用Predicate class FunctionalStrategy { public void validateText(String text, Predicate<String> validator) { if (validator.test(text)) { System.out.println("验证通过"); } else { System.out.println("验证失败"); } } public void demo() { // 使用Lambda表达式 validateText("hello", s -> s.length() > 5); validateText("test", s -> s.contains("t")); } } // 传统观察者模式 vs 函数式实现 class FunctionalObserver { private List<Consumer<String>> observers = new ArrayList<>(); public void addObserver(Consumer<String> observer) { observers.add(observer); } public void notifyObservers(String event) { observers.forEach(observer -> observer.accept(event)); } }9.2 现代框架中的模式内化
很多现代框架已经内置了设计模式的实现,开发者不需要手动实现:
- Spring框架:依赖注入(控制反转)、单例模式、代理模式
- Java Stream API:装饰器模式、策略模式
- Reactive编程:观察者模式、迭代器模式
9.3 设计模式与架构模式的关系
理解设计模式与架构模式的区别很重要:
| 维度 | 设计模式 | 架构模式 |
|---|---|---|
| 范围 | 微观(类/对象级别) | 宏观(系统级别) |
| 关注点 | 代码结构、对象关系 | 系统分解、技术选型 |
| 示例 | 工厂模式、观察者模式 | MVC、微服务、事件驱动 |
在实际项目中,设计模式通常服务于架构模式。比如在微服务架构中,你可能会使用工厂模式创建服务实例,使用观察者模式处理服务间事件。
10. 实战练习:重构坏味道代码
最好的学习方式是通过实际的重构练习。下面是一个典型的"坏味道"代码示例,我们逐步将其重构为使用合适的设计模式。
10.1 原始代码(问题代码)
// 文件路径:src/main/java/com/example/designpatterns/refactor/before/BadCode.java class OrderService { public void processOrder(String orderType, String customerType, double amount) { // 复杂的条件判断 if (orderType.equals("ONLINE")) { if (customerType.equals("VIP")) { // VIP在线订单处理逻辑 System.out.println("处理VIP在线订单"); amount = amount * 0.9; // 9折 } else if (customerType.equals("NORMAL")) { // 普通在线订单处理逻辑 System.out.println("处理普通在线订单"); } } else if (orderType.equals("OFFLINE")) { if (customerType.equals("VIP")) { // VIP线下订单处理逻辑 System.out.println("处理VIP线下订单"); amount = amount * 0.8; // 8折 } else if (customerType.equals("NORMAL")) { // 普通线下订单处理逻辑 System.out.println("处理普通线下订单"); } } // 支付处理 if (amount > 1000) { // 大额支付逻辑 System.out.println("使用信用卡支付: " + amount); } else { // 小额支付逻辑 System.out.println("使用余额支付: " + amount); } // 通知逻辑 if (orderType.equals("ONLINE")) { System.out.println("发送邮件通知"); } else { System.out.println("发送短信通知"); } } }10.2 重构后的代码
// 文件路径:src/main/java/com/example/designpatterns/refactor/after/RefactoredCode.java // 使用策略模式处理折扣逻辑 interface DiscountStrategy { double applyDiscount(double originalAmount); } class VIPOnlineDiscount implements DiscountStrategy { @Override public double applyDiscount(double originalAmount) { return originalAmount * 0.9; } } class VIPOfflineDiscount implements DiscountStrategy { @Override public double applyDiscount(double originalAmount) { return originalAmount * 0.8; } } class NoDiscount implements DiscountStrategy { @Override