1. 设计模式基础认知
2003年我刚入行时,第一次在《设计模式:可复用面向对象软件的基础》中看到23种设计模式的分类,那种醍醐灌顶的感觉至今难忘。设计模式不是银弹,但确实是程序员从"能写代码"到"会设计系统"的关键跃迁点。就像建筑领域的结构力学公式,这些模式凝结了无数前辈在复杂软件设计中总结出的最佳实践。
设计模式主要分为三大类:
- 创建型模式:处理对象创建机制,降低对象创建的复杂度
- 结构型模式:处理类和对象的组合关系,建立灵活的结构
- 行为型模式:处理对象间的通信与职责分配,提升协作效率
重要提示:不要为了用模式而用模式。我在2015年参与重构一个过度设计的中台系统时,发现开发者强行套用12种模式反而导致系统难以维护。好的模式应用应该像盐溶于水——解决问题却不着痕迹。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 创建型模式实战解析
2.1 单例模式(Singleton)
去年优化电商促销系统时,我们使用双重检查锁定实现日志服务单例:
java复制public class Logger {
private static volatile Logger instance;
private Logger() {}
public static Logger getInstance() {
if (instance == null) {
synchronized (Logger.class) {
if (instance == null) {
instance = new Logger();
}
}
}
return instance;
}
}
这种实现既保证线程安全又避免每次访问都同步。在需要全局访问点且要求唯一性的场景(如配置管理、线程池、缓存)中特别实用。
2.2 工厂方法模式(Factory Method)
开发跨平台UI组件库时,我们抽象了按钮创建接口:
typescript复制interface ButtonFactory {
createButton(): Button;
}
class WindowsButtonFactory implements ButtonFactory {
createButton() { return new WindowsButton(); }
}
class MacOSButtonFactory implements ButtonFactory {
createButton() { return new MacOSButton(); }
}
这使得新增Linux平台支持时,只需添加新的工厂类而无需修改现有代码。在需要隔离具体类、支持扩展的场景下,工厂方法比简单工厂更符合开闭原则。
2.3 建造者模式(Builder)
为简化复杂报表对象的构建,我们设计了这样的建造者:
python复制class ReportBuilder:
def set_title(self, title): ...
def set_chart(self, chart_type): ...
def add_dataset(self, data): ...
def build(self) -> Report: ...
# 使用示例
builder = ReportBuilder()
report = (builder.set_title("销售报表")
.set_chart("折线图")
.add_dataset(q1_data)
.add_dataset(q2_data)
.build())
当对象需要多个步骤构建且存在不同表示时(如SQL查询构造器、邮件组装器),建造者模式能提供清晰的创建流程和灵活的配置能力。
3. 结构型模式深度应用
3.1 适配器模式(Adapter)
在整合第三方支付接口时,我们遇到接口不兼容问题:
java复制// 现有系统接口
interface PaymentProcessor {
void process(Order order);
}
// 第三方支付类
class WeChatPay {
void pay(String orderId, BigDecimal amount) { ... }
}
// 适配器实现
class WeChatPayAdapter implements PaymentProcessor {
private WeChatPay wechatPay = new WeChatPay();
@Override
public void process(Order order) {
wechatPay.pay(order.getId(), order.getTotal());
}
}
这个模式在系统演进过程中特别有用,就像Type-C转接头让新旧设备能协同工作。但要注意避免过度适配导致的"适配器地狱"。
3.2 装饰器模式(Decorator)
实现带缓存的文件读取器时:
typescript复制interface DataReader {
read(): string;
}
class FileReader implements DataReader { ... }
class CachedReader implements DataReader {
constructor(private reader: DataReader) {}
private cache: string | null = null;
read() {
if (!this.cache) {
this.cache = this.reader.read();
}
return this.cache;
}
}
// 使用
const reader = new CachedReader(new FileReader());
这种动态添加职责的方式比继承更灵活,在需要透明扩展功能的场景(如权限校验、日志记录、性能监控)中表现优异。
3.3 外观模式(Facade)
为简化微服务调用,我们设计了服务门面:
go复制type OrderFacade struct {
inventoryClient *InventoryService
paymentClient *PaymentService
shippingClient *ShippingService
}
func (f *OrderFacade) PlaceOrder(order Order) error {
if err := f.inventoryClient.ReserveItems(order); err != nil {
return err
}
if err := f.paymentClient.ProcessPayment(order); err != nil {
f.inventoryClient.RollbackReservation(order)
return err
}
return f.shippingClient.ScheduleDelivery(order)
}
外观模式就像餐厅领班,对外提供简单接口,内部协调多个子系统。在复杂模块整合、API网关等场景中能显著降低使用复杂度。
4. 行为型模式最佳实践
4.1 观察者模式(Observer)
实现实时数据看板时:
python复制class DataSubject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def notify(self, data):
for obs in self._observers:
obs.update(data)
class ChartObserver:
def update(self, data):
self.redraw(data)
# 使用
subject = DataSubject()
subject.attach(ChartObserver())
subject.notify(new_data)
这种发布-订阅机制在事件驱动架构中无处不在,从GUI事件处理到WebSocket消息推送都在使用其变体。但要注意避免观察者之间的隐式耦合。
4.2 策略模式(Strategy)
电商促销系统中有多种折扣策略:
java复制interface DiscountStrategy {
BigDecimal apply(BigDecimal amount);
}
class ChristmasDiscount implements DiscountStrategy { ... }
class MemberDiscount implements DiscountStrategy { ... }
class Order {
private DiscountStrategy strategy;
void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
BigDecimal checkout() {
return strategy.apply(this.total);
}
}
策略模式让算法可以独立于客户端变化,在需要动态切换业务规则(如支付方式、排序算法、验证规则)时特别有用。我们团队通过这种设计使促销活动配置时间从2天缩短到2小时。
4.3 责任链模式(Chain of Responsibility)
处理HTTP请求中间件时:
javascript复制class Middleware {
constructor(next = null) {
this.next = next;
}
handle(request) {
if (this.canProcess(request)) {
return this.process(request);
}
return this.next?.handle(request);
}
}
class AuthMiddleware extends Middleware { ... }
class LoggingMiddleware extends Middleware { ... }
class CacheMiddleware extends Middleware { ... }
// 构建处理链
const handler = new AuthMiddleware(
new LoggingMiddleware(
new CacheMiddleware()));
这种模式让多个处理器都有机会处理请求,在审批流程、异常处理、过滤器链等场景表现出色。我们用它实现的插件系统支持动态插入处理节点。
5. 模式选择与组合实践
在真实项目中,模式往往需要组合使用。去年设计分布式任务调度系统时,我们这样组合模式:
- 用抽象工厂创建不同任务类型
- 用装饰器添加重试、日志等能力
- 用策略模式实现不同调度算法
- 用观察者模式通知任务状态变更
选择模式的几个经验原则:
- 当创建逻辑复杂时 → 考虑创建型模式
- 当接口适配困难时 → 考虑结构型模式
- 当行为需要灵活变化时 → 考虑行为型模式
- 当变化方向明确时 → 针对该变化点应用模式
避坑指南:在微服务架构中,有些模式会自然下沉到基础设施层(如网关中的外观模式、消息队列中的观察者模式),此时在业务代码中强行应用反而会造成过度设计。
