!设计模式的产生和发展背后有着深刻的原因:
一、为什么会有这么多设计模式?
1. 软件开发的普遍问题
- 重复出现的问题:软件开发中很多问题是普遍存在的
- 重复造轮子:程序员们反复解决相同的问题,但方法各异
- 经验传承:将优秀解决方案标准化,避免重复探索
2. 模式的形成过程
java
// 以单例模式为例:为什么需要它?
// 问题:如何确保一个类只有一个实例?
// 原始方案(各种不完善的尝试)
class Database {
// 每个人都用自己的方式控制,容易出错
}
// 经过多年实践,提炼出的最佳方案
class SingletonDatabase {
private static SingletonDatabase instance;
private SingletonDatabase() {} // 私有构造
public static SingletonDatabase getInstance() {
if (instance == null) {
instance = new SingletonDatabase();
}
return instance;
}
}
二、设计模式诞生的根本原因
1. 应对软件设计的复杂性
java
// 没有模式的情况:代码紧密耦合
class OrderService {
private MySQLDatabase db; // 直接依赖具体实现
private EmailSender email; // 紧密耦合
public void createOrder() {
// 业务逻辑、数据访问、发送邮件混在一起
}
}
// 使用模式后:职责分离
class OrderService {
private Database db; // 依赖抽象(策略模式)
private NotificationSender sender; // 依赖接口
public void createOrder() {
// 业务逻辑清晰
}
}
2. 解决特定类型的问题
| 问题类型 | 解决方案模式 | 具体问题 |
|---|---|---|
| 对象创建复杂 | 建造者模式 | 创建包含多个部分的复杂对象 |
| 接口不兼容 | 适配器模式 | 新旧系统接口不一致 |
| 状态管理复杂 | 状态模式 | 对象行为随状态改变 |
| 对象依赖过多 | 观察者模式 | 多个对象需要监听一个对象的变化 |
三、设计模式解决的核心问题
1. 代码的可维护性
java
// 问题:修改时牵一发而动全身
// 解决方案:使用模式降低耦合
// 坏示例:硬编码
class PaymentProcessor {
public void pay(String type) {
if ("credit".equals(type)) {
// 信用卡支付逻辑
} else if ("paypal".equals(type)) {
// PayPal支付逻辑
}
// 新增支付方式需要修改这里
}
}
// 好示例:策略模式
interface PaymentStrategy {
void pay();
}
class PaymentProcessor {
private PaymentStrategy strategy; // 易于扩展
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
}
2. 代码的可扩展性
java
// 问题:系统难以扩展新功能
// 解决方案:装饰器模式
// 基础组件
interface Coffee {
double getCost();
String getDescription();
}
// 装饰器基类
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
}
// 可以轻松添加新功能而不修改原有类
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double getCost() {
return decoratedCoffee.getCost() + 0.5;
}
}
3. 代码的复用性
java
// 模板方法模式:复用算法骨架
abstract class DataProcessor {
// 模板方法
public final void process() {
readData();
processData(); // 由子类实现
saveData();
}
protected abstract void processData();
}
四、设计模式的演进过程
历史背景:
- 1970-80年代:面向对象编程兴起
- 常见问题反复出现:程序员们各自解决相似问题
- 1994年 GoF:Erich Gamma等4人总结23种模式
- 模式社区发展:不断发现和记录新模式
为什么模式会持续增加?
java
// 新问题催生新模式
// 例如:响应式编程催生 Reactor 模式
// 并发编程催生 Actor 模式
五、重要设计模式诞生的原因
1. 单例模式:为什么出现?
- 问题:全局资源(配置、数据库连接池)需要唯一实例
- 防止:资源浪费、状态不一致
- 示例:Spring的ApplicationContext
2. 观察者模式:为什么出现?
- 问题:对象状态变化,多个对象需要知道
- 传统方案:直接调用所有依赖对象(紧耦合)
- 观察者模式:解耦,支持动态添加/移除观察者
3. 工厂模式:为什么出现?
- 问题:对象创建逻辑复杂,可能变化
- 坏处 :
new ConcreteClass()散布各处 - 好处:创建逻辑集中,易于修改
六、现实世界的类比
建筑模式的启发
- Christopher Alexander(建筑学家)首先提出"模式"概念
- 建筑设计中的"门窗安排"、"房间布局"等模式
- 软件设计借鉴了这一思想
生活中的模式
- 餐厅点餐:模板方法模式(固定流程:点餐→烹饪→上菜→结账)
- 电源适配器:适配器模式(不同插头标准转换)
- 快递物流:责任链模式(快递经过多个中转站)
七、正确看待设计模式
不要过度使用
java
// 反模式:为了模式而模式
class SimpleService {
// 一个简单类不需要工厂+单例+装饰器...
}
// 正确的态度:按需使用
// 1. 先写简单直接的代码
// 2. 发现痛点(变化、扩展、维护问题)
// 3. 选择合适模式重构
模式的价值
- 沟通词汇:说"用观察者模式"比描述整个方案更高效
- 最佳实践总结:避免重复踩坑
- 设计思维训练:学习如何设计灵活、可维护的系统
总结
设计模式的产生是软件开发经验积累的必然结果 。它们不是凭空发明的,而是从无数实际项目中提炼出来的解决特定问题的成熟方案。就像木工的工具箱,不同的工具(模式)解决不同的问题。理解模式背后的"为什么"比记住模式本身更重要,这样才能在适当的时候选择适当的工具。