当前位置: 首页 > news >正文

23种设计模式解析--行为型

行为型模式(协作的艺术)
  1. 观察者模式

观察者模式详解

模式定义

观察者模式(Observer Pattern)是一种行为设计模式,用于建立对象间一对多的依赖关系。当一个对象(Subject)状态变化时,所有依赖它的对象(Observers)会自动收到通知并更新。该模式解耦了主题与观察者,遵循开闭原则(对扩展开放,对修改关闭)。

核心组件
  1. Subject (主题)
    • 维护观察者列表(添加/删除方法)
    • 提供状态更新通知方法(NotifyObservers
  2. Observer (观察者接口)
    • 定义更新接口(如Update()
  3. ConcreteObserver (具体观察者)
    • 实现更新逻辑,与主题状态同步
  4. ConcreteSubject (具体主题)
    • 存储具体状态,状态变更时触发通知

C# 实现示例

// 主题接口
public interface ISubject {void RegisterObserver(IObserver o);void RemoveObserver(IObserver o);void NotifyObservers();
}// 观察者接口
public interface IObserver {void Update(string message);
}// 具体主题(新闻发布中心)
public class NewsAgency : ISubject {private List<IObserver> _observers = new List<IObserver>();private string _latestNews;public void RegisterObserver(IObserver o) => _observers.Add(o);public void RemoveObserver(IObserver o) => _observers.Remove(o);public void NotifyObservers() {foreach (var observer in _observers) {observer.Update(_latestNews);}}public void PublishNews(string news) {_latestNews = news;NotifyObservers(); // 状态变更时自动通知}
}// 具体观察者(新闻订阅用户)
public class NewsSubscriber : IObserver {private string _name;public NewsSubscriber(string name) => _name = name;public void Update(string news) {Console.WriteLine($"{_name} received news: {news}");}
}// 使用
var agency = new NewsAgency();
var user1 = new NewsSubscriber("User1");
var user2 = new NewsSubscriber("User2");agency.RegisterObserver(user1);
agency.RegisterObserver(user2);
agency.PublishNews("Breaking: New AI Model Released!");

Java 实现示例

import java.util.*;// 主题接口
interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}// 观察者接口
interface Observer {void update(String message);
}// 具体主题(股票交易所)
class StockExchange implements Subject {private List<Observer> observers = new ArrayList<>();private double stockPrice;public void registerObserver(Observer o) { observers.add(o); }public void removeObserver(Observer o) { observers.remove(o); }public void notifyObservers() {for (Observer o : observers) {o.update("Price updated: " + stockPrice);}}public void setStockPrice(double price) {this.stockPrice = price;notifyObservers(); // 价格变动时通知}
}// 具体观察者(交易员)
class Trader implements Observer {private String name;public Trader(String name) { this.name = name; }@Overridepublic void update(String message) {System.out.println(name + " notified: " + message);}
}// 使用
public class Main {public static void main(String[] args) {StockExchange exchange = new StockExchange();Trader trader1 = new Trader("Alice");Trader trader2 = new Trader("Bob");exchange.registerObserver(trader1);exchange.registerObserver(trader2);exchange.setStockPrice(150.75);}
}

常用应用场景

  1. 事件驱动系统
    • GUI按钮点击事件(如C# WinForms、Java Swing)
    • 游戏引擎中的碰撞检测事件
  2. 发布-订阅模型
    • 新闻推送、社交媒体Feed更新
    • 微服务间的事件通知(如Kafka消息队列)
  3. 状态监控
    • 服务器资源使用率报警(CPU/Memory阈值触发)
    • IoT设备数据实时仪表盘
  4. 数据同步
    • 数据库变更同步到缓存(如Redis)
    • Excel单元格修改联动图表刷新
  5. MVC架构
    • 模型(Model)变更时自动更新视图(View)

关键注意事项

  1. 内存泄漏风险

    • 问题:观察者未注销时,主题持有其引用导致无法GC回收。
    • 解决:显式调用RemoveObserver()(如C# IDisposable接口、Java close()方法)。
  2. 通知顺序不可控

    • 问题:观察者接收顺序依赖注册顺序,可能影响业务逻辑。
    • 解决:引入优先级机制或保证观察者独立性。
  3. 性能瓶颈

    • 问题:观察者过多或更新逻辑复杂导致通知延迟。
    • 解决
      • 异步通知(如C# Task.Run、Java ExecutorService
      • 批量更新(合并多次状态变更)
  4. 循环依赖

    • 问题:观察者更新时反向修改主题状态,引发递归通知。
    • 解决:状态变更前检查if (oldState != newState)
  5. 线程安全问题

    • 问题:多线程环境下观察者列表动态修改导致ConcurrentModificationException(Java)。
    • 解决:使用线程安全集合(如CopyOnWriteArrayList)或同步锁。

架构设计建议

  1. 使用现有框架

    • C#:内置IObservable<T>/IObserver<T>接口
      public class Stock : IObservable<double> {private List<IObserver<double>> observers = new List<IObserver<double>>();public IDisposable Subscribe(IObserver<double> observer) { ... }
      }
      
    • Javajava.util.Observable类(已过时,推荐自定义实现)
  2. 事件与委托优化(C#专属)

    • 使用event关键字简化观察者管理:
      public class Publisher {public event Action<string> OnMessagePublished;public void Publish(string msg) => OnMessagePublished?.Invoke(msg);
      }
      
  3. 避免过度耦合

    • 观察者不应直接调用具体主题的方法,通过接口交互。
    • 主题通过NotifyObservers()传递最小必要数据(如事件对象而非整个主题引用)。
  4. 分布式场景扩展

    • 结合消息中间件(如RabbitMQ、Azure Service Bus)实现跨进程观察者模式。
  5. 测试策略

    • 使用Mock观察者验证主题通知逻辑。
    • 注入虚拟主题测试观察者行为。

模式优缺点

优点缺点
主题与观察者解耦意外更新链(级联通知)
动态添加/移除观察者调试困难(间接调用链)
符合开闭原则(新增观察者无需改主题)可能增加系统复杂性

适用性:适合状态变化触发跨模块更新,但需警惕过度使用导致系统难以追踪。

  1. 策略模式

策略模式详解:架构师视角

策略模式(Strategy Pattern)是一种行为设计模式,它定义一系列算法,封装每个算法,并使它们可以相互替换。策略模式让算法的变化独立于使用它的客户端。


核心结构

classDiagramclass Context {-IStrategy strategy+SetStrategy(IStrategy)+ExecuteStrategy()}interface IStrategy {+Execute()}class ConcreteStrategyA {+Execute()}class ConcreteStrategyB {+Execute()}Context o--> IStrategyIStrategy <|.. ConcreteStrategyAIStrategy <|.. ConcreteStrategyB
  1. Context(上下文)

    • 维护策略对象的引用
    • 提供设置策略的方法
    • 执行策略的入口
  2. Strategy(策略接口)

    • 定义算法族的公共接口
  3. ConcreteStrategy(具体策略)

    • 实现策略接口的具体算法

C#/Java 代码示例

C# 实现
// 策略接口
public interface IPaymentStrategy 
{void ProcessPayment(decimal amount);
}// 具体策略
public class CreditCardPayment : IPaymentStrategy
{public void ProcessPayment(decimal amount) => Console.WriteLine($"Credit card: ${amount}");
}public class PayPalPayment : IPaymentStrategy
{public void ProcessPayment(decimal amount) => Console.WriteLine($"PayPal: ${amount}");
}// 上下文
public class PaymentContext
{private IPaymentStrategy _strategy;public void SetStrategy(IPaymentStrategy strategy) => _strategy = strategy;public void ExecutePayment(decimal amount) => _strategy?.ProcessPayment(amount);
}// 使用
var context = new PaymentContext();
context.SetStrategy(new CreditCardPayment());
context.ExecutePayment(100);  // 输出: Credit card: $100
Java 实现
// 策略接口
interface PaymentStrategy {void processPayment(BigDecimal amount);
}// 具体策略
class WeChatPay implements PaymentStrategy {@Overridepublic void processPayment(BigDecimal amount) {System.out.println("WeChat Pay: " + amount);}
}class Alipay implements PaymentStrategy {@Overridepublic void processPayment(BigDecimal amount) {System.out.println("Alipay: " + amount);}
}// 上下文
class PaymentContext {private PaymentStrategy strategy;public void setStrategy(PaymentStrategy strategy) {this.strategy = strategy;}public void executePayment(BigDecimal amount) {if(strategy != null) {strategy.processPayment(amount);}}
}// 使用
PaymentContext context = new PaymentContext();
context.setStrategy(new Alipay());
context.executePayment(new BigDecimal("200"));  // 输出: Alipay: 200

典型应用场景

  1. 支付系统(如示例):

    • 支持多种支付方式(信用卡/PayPal/加密货币)
    • 新增支付方式不影响现有逻辑
  2. 数据压缩/加密

    public interface ICompressionStrategy {byte[] Compress(byte[] data);
    }public class ZipCompression : ICompressionStrategy { ... }
    public class RarCompression : ICompressionStrategy { ... }
    
  3. 路由算法

    public interface IRoutingStrategy {Route CalculateRoute(Point start, Point end);
    }public class FastestRouteStrategy implements IRoutingStrategy { ... }
    public class EcoRouteStrategy implements IRoutingStrategy { ... }
    
  4. 表单验证

    public interface IValidationStrategy {bool Validate(string input);
    }public class EmailValidation : IValidationStrategy { ... }
    public class PhoneValidation : IValidationStrategy { ... }
    
  5. 电商折扣策略

    public interface IDiscountStrategy {BigDecimal applyDiscount(BigDecimal originalPrice);
    }public class VIPDiscount implements IDiscountStrategy { ... }
    public class FestivalDiscount implements IDiscountStrategy { ... }
    

架构建议与注意事项

  1. 避免策略膨胀

    • 当策略超过10个时,考虑使用策略工厂管理创建
    public class StrategyFactory {public IPaymentStrategy Create(string type) => type switch {"CreditCard" => new CreditCardPayment(),"PayPal" => new PayPalPayment(),_ => throw new ArgumentException()};
    }
    
  2. 策略与状态模式区分

    • 策略模式:算法选择(客户端主动切换)
    • 状态模式:状态驱动(自动切换)
  3. 性能优化

    • 无状态策略可设计为单例减少对象创建
    public enum CompressionSingleton implements ICompressionStrategy {INSTANCE;@Overridepublic byte[] compress(byte[] data) { ... }
    }
    
  4. 依赖注入集成

    • 通过DI容器管理策略生命周期
    services.AddTransient<IPaymentStrategy, CreditCardPayment>();
    services.AddTransient<IPaymentStrategy, PayPalPayment>();
    
  5. 策略组合

    • 支持策略的嵌套组合(装饰器模式)
    public class DiscountCombo implements IDiscountStrategy {private List<IDiscountStrategy> strategies;public BigDecimal applyDiscount(BigDecimal price) {for (IDiscountStrategy s : strategies) {price = s.applyDiscount(price);}return price;}
    }
    
  6. 文档规范

    • 使用XML注释/JavaDoc明确策略契约
    /*** @implSpec 实现必须保证线程安全*/
    public interface ICachingStrategy { ... }
    

反模式警示

  1. 策略泄露

    // 错误:上下文暴露策略细节
    public class PaymentContext {public void ProcessCreditCard(CardDetails card) { ... }
    }
    
  2. 过度抽象

    • 简单条件判断无需策略模式
    // 不推荐:只有两种固定策略
    if(isVip) {new VIPDiscount().apply(price);
    } else {new RegularDiscount().apply(price);
    }
    
  3. 策略耦合

    // 错误:策略依赖具体实现
    public class Alipay : IPaymentStrategy {public void Process() {// 直接依赖微信支付new WeChatPay().Process(); }
    }
    

性能考量

场景建议方案
高频调用策略使用轻量级策略对象
策略初始化成本高延迟加载/Lazy初始化
需要动态切换策略使用享元模式管理策略实例
策略执行需要上下文数据通过参数传递避免状态存储

最佳实践总结

  1. 定义清晰策略边界:每个策略应解决单一问题
  2. 面向接口编程:上下文仅依赖策略接口
  3. 控制策略范围:避免创建过于细粒度的策略
  4. 结合工厂模式:解耦策略创建逻辑
  5. 单元测试策略:独立测试每个策略实现
  6. 监控策略执行:记录策略使用情况用于分析

架构师洞见:策略模式本质是将可变性封装在独立的策略对象中,符合开闭原则(OCP)。在微服务架构中,可将复杂策略实现为独立服务,通过策略网关进行路由,实现架构级策略管理。

  1. 命令模式

命令模式详解

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为独立对象(命令),解耦请求的发送者(Invoker)和接收者(Receiver),支持请求排队、日志记录、撤销/重做等操作。


核心组件
角色作用
Command抽象命令接口,声明执行方法(如 Execute()
ConcreteCommand具体命令,绑定接收者与动作,实现 Execute()(调用接收者的方法)
Receiver实际执行业务逻辑的对象(如数据库操作、设备控制)
Invoker触发命令的对象(如按钮、菜单),不直接依赖接收者
Client创建命令对象并设置其接收者

C# 实现示例

// 命令接口
public interface ICommand {void Execute();void Undo(); // 支持撤销
}// 接收者:实际执行操作的对象
public class Light {public void TurnOn() => Console.WriteLine("Light is ON");public void TurnOff() => Console.WriteLine("Light is OFF");
}// 具体命令
public class LightOnCommand : ICommand {private Light _light;public LightOnCommand(Light light) => _light = light;public void Execute() => _light.TurnOn();public void Undo() => _light.TurnOff(); // 撤销操作
}// 调用者(如遥控器按钮)
public class RemoteControl {private ICommand _command;public void SetCommand(ICommand command) => _command = command;public void PressButton() {_command.Execute();_history.Push(_command); // 记录历史用于撤销}private Stack<ICommand> _history = new Stack<ICommand>();
}// 客户端
var light = new Light();
var lightOn = new LightOnCommand(light);
var remote = new RemoteControl();
remote.SetCommand(lightOn);
remote.PressButton(); // 输出:"Light is ON"

Java 实现示例

// 命令接口
interface Command {void execute();void undo();
}// 接收者
class Light {public void turnOn() { System.out.println("Light ON"); }public void turnOff() { System.out.println("Light OFF"); }
}// 具体命令
class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) { this.light = light; }@Overridepublic void execute() { light.turnOn(); }@Overridepublic void undo() { light.turnOff(); }
}// 调用者
class RemoteControl {private Command command;private Stack<Command> history = new Stack<>();public void setCommand(Command command) { this.command = command; }public void pressButton() {command.execute();history.push(command);}
}// 客户端
public static void main(String[] args) {Light light = new Light();Command lightOn = new LightOnCommand(light);RemoteControl remote = new RemoteControl();remote.setCommand(lightOn);remote.pressButton(); // 输出:"Light ON"
}

常用应用场景

  1. GUI 操作
    • 按钮点击、菜单命令(如文本编辑器的复制/粘贴)
    • 示例:将每个操作封装为命令对象,支持撤销/重做。
  2. 任务队列与日志
    • 将请求排队(如线程池任务调度)
    • 记录操作日志(用于审计或崩溃恢复)
  3. 事务行为
    • 数据库事务的原子操作(失败时执行反向命令回滚)
  4. 宏命令(组合命令)
    • 一键执行多个命令(如批量处理文件)
  5. 异步任务管理
    • 将耗时操作封装为命令,由后台线程执行

注意事项与架构建议

注意事项
  1. 避免过度设计:简单请求(如直接函数调用)无需使用命令模式。
  2. 内存消耗:每个命令都是一个独立对象,大量命令可能增加内存开销。
  3. 撤销实现复杂性
    • 需存储额外状态(如 Memento 模式)或反向操作逻辑。
    • 多次撤销可能需维护命令历史栈。
架构建议
  1. 结合其他模式增强能力
    • 组合模式:实现宏命令(组合多个子命令)。
    • 备忘录模式:存储命令执行前的状态,支持完美撤销。
    // 示例:宏命令(C#)
    public class MacroCommand : ICommand {private List<ICommand> _commands = new List<ICommand>();public void Add(ICommand cmd) => _commands.Add(cmd);public void Execute() => _commands.ForEach(cmd => cmd.Execute());
    }
    
  2. 依赖注入
    • 通过 DI 容器管理命令和接收者,提高可测试性。
  3. 线程安全
    • 多线程环境下,命令对象需设计为无状态或使用锁机制。
  4. 空命令对象
    • 提供 NullCommand 避免 Invoker 对命令的空值检查。
    // Java 空命令示例
    class NullCommand implements Command {@Override public void execute() {} @Override public void undo() {}
    }
    
  5. 命令持久化
    • 序列化命令对象,支持重启后恢复操作(如游戏存档)。

设计原则验证

  • 单一职责原则:命令对象仅封装请求,接收者专注业务逻辑。
  • 开闭原则:新增命令无需修改 Invoker 或 Receiver。
  • 松耦合:Invoker 仅依赖抽象命令,与接收者解耦。

总结

适用场景:需要解耦请求发送者与接收者、支持撤销/重做、任务队列或日志的场景。
避坑指南

  • 简单场景避免滥用,优先考虑函数式编程替代(如 C# Action/Java Runnable)。
  • 为高频命令实现轻量级版本(如共享无状态接收者)。
  • 撤销功能需在早期设计阶段考虑,避免后期重构。

命令模式通过封装请求为对象,显著提升系统的灵活性与扩展性,是复杂操作管理的核心模式之一。

  1. 状态模式

状态模式(State Pattern)详解

核心概念

状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为,使对象看起来像是修改了它的类。该模式将状态相关的行为封装到独立的类中,并通过委托机制让上下文对象在不同状态下表现出不同行为。

核心组件
  1. Context(上下文)
    • 持有当前状态对象的引用
    • 定义客户端交互接口
    • 提供状态切换方法
  2. State(抽象状态)
    • 定义状态接口,声明状态相关行为
  3. ConcreteState(具体状态)
    • 实现状态接口,封装特定状态下的行为
C# 实现示例
// 抽象状态
public interface IOrderState
{void Confirm(OrderContext context);void Cancel(OrderContext context);void Ship(OrderContext context);
}// 具体状态:待确认
public class PendingState : IOrderState
{public void Confirm(OrderContext context) => context.SetState(new ConfirmedState());public void Cancel(OrderContext context) => context.SetState(new CancelledState());public void Ship(OrderContext context) => throw new InvalidOperationException("待确认订单不能发货");
}// 具体状态:已确认
public class ConfirmedState : IOrderState
{public void Confirm(OrderContext context) => throw new InvalidOperationException("订单已确认");public void Cancel(OrderContext context) => context.SetState(new CancelledState());public void Ship(OrderContext context) => context.SetState(new ShippedState());
}// 上下文
public class OrderContext
{private IOrderState _state = new PendingState();public void SetState(IOrderState state) => _state = state;public void Confirm() => _state.Confirm(this);public void Cancel() => _state.Cancel(this);public void Ship() => _state.Ship(this);
}// 使用
var order = new OrderContext();
order.Confirm();  // 状态转为ConfirmedState
order.Ship();     // 状态转为ShippedState
Java 实现示例
// 抽象状态
interface OrderState {void confirm(OrderContext context);void cancel(OrderContext context);void ship(OrderContext context);
}// 具体状态:待确认
class PendingState implements OrderState {public void confirm(OrderContext context) {context.setState(new ConfirmedState());}public void cancel(OrderContext context) {context.setState(new CancelledState());}public void ship(OrderContext context) {throw new IllegalStateException("待确认订单不能发货");}
}// 上下文
class OrderContext {private OrderState state = new PendingState();void setState(OrderState state) { this.state = state; }void confirm() { state.confirm(this); }void cancel() { state.cancel(this); }void ship() { state.ship(this); }
}

典型应用场景

  1. 订单/工作流系统

    • 订单状态(待支付/已发货/已完成)
    • 审批流程(草稿/审批中/已批准)
  2. 游戏角色状态

    • 角色行为(站立/奔跑/跳跃/攻击)
    • 状态切换时行为变化(如跳跃时不可攻击)
  3. 硬件控制

    • 电梯状态(停止/运行/故障)
    • 打印机状态(空闲/打印/卡纸)
  4. UI 组件交互

    • 按钮状态(正常/禁用/悬停)
    • 动画控件状态(开始/暂停/停止)
  5. 网络协议处理

    • TCP连接状态(建立连接/数据传输/断开连接)
    • 协议状态机实现

注意事项

  1. 避免状态膨胀

    • 当状态超过10个时需重新评估设计
    • 考虑使用状态表(State Table)或状态机库替代
  2. 状态转换控制

    • 转换逻辑放在Context还是State?
      • Context控制:集中管理转换规则(推荐)
      • State控制:增加状态间耦合(慎用)
  3. 状态共享

    • 无内部状态的状态对象可设计为单例
    public class CancelledState : IOrderState 
    {public static readonly IOrderState Instance = new CancelledState();// ... 实现方法
    }
    
  4. 初始化问题

    • 确保Context初始状态有效
    • 使用工厂方法初始化默认状态
  5. 并发安全

    • 多线程环境下需同步状态切换
    • 推荐使用不可变状态对象

架构建议

1. 分层状态机
payment
cancel
ship
confirm
Unpaid
Paid
Cancelled
Shipped
Completed
  • 复杂场景使用分层状态(HFSM)
  • 子状态可继承父状态行为
2. 与策略模式对比
状态模式策略模式
状态自动转换策略手动切换
状态知晓上下文策略独立于上下文
状态间存在关联策略可独立替换
3. 性能优化
  • 状态预创建:初始化时创建所有状态对象
  • 轻量状态:避免在状态中存储上下文数据
4. 测试建议
  • 为每个状态类编写独立单元测试
  • 验证非法状态转换的异常处理
  • 使用Mock对象测试状态间交互
5. 与其它模式协作
  • 结合享元模式:共享无状态的状态对象
  • 使用备忘录模式:实现状态历史回溯
  • 通过观察者模式:通知状态变更事件

反模式警示

  1. 上帝状态对象

    // 错误示范:一个状态类处理所有逻辑
    public class GodState : IOrderState 
    {public void Handle(OrderContext ctx) {if(ctx.Status == Status.Pending) {...}else if(ctx.Status == Status.Confirmed) {...} // 违反开闭原则}
    }
    
  2. 循环依赖

    • 状态类不应直接引用其它具体状态类
    • 通过Context进行状态切换解耦
  3. 忽略状态重置

    • 长时间运行的系统需设计状态重置机制
    • 提供Reset()方法恢复初始状态

最佳实践总结

  1. 明确状态边界:每个状态对应唯一行为集合
  2. 单向依赖原则:状态类只依赖抽象Context
  3. 有限状态转换:使用状态转换图定义合法路径
  4. 文档驱动:使用PlantUML等工具维护状态图
  5. 防御式编程:在Context中验证状态转换合法性

架构师建议:在核心业务逻辑(如订单/支付)中使用状态模式,能显著提升系统可维护性。对于超复杂状态机(>20状态),推荐使用专门的State Machine框架(如Stateless for .NET或Spring State Machine)。

  1. 责任链

责任链模式详解

模式定义

责任链(Chain of Responsibility)是一种行为型设计模式,允许多个对象按顺序处理请求,形成处理链。请求沿链传递直到被处理或到达链尾,实现发送者与接收者的解耦。

核心组件
  1. Handler(抽象处理者)
    • 定义处理请求的接口
    • 持有下一个处理者的引用(可选)
  2. ConcreteHandler(具体处理者)
    • 实现请求处理逻辑
    • 决定是否处理请求或传递给下一处理者
  3. Request(请求对象)
    • 封装请求数据

C# 实现示例

// 请求类
public class PurchaseRequest {public decimal Amount { get; set; }
}// 抽象处理者
public abstract class Approver {protected Approver? NextApprover;public void SetNext(Approver next) => NextApprover = next;public abstract void Process(PurchaseRequest request);
}// 具体处理者:经理
public class Manager : Approver {public override void Process(PurchaseRequest request) {if (request.Amount <= 1000) {Console.WriteLine($"经理审批: {request.Amount}元");} else if (NextApprover != null) {NextApprover.Process(request); // 传递请求}}
}// 具体处理者:总监
public class Director : Approver {public override void Process(PurchaseRequest request) {if (request.Amount <= 5000) {Console.WriteLine($"总监审批: {request.Amount}元");} else if (NextApprover != null) {NextApprover.Process(request);}}
}// 使用
var manager = new Manager();
var director = new Director();
manager.SetNext(director);manager.Process(new PurchaseRequest { Amount = 800 });   // 经理处理
manager.Process(new PurchaseRequest { Amount = 4500 });  // 总监处理

Java 实现示例

// 抽象处理者
abstract class Approver {protected Approver next;public void setNext(Approver next) { this.next = next; }public abstract void process(PurchaseRequest request);
}// 具体处理者
class Manager extends Approver {@Overridepublic void process(PurchaseRequest request) {if (request.getAmount() <= 1000) {System.out.println("经理审批: " + request.getAmount());} else if (next != null) {next.process(request); // 传递请求}}
}// 使用
Approver manager = new Manager();
Approver director = new Director();
manager.setNext(director);manager.process(new PurchaseRequest(800));   // 经理处理
manager.process(new PurchaseRequest(4500));  // 总监处理

常用场景

  1. 多级审批系统
    • 费用报销、请假审批(不同金额/时长由不同层级审批)
  2. 请求过滤/中间件
    • Web框架的过滤器链(如Spring Security)
    • 日志记录、身份验证、数据清洗
  3. 事件处理
    • GUI事件冒泡(如Java AWT/Swing)
  4. 异常处理
    • 多级异常捕获机制(如Java的try-catch链)
  5. 日志分级处理
    • DEBUG → INFO → WARN → ERROR 链式传递

注意事项

  1. 链的终止条件
    • 必须确保链有终点,避免请求无限循环
    • 可在基类添加默认处理逻辑(如抛出异常或日志警告)
  2. 性能考量
    • 长链可能导致性能下降,避免高频场景使用
  3. 调试复杂性
    • 请求传递路径不易跟踪,需完善日志
  4. 处理者顺序敏感
    • 链的顺序影响行为(如权限检查应先于业务处理)
  5. 请求丢失风险
    • 确保所有处理者正确传递未处理的请求

架构建议

  1. 动态链构建
    • 使用配置文件或依赖注入动态组装链(如Spring的@Order
    // Spring示例:按Order注解排序
    @Component @Order(1)
    class AuthFilter implements Filter { ... }
    
  2. 组合模式融合
    • 复杂场景下,用组合模式构建树形责任链
  3. 模板方法优化
    • 在抽象类中封装传递逻辑,子类聚焦核心处理
    public abstract class Approver {protected virtual bool CanHandle(PurchaseRequest r) => false;public void Process(PurchaseRequest r) {if (CanHandle(r)) Handle(r);else NextApprover?.Process(r);}protected abstract void Handle(PurchaseRequest r);
    }
    
  4. 短路机制
    • 特定场景可中断传递(如权限验证失败时直接返回)
  5. 监控扩展
    • 添加链执行统计(如处理时长、成功率)

经典应用

框架/系统应用场景
Spring MVC拦截器链(HandlerInterceptor)
Servlet Filter请求过滤链
Log4j/Logback日志级别过滤链
NettyChannelHandler处理链

责任链模式通过解耦请求发送者和处理者,显著提升系统扩展性。适用于需动态调整处理流程的场景,但需谨慎处理链的终止条件和性能影响。
15. 迭代器

迭代器模式详解(Iterator Pattern)

模式定义

迭代器模式是一种行为设计模式,提供一种方法顺序访问聚合对象中的各个元素,而无需暴露该对象的内部表示。它通过将遍历逻辑从聚合对象中分离,实现“单一职责原则”,同时支持多种遍历方式。

核心组件
组件作用示例接口
迭代器接口定义遍历操作(如 next, hasNext)IEnumerator (C#) / Iterator (Java)
具体迭代器实现迭代器接口,持有聚合对象的引用并跟踪遍历位置ListEnumerator
聚合接口定义创建迭代器的方法IEnumerable (C#) / Iterable (Java)
具体聚合类实现聚合接口,返回具体迭代器实例List<T>

C# 实现示例

// 迭代器接口
public interface IIterator
{bool HasNext();object Next();
}// 聚合接口
public interface IAggregate
{IIterator CreateIterator();
}// 具体聚合类
public class ConcreteAggregate : IAggregate
{private object[] _items = { "A", "B", "C" };public IIterator CreateIterator(){return new ConcreteIterator(this);}public int Count => _items.Length;public object this[int index] => _items[index];
}// 具体迭代器
public class ConcreteIterator : IIterator
{private readonly ConcreteAggregate _aggregate;private int _index = 0;public ConcreteIterator(ConcreteAggregate aggregate){_aggregate = aggregate;}public bool HasNext() => _index < _aggregate.Count;public object Next() => _aggregate[_index++];
}// 使用
var aggregate = new ConcreteAggregate();
var iterator = aggregate.CreateIterator();
while (iterator.HasNext())
{Console.WriteLine(iterator.Next()); // 输出 A, B, C
}

Java 实现示例

// 迭代器接口
public interface Iterator<T> {boolean hasNext();T next();
}// 聚合接口
public interface Iterable<T> {Iterator<T> createIterator();
}// 具体聚合类
public class ConcreteAggregate implements Iterable<String> {private String[] items = {"A", "B", "C"};@Overridepublic Iterator<String> createIterator() {return new ConcreteIterator();}private class ConcreteIterator implements Iterator<String> {private int index = 0;@Overridepublic boolean hasNext() {return index < items.length;}@Overridepublic String next() {return items[index++];}}
}// 使用
ConcreteAggregate aggregate = new ConcreteAggregate();
Iterator<String> iterator = aggregate.createIterator();
while (iterator.hasNext()) {System.out.println(iterator.next()); // 输出 A, B, C
}

常用场景

  1. 遍历复杂数据结构

    • 树形结构(二叉树、多叉树)
    • 图结构(DFS/BFS遍历器)
    • 自定义集合(如分页查询结果集)
  2. 解耦客户端与集合实现

    • 客户端仅依赖迭代器接口,不依赖具体集合类(如 List vs Set
    • 示例:统一遍历数据库查询结果与内存集合
  3. 延迟加载/流式处理

    • 大数据集分批加载(如数据库分页迭代器)
    • 流处理管道(如 Java Stream API 的迭代器实现)
  4. 多线程安全遍历

    • 提供快照迭代器(如 CopyOnWriteArrayList
    • 并发修改检测(Java 的 ConcurrentModificationException

注意事项

  1. 线程安全问题

    • 迭代过程中修改集合会导致未定义行为(如 Java 的 fail-fast 机制)
    • 解决方案:使用并发集合或克隆数据
  2. 资源泄漏风险

    • 迭代器持有集合引用可能导致内存泄漏
    • 特别在长生命周期迭代器(如缓存中)需注意
  3. 性能开销

    • 每步操作需状态检查(如 hasNext()
    • 复杂数据结构(如树)的迭代器实现可能低效
  4. 空迭代器处理

    • 空集合应返回有效的“空迭代器”,而非 null

架构设计建议

  1. 优先使用语言内置迭代器

    • C#:IEnumerable<T> + yield return
      public IEnumerable<int> GetValues() {for (int i = 0; i < 10; i++) {yield return i; // 自动生成迭代器}
      }
      
    • Java:实现 Iterable<T> + Lambda
      List<Integer> list = Arrays.asList(1, 2, 3);
      list.forEach(System.out::println); // 内部迭代
      
  2. 为自定义集合提供标准迭代器

    • 实现语言标准接口(如 Java 的 Iterable),方便与现有库集成
    • 示例:自定义树结构实现 Iterable<Node>
  3. 支持多种遍历策略

    • 通过工厂方法返回不同迭代器:
      public Iterator<T> createIterator(TraversalType type) {switch(type) {case IN_ORDER: return new InOrderIterator();case PRE_ORDER: return new PreOrderIterator();}
      }
      
  4. 防御性编程

    • 迭代器实现应检测并发修改:
      public class SafeIterator {private final int expectedModCount;public T next() {if (modCount != expectedModCount) throw new ConcurrentModificationException();// ...}
      }
      
  5. 避免暴露内部状态

    • 迭代器不应提供修改集合的方法(如 remove() 需谨慎设计)
    • 分离只读迭代器与读写迭代器接口

典型应用案例

  • 集合框架
    Java 的 ArrayList.iterator(), C# 的 List<T>.GetEnumerator()

  • 数据库访问
    ORM 框架的查询结果迭代(如 Entity Framework 的 IQueryable

  • 文件/网络流处理
    按行读取大文件:

    foreach (var line in File.ReadLines("large.txt")) {// 逐行处理,避免全量加载
    }
    
  • 组合模式树遍历
    递归遍历 UI 组件树:

    public class UIComponent implements Iterable<UIComponent> {private List<UIComponent> children = new ArrayList<>();public Iterator<UIComponent> iterator() {return new DepthFirstIterator(this);}
    }
    

总结

迭代器模式通过抽象遍历过程,实现了:

  1. 解耦:分离集合结构与遍历逻辑
  2. 扩展性:支持多种遍历方式且不修改聚合类
  3. 简洁性:统一使用 foreach 等语法糖

黄金法则:当你的集合需要提供遍历能力时,优先实现语言标准迭代协议(C# 的 IEnumerable/Java 的 Iterable),而非自定义接口。这能最大化兼容性和可维护性。
16. 中介者

中介者模式(Mediator Pattern)详解

中介者模式是一种行为设计模式,通过引入中介对象封装一组对象之间的交互,降低对象间的直接耦合。核心思想是 “对象间不直接通信,而是通过中介者转发请求”

模式结构
«interface»
Mediator
+Notify(sender: Colleague, event: string)
ConcreteMediator
-colleagues: List<Colleague>
+Register(colleague: Colleague)
+Notify(sender: Colleague, event: string)
Colleague
-mediator: Mediator
+SetMediator(mediator: Mediator)
ConcreteColleagueA
+DoOperation()
ConcreteColleagueB
+HandleEvent()

C# 示例:智能家居控制系统

// 中介者接口
public interface ISmartHomeMediator
{void Register(Device device);void Notify(Device sender, string eventType);
}// 具体中介者
public class HomeAutomationHub : ISmartHomeMediator
{private readonly List<Device> _devices = new();public void Register(Device device) => _devices.Add(device);public void Notify(Device sender, string eventType){foreach (var device in _devices.Where(d => d != sender)){device.HandleEvent(eventType);}}
}// 抽象同事类
public abstract class Device
{protected ISmartHomeMediator Mediator;public void SetMediator(ISmartHomeMediator mediator) => Mediator = mediator;public abstract void HandleEvent(string eventType);
}// 具体设备
public class Light : Device
{public override void HandleEvent(string eventType){if (eventType == "MOTION_DETECTED")Console.WriteLine("Light turns ON");else if (eventType == "NO_MOTION")Console.WriteLine("Light turns OFF");}
}public class SecurityCamera : Device
{public void DetectMotion() => Mediator.Notify(this, "MOTION_DETECTED");
}// 使用
var hub = new HomeAutomationHub();
var light = new Light();
var camera = new SecurityCamera();light.SetMediator(hub);
camera.SetMediator(hub);
hub.Register(light);
hub.Register(camera);camera.DetectMotion(); // 触发所有设备响应

Java 示例:航空交通管制系统

// 中介者接口
interface AirTrafficControl {void registerFlight(Flight flight);void sendWarning(Flight sender, String message);
}// 具体中介者
class ControlTower implements AirTrafficControl {private List<Flight> flights = new ArrayList<>();public void registerFlight(Flight flight) {flights.add(flight);}public void sendWarning(Flight sender, String message) {for (Flight flight : flights) {if (flight != sender) {flight.receiveWarning(message);}}}
}// 抽象同事类
abstract class Flight {protected AirTrafficControl atc;public void setATC(AirTrafficControl atc) {this.atc = atc;}public abstract void receiveWarning(String message);
}// 具体航班
class CargoFlight extends Flight {public void reportPosition() {atc.sendWarning(this, "CARGO_FLIGHT at 10,000m");}@Overridepublic void receiveWarning(String message) {System.out.println("Cargo flight received: " + message);}
}// 使用
ControlTower tower = new ControlTower();
CargoFlight flight1 = new CargoFlight();
CargoFlight flight2 = new CargoFlight();flight1.setATC(tower);
flight2.setATC(tower);
tower.registerFlight(flight1);
tower.registerFlight(flight2);flight1.reportPosition(); // 触发其他航班接收警告

常用应用场景

  1. GUI组件交互
    • 按钮/文本框/下拉菜单通过中介者协调(如:表单验证、状态联动)
  2. 分布式系统协调
    • 微服务通过消息中介(如RabbitMQ)解耦通信
  3. 游戏开发
    • 角色/道具/环境通过游戏主循环中介交互
  4. 工作流引擎
    • 审批节点通过流程引擎中介传递任务
  5. 聊天系统
    • 用户通过聊天室中介广播消息

注意事项与架构建议

⚠️ 注意事项
  1. 避免上帝对象
    • 中介者不应包含过多业务逻辑(违反单一职责原则)
  2. 性能考量
    • 高频通信场景需优化中介者转发效率
  3. 调试复杂性
    • 交互链路间接化增加调试难度
✅ 架构建议
  1. 分层中介者
    全局中介者
    模块中介者1
    模块中介者2
    组件A
    组件B
    组件C
  2. 与观察者模式结合
    • 用事件机制实现中介通知(INotifyPropertyChanged
  3. 接口隔离原则
    • 为不同组件定义专用中介接口
    public interface IDeviceMediator {void NotifyLightSensor();void NotifyThermostat();
    }
    
  4. DI容器集成
    • 通过依赖注入管理中介者生命周期(.NET Core/Spring)
  5. 有限使用场景
    • 仅在对象间存在复杂网状关系时使用

模式对比

模式特点适用场景
中介者集中控制多对象交互复杂组件网络
观察者一对多依赖关系事件通知系统
外观简化子系统访问接口复杂子系统封装

黄金法则:当系统出现"蜘蛛网式耦合"(对象间引用混乱)时,优先考虑中介者模式重构。

  1. 备忘录

备忘录模式(Memento Pattern)详解

模式定义

备忘录模式是一种行为设计模式,它允许在不破坏对象封装性的前提下捕获并外部化对象的内部状态,以便后续可将该对象恢复到先前的状态。核心目标是提供状态的快照机制回滚能力

核心角色
  1. Originator(发起人)

    • 需要保存状态的对象(如文档编辑器、游戏角色)
    • 提供创建备忘录(CreateMemento())和恢复状态(RestoreMemento())的方法
  2. Memento(备忘录)

    • 存储Originator内部状态的不可变对象(通常设计为只读)
    • 通过窄接口(如GetState())暴露状态,保护封装性
  3. Caretaker(管理者)

    • 负责存储和管理备忘录(如历史记录栈)
    • 无权修改或读取备忘录内容(符合迪米特法则)

常用场景示例

场景1:文档编辑器的撤销/重做(C#)
// Memento
public class DocumentMemento
{public string Content { get; } // 只读属性保护状态public DocumentMemento(string content) => Content = content;
}// Originator
public class Document
{public string Content { get; set; }public DocumentMemento CreateMemento() => new(Content);public void RestoreMemento(DocumentMemento memento) => Content = memento.Content;
}// Caretaker
public class HistoryTracker
{private readonly Stack<DocumentMemento> _history = new();public void SaveState(Document doc) => _history.Push(doc.CreateMemento());public void Undo(Document doc){if (_history.Count > 0) doc.RestoreMemento(_history.Pop());}
}// 使用
var doc = new Document();
var history = new HistoryTracker();doc.Content = "Version 1";
history.SaveState(doc);  // 保存状态doc.Content = "Version 2"; // 修改内容
history.Undo(doc);       // 撤销到Version 1
场景2:游戏角色状态存档(Java)
// Memento
public class PlayerMemento {private final int health;private final String position;public PlayerMemento(int health, String position) {this.health = health;this.position = position;}public int getHealth() { return health; }  // 只提供Getterpublic String getPosition() { return position; }
}// Originator
public class Player {private int health;private String position;public PlayerMemento save() {return new PlayerMemento(health, position);}public void load(PlayerMemento memento) {this.health = memento.getHealth();this.position = memento.getPosition();}
}// Caretaker
public class SaveManager {private Map<String, PlayerMemento> saves = new HashMap<>();public void saveGame(String slot, Player player) {saves.put(slot, player.save());}public void loadGame(String slot, Player player) {if (saves.containsKey(slot)) player.load(saves.get(slot));}
}

注意事项与架构建议

注意事项
  1. 内存消耗

    • 频繁保存大对象状态可能导致内存溢出(如高清图片编辑)
    • 解决方案:增量备份、压缩存储、限制历史记录数量
  2. 封装性保护

    • 备忘录必须严格限制状态访问(C#用internal修饰,Java用包级私有)
    • 禁止Caretaker直接修改备忘录内容
  3. 深拷贝问题

    • 对象包含引用类型时需深拷贝(如集合、嵌套对象)
    • 示例:DocumentMemento中的Content是字符串(不可变),无需深拷
  4. 生命周期管理

    • 长时间未使用的备忘录应及时清除(如LRU缓存策略)
架构建议
  1. 性能优化

    // 仅保存差异状态(增量备份)
    public class DiffMemento {public string ChangedText { get; }public int StartIndex { get; }// ... 其他差异元数据
    }
    
  2. 支持多级撤销

    // Caretaker中使用双栈实现
    Stack<Memento> undoStack = new Stack<>();
    Stack<Memento> redoStack = new Stack<>();
    
  3. 持久化扩展

    • 备忘录可序列化为JSON/二进制存储到数据库
    • 示例:
      public string SerializeMemento(DocumentMemento m) => JsonConvert.SerializeObject(m);
      
  4. 安全控制

    • 对备忘录加密(如游戏存档防篡改)
    • 添加版本号兼容旧版状态
  5. 结合其他模式

    • 命令模式:将备忘录绑定到命令对象实现事务操作
    • 原型模式:通过克隆生成备忘录减少开销

经典应用案例

领域应用实例
文本编辑器Word/VS Code的撤销栈
图形设计软件Photoshop历史记录
游戏开发角色状态存档/关卡进度保存
数据库系统事务回滚(Transaction Rollback)
版本控制系统Git的commit/checkout机制

黄金法则:当系统需要“时间机器”功能时优先考虑备忘录模式,但需警惕状态爆炸问题。建议通过[Serializable](C#)或Serializable接口(Java)支持跨进程状态恢复。

  1. 访问者

访问者模式详解

访问者模式(Visitor Pattern)是一种行为型设计模式,允许你将算法与操作的对象结构分离。它通过将操作逻辑移至独立的访问者类中,实现在不修改现有类结构的前提下添加新操作。

核心思想

  • 双重分派(Double Dispatch):通过组合方法调用实现运行时多态
  • 分离关注点:数据结构与数据操作解耦
  • 开放封闭原则:新增操作只需添加新的访问者,无需修改元素类

模式结构

accept调用visit
accept调用visit
«interface»
Visitor
+visitElementA(ElementA)
+visitElementB(ElementB)
ConcreteVisitor1
+visitElementA(ElementA)
+visitElementB(ElementB)
«interface»
Element
+accept(Visitor)
ElementA
+accept(Visitor)
+featureA()
ElementB
+accept(Visitor)
+featureB()

C# 实现示例

// 元素接口
public interface IElement
{void Accept(IVisitor visitor);
}// 具体元素A
public class ConcreteElementA : IElement
{public void FeatureA() => Console.WriteLine("Feature A");public void Accept(IVisitor visitor) => visitor.VisitElementA(this);
}// 具体元素B
public class ConcreteElementB : IElement
{public void FeatureB() => Console.WriteLine("Feature B");public void Accept(IVisitor visitor) => visitor.VisitElementB(this);
}// 访问者接口
public interface IVisitor
{void VisitElementA(ConcreteElementA element);void VisitElementB(ConcreteElementB element);
}// 具体访问者
public class ConcreteVisitor : IVisitor
{public void VisitElementA(ConcreteElementA element){Console.WriteLine("Visitor processing ElementA");element.FeatureA();}public void VisitElementB(ConcreteElementB element){Console.WriteLine("Visitor processing ElementB");element.FeatureB();}
}// 对象结构
public class ObjectStructure
{private readonly List<IElement> _elements = new();public void Attach(IElement element) => _elements.Add(element);public void Detach(IElement element) => _elements.Remove(element);public void Accept(IVisitor visitor){foreach (var element in _elements){element.Accept(visitor);}}
}

Java 实现示例

// 元素接口
interface Element {void accept(Visitor visitor);
}// 具体元素A
class ConcreteElementA implements Element {public void featureA() {System.out.println("Feature A");}@Overridepublic void accept(Visitor visitor) {visitor.visitElementA(this);}
}// 具体元素B
class ConcreteElementB implements Element {public void featureB() {System.out.println("Feature B");}@Overridepublic void accept(Visitor visitor) {visitor.visitElementB(this);}
}// 访问者接口
interface Visitor {void visitElementA(ConcreteElementA element);void visitElementB(ConcreteElementB element);
}// 具体访问者
class ConcreteVisitor implements Visitor {@Overridepublic void visitElementA(ConcreteElementA element) {System.out.println("Visitor processing ElementA");element.featureA();}@Overridepublic void visitElementB(ConcreteElementB element) {System.out.println("Visitor processing ElementB");element.featureB();}
}// 对象结构
class ObjectStructure {private final List<Element> elements = new ArrayList<>();public void attach(Element element) {elements.add(element);}public void detach(Element element) {elements.remove(element);}public void accept(Visitor visitor) {for (Element element : elements) {element.accept(visitor);}}
}

常用应用场景

  1. 复杂对象结构操作

    • 抽象语法树(AST)处理(编译器设计)
    • 文档对象模型(DOM)处理
    • UI组件树遍历
  2. 跨类层次的操作

    • 报表生成(不同业务对象生成不同格式报表)
    • 序列化/反序列化系统
    • 权限检查系统
  3. 分离关注点

    • 数据收集与统计(如电商订单各元素价格计算)
    • 多格式导出系统(XML/JSON/CSV)
    • 游戏实体行为处理(不同NPC类型的不同交互)
  4. 扩展框架功能

    • IDE插件系统
    • 工作流引擎扩展点
    • 规则引擎执行器

关键注意事项

  1. 元素稳定性要求

    • 适用场景:元素类结构稳定,但操作频繁变化
    • 不适用场景:元素类需要频繁添加新类型
  2. 封装性破坏风险

    • 访问者通常需要访问元素内部状态
    • 解决方案:
      • 提供受控访问接口
      • 使用友元关系(C++)
      • 包级私有访问(Java)
  3. 循环依赖问题

    • 元素和访问者相互引用
    • 解决方案:通过接口解耦,避免具体类依赖
  4. 遍历责任归属

    • 明确对象结构负责遍历还是访问者负责
    • 推荐:对象结构控制遍历顺序(如组合模式)

架构设计建议

  1. 访问者层次设计

    抽象访问者
    报表生成
    数据导出
    校验器
    PDFReportVisitor
    ExcelReportVisitor
  2. 与组合模式结合

    public class CompositeElement : IElement
    {private readonly List<IElement> _children = new();public void Add(IElement element) => _children.Add(element);public void Accept(IVisitor visitor){visitor.VisitComposite(this);foreach (var child in _children){child.Accept(visitor);}}
    }
    
  3. 访问者状态管理

    • 有状态访问者:适合数据聚合场景(如价格计算)
    • 无状态访问者:适合纯操作场景(如格式转换)
  4. 性能优化策略

    • 访问者缓存:复用访问者实例
    • 遍历优化:增量遍历大型结构
    • 并行处理:线程安全访问者
  5. 访问控制机制

    • 基于角色的访问控制:
    public class RoleBasedVisitor implements Visitor {private final UserRole role;public RoleBasedVisitor(UserRole role) {this.role = role;}@Overridepublic void visitElementA(ConcreteElementA element) {if(role.canAccess(element)) {// 执行操作}}
    }
    

最佳实践总结

  1. 适用场景判断

    • 当操作比元素类型更易变时优先选用
    • 当需要跨不相关类层次执行操作时使用
  2. 设计权衡

    • 优势:符合开闭原则,集中相关操作
    • 代价:增加系统复杂度,元素接口扩展困难
  3. 替代方案

    • 简单场景:考虑使用迭代器+策略模式组合
    • 功能扩展:AOP(面向切面编程)
  4. 架构集成

    • 框架设计:作为扩展点机制
    • 领域驱动设计:分离领域模型与技术实现

访问者模式在复杂业务系统中能显著提升架构的扩展性和可维护性,但需谨慎评估其对系统复杂度的增加。在编译器设计、复杂报表系统等场景中表现尤为出色,是系统架构师解决操作扩展问题的有力工具。
19. 模板方法

模板方法模式详解(系统架构师视角)

模式定义

模板方法模式是一种行为设计模式,它在抽象类中定义算法的骨架,将某些步骤延迟到子类实现。该模式通过固定算法结构确保核心流程不变,同时允许子类重写特定步骤的实现。

核心结构
// Java示例
abstract class AbstractClass {// 模板方法(final防止子类覆盖算法结构)public final void templateMethod() {step1();step2();  // 抽象步骤step3();if (hook()) {  // 钩子方法step4();}}// 固定步骤(可提供默认实现)private void step1() {System.out.println("固定步骤1");}// 抽象步骤(子类必须实现)protected abstract void step2();// 可选步骤(子类可覆盖)protected void step3() {System.out.println("默认步骤3");}// 钩子方法(控制流程扩展点)protected boolean hook() {return true;}
}
// C#示例
abstract class AbstractClass {public void TemplateMethod() {Step1();Step2();  // 抽象步骤Step3();if (Hook()) {  // 钩子方法Step4();}}private void Step1() => Console.WriteLine("固定步骤1");protected abstract void Step2();protected virtual void Step3() => Console.WriteLine("默认步骤3");protected virtual bool Hook() => true;
}
典型应用场景
  1. 框架扩展点设计

    • 场景:开发框架时固定核心流程(如Spring的事务管理、Servlet生命周期)
    • 示例:
      // Java Servlet
      public abstract class HttpServlet {protected void service(HttpServletRequest req, HttpServletResponse resp) {// 固定流程if (req.getMethod().equals("GET")) doGet(...);else if (req.getMethod().equals("POST")) doPost(...);}protected abstract void doGet(...); // 子类实现
      }
      
  2. 跨平台业务逻辑

    • 场景:多平台实现相同流程但细节不同(如支付流程:验证→执行→日志)
    • 示例:
      // C#支付处理
      abstract class PaymentProcessor {public void Process() {Validate();ExecutePayment(); // 平台相关实现LogResult();}protected abstract void ExecutePayment();
      }
      
  3. 算法扩展

    • 场景:算法结构固定但部分步骤可变(如数据解析:读数据→解析→输出)
    • 示例:Java集合框架的AbstractList定义骨架方法,子类实现get()
  4. 生命周期管理

    • 场景:对象创建/初始化的固定流程(如游戏角色生成:加载资源→初始化状态→注册事件)
      abstract class GameCharacter {public final void init() {loadModel();initAI();  // 子类自定义AI逻辑registerEvents();}protected abstract void initAI();
      }
      
架构注意事项
  1. 流程控制

    • 保护模板方法:用final(Java)/sealed(C#)修饰模板方法防止子类破坏结构
    • ⚠️ 避免过度拆分:抽象步骤不宜过多(通常3-5个),否则增加子类实现负担
  2. 扩展性设计

    • 钩子方法:提供带默认实现的虚方法(如hook()),允许子类影响主流程
    • 好莱坞原则:“Don’t call us, we’ll call you” – 子类不应直接调用父类
  3. 继承风险

    • 里氏替换原则:子类扩展时不得改变父类既定行为
    • ⚠️ 组合替代:若存在多重变化维度,考虑结合策略模式
架构最佳实践
  1. 层次化抽象

    AbstractClass
    +templateMethod()
    +step2()
    ConcreteClassA
    +step2()
    ConcreteClassB
    +step2()
  2. 文档规范

    • 明确标注抽象方法的契约(前置/后置条件)
    • 示例:Java注释
      /*** 实现支付执行逻辑(必须保证幂等性)* @throws PaymentException 超过重试次数时抛出*/
      protected abstract void executePayment();
      
  3. 防御式编程

    • 在模板方法中添加关键检查:
      public void TemplateMethod() {if (!IsValidState()) throw new InvalidOperationException();// ...继续流程
      }
      
  4. 与其它模式协作

    • 工厂方法模式:在模板方法中调用工厂方法创建对象
    • 策略模式:将可变步骤委托给策略接口,避免继承膨胀
反模式警示
  1. 流程碎片化
    ❌ 错误:将算法拆分成过多细碎步骤
    ✅ 改进:合并相关步骤,保持高内聚

  2. 子类耦合父类
    ❌ 错误:子类方法直接调用父类具体方法
    ✅ 改进:通过抽象方法隔离依赖

  3. 过度使用继承

    graph LRA[模板方法模式] --> B{是否需要支持运行时变更行为?}B -->|是| C[改用策略模式]B -->|否| D[继续使用模板方法]
    
性能考量
  • 虚方法调用成本:在高性能场景(如金融交易),避免深层继承树
  • 解决方案:C#使用sealed修饰叶子子类,Java启用JIT内联优化

架构师决策点:当系统需要 强制统一流程 且存在 可扩展步骤 时优先选用模板方法模式,在框架设计和跨平台实现中尤为有效。同时需警惕"继承地狱",必要时结合组合模式优化结构。

  1. 解释器

解释器模式详解

模式定义

解释器模式(Interpreter Pattern) 是一种行为设计模式,用于定义语言的文法规则,并构建解释器来解释语言中的表达式。它将语法解析分解为多个小类,通过组合这些类实现语法解释功能。

核心组件
组件说明
AbstractExpression抽象表达式接口,声明解释操作(如 Interpret()
TerminalExpression终结符表达式,实现与文法中终结符相关的解释(如变量、常量)
NonterminalExpression非终结符表达式,通过组合子表达式解释复杂语法(如运算符、逻辑规则)
Context全局上下文信息(如变量存储、函数表)
Client构建语法树并触发解释操作

C# / Java 代码实现

场景示例:SQL WHERE 条件解析

假设需要解析类似 "Age > 25 AND Country = 'USA'" 的条件表达式。

C# 实现
// 抽象表达式
public interface IExpression {bool Interpret(Dictionary<string, object> context);
}// 终结符表达式:变量
public class VariableExpression : IExpression {private string _key;public VariableExpression(string key) => _key = key;public bool Interpret(Dictionary<string, object> context) => context.ContainsKey(_key);
}// 终结符表达式:常量
public class ConstantExpression : IExpression {private object _value;public ConstantExpression(object value) => _value = value;public bool Interpret(Dictionary<string, object> context) => _value != null;
}// 非终结符表达式:等于操作
public class EqualsExpression : IExpression {private IExpression _left, _right;public EqualsExpression(IExpression left, IExpression right) => (_left, _right) = (left, right);public bool Interpret(Dictionary<string, object> context) {dynamic leftVal = context[(_left as VariableExpression)?._key ?? ""];dynamic rightVal = (_right as ConstantExpression)?._value;return leftVal == rightVal;}
}// 非终结符表达式:AND 操作
public class AndExpression : IExpression {private IExpression _expr1, _expr2;public AndExpression(IExpression expr1, IExpression expr2) => (_expr1, _expr2) = (expr1, expr2);public bool Interpret(Dictionary<string, object> context) => _expr1.Interpret(context) && _expr2.Interpret(context);
}// 客户端调用
var context = new Dictionary<string, object> {{ "Age", 30 }, { "Country", "USA" }
};var expr = new AndExpression(new GreaterThanExpression(new VariableExpression("Age"),new ConstantExpression(25)),new EqualsExpression(new VariableExpression("Country"),new ConstantExpression("USA"))
);Console.WriteLine(expr.Interpret(context)); // 输出: True
Java 实现
// 抽象表达式
interface Expression {boolean interpret(Map<String, Object> context);
}// 终结符:变量
class VariableExpression implements Expression {private String key;public VariableExpression(String key) { this.key = key; }public boolean interpret(Map<String, Object> context) {return context.containsKey(key);}
}// 终结符:常量
class ConstantExpression implements Expression {private Object value;public ConstantExpression(Object value) { this.value = value; }public boolean interpret(Map<String, Object> context) {return value != null;}
}// 非终结符:等于操作
class EqualsExpression implements Expression {private Expression left, right;public EqualsExpression(Expression left, Expression right) {this.left = left;this.right = right;}public boolean interpret(Map<String, Object> context) {Object leftVal = context.get(((VariableExpression) left).key);Object rightVal = ((ConstantExpression) right).value;return leftVal.equals(rightVal);}
}// 客户端
Map<String, Object> context = new HashMap<>();
context.put("Age", 30);
context.put("Country", "USA");Expression expr = new AndExpression(new GreaterThanExpression(new VariableExpression("Age"),new ConstantExpression(25)),new EqualsExpression(new VariableExpression("Country"),new ConstantExpression("USA"))
);System.out.println(expr.interpret(context)); // 输出: true

常用应用场景

  1. 领域特定语言(DSL)
    • 规则引擎(如Drools)
    • 业务规则配置(如折扣规则、风控规则)
  2. 语法解析
    • SQL WHERE 条件解析
    • 数学公式计算器
  3. 配置文件解析
    • 自定义格式的配置规则
    • 游戏脚本系统
  4. 正则表达式引擎
    • 模式匹配解释器

注意事项与架构建议

⚠️ 注意事项
  1. 性能问题
    • 深层嵌套语法树会降低性能(考虑缓存解释结果)
    • 避免在性能敏感场景使用(如高频交易)
  2. 文法复杂度
    • 仅适合简单文法(BNF范式可描述)
    • 复杂文法需用解析器生成器(如ANTLR)
  3. 维护成本
    • 每增加一条规则需新增类
    • 过度使用会导致类膨胀
🏗️ 架构建议
  1. 结合组合模式
    • 用树形结构组织表达式(如 CompositeExpression
  2. 分离解析与执行
    • 使用单独解析器构建语法树
    • 解释器仅负责执行
  3. 上下文优化
    • 线程安全的上下文设计
    • 预编译常用表达式(如预计算常量)
  4. 扩展性设计
    // 通过装饰器增加新功能
    public class CachedExpression : IExpression {private IExpression _expr;private bool? _lastResult;public bool Interpret(Dictionary<string, object> context) {return _lastResult ??= _expr.Interpret(context);}
    }
    
  5. 替代方案
    • 复杂场景用访问者模式遍历语法树
    • 考虑现成工具(如Roslyn、Eclipse JDT)

总结

适用场景

  • 需要灵活扩展语法规则
  • 文法简单且执行频率不高
  • 避免重复解析相同逻辑(如模板引擎)

规避场景

  • 高性能需求系统
  • 文法规则频繁变化
  • 复杂语法(如完整编程语言)

通过合理设计,解释器模式能高效解决特定领域语言解析问题,但需警惕其潜在复杂性和性能瓶颈。在实际架构中,优先评估是否可用现成解析库替代自定义实现。
21. 享元

享元模式(Flyweight Pattern)详解

模式定义

享元模式是一种结构型设计模式,通过共享大量细粒度对象来减少内存占用和提高性能。核心思想是将对象状态分为:

  • 内部状态(Intrinsic):可共享的、不变的部分(如字符编码)
  • 外部状态(Extrinsic):不可共享的、变化的部分(如位置坐标)
模式结构
创建/管理
请求
设置外部状态
FlyweightFactory
-flyweights: Map
+GetFlyweight(key)
Flyweight
+Operation(extrinsicState)
ConcreteFlyweight
-intrinsicState
+Operation(extrinsicState)
UnsharedFlyweight
-allState
+Operation(extrinsicState)
Client
-extrinsicState
C# 实现示例
// 抽象享元
public interface ITextCharacter {void Display(int position);
}// 具体享元(包含内部状态)
public class Character : ITextCharacter {private readonly char _symbol; // 内部状态public Character(char symbol) => _symbol = symbol;public void Display(int position) => Console.WriteLine($"Symbol: {_symbol}, Position: {position}");
}// 享元工厂
public class CharacterFactory {private readonly Dictionary<char, ITextCharacter> _characters = new();public ITextCharacter GetCharacter(char key) {if (!_characters.TryGetValue(key, out var character)) {character = new Character(key);_characters.Add(key, character);}return character;}
}// 客户端
var factory = new CharacterFactory();
var charA = factory.GetCharacter('A');
charA.Display(10); // 外部状态:位置
Java 实现示例
// 抽象享元
interface TextCharacter {void display(int position);
}// 具体享元
class Character implements TextCharacter {private final char symbol; // 内部状态public Character(char symbol) { this.symbol = symbol; }@Overridepublic void display(int position) {System.out.println("Symbol: " + symbol + ", Position: " + position);}
}// 享元工厂
class CharacterFactory {private final Map<Character, TextCharacter> pool = new HashMap<>();public TextCharacter getCharacter(char key) {return pool.computeIfAbsent(key, Character::new);}
}// 客户端
CharacterFactory factory = new CharacterFactory();
TextCharacter charA = factory.getCharacter('A');
charA.display(10);

常用场景

  1. 文本编辑器

    • 共享字符对象(内部状态:字体、大小)
    • 外部状态:位置、颜色
  2. 游戏开发

    • 共享粒子/树木/武器对象(内部状态:纹理、模型)
    • 外部状态:位置、旋转角度
  3. 图形处理

    • 共享图形对象(内部状态:形状类型)
    • 外部状态:坐标、缩放比例
  4. 数据库连接池

    • 共享连接对象(内部状态:配置)
    • 外部状态:会话状态
  5. UI组件库

    • 共享按钮/图标(内部状态:样式)
    • 外部状态:位置、点击事件

注意事项

  1. 线程安全问题

    • 共享对象需设计为不可变(Immutable)
    • 使用线程安全容器(如 ConcurrentDictionary
  2. 外部状态管理

    • 客户端负责维护外部状态
    • 避免外部状态污染内部状态
  3. 性能权衡

    • 对象共享会引入查找开销(工厂模式)
    • 适用于对象创建成本高且数量大的场景
  4. 内存泄漏风险

    • 长期持有未使用的享元对象
    • 解决方案:弱引用(WeakReference)或定期清理

架构建议

  1. 结合工厂模式

    • 强制通过工厂获取对象,确保共享机制
  2. 与组合模式结合

    • 处理树形结构时,共享叶子节点
    // 组合模式示例
    public class TreeNode : IComponent {private readonly ITextCharacter _character;private readonly List<IComponent> _children = new();public void Add(IComponent comp) => _children.Add(comp);public void Render(int x) {_character.Display(x);foreach (var child in _children) child.Render(x + 10);}
    }
    
  3. 外部状态存储优化

    • 使用轻量结构存储外部状态(如元组、结构体)
    • 避免外部状态包含大对象
  4. 性能监控

    • 跟踪享元对象命中率(Hit Rate)
    • 当命中率<70%时,考虑是否滥用模式
  5. 区分共享边界

    • 明确划分线程级共享/进程级共享
    • 分布式场景使用享元代理(Flyweight Proxy)

经典案例:游戏地图渲染

// 地形类型(内部状态)
enum TerrainType { FOREST, MOUNTAIN, WATER }// 享元对象
class Terrain {private final TerrainType type;private final String texture; // 大纹理数据(共享)public Terrain(TerrainType type, String texture) { ... }public void render(int x, int y) {// 使用外部状态(x,y)渲染}
}// 客户端使用
Terrain forest = factory.getTerrain(TerrainType.FOREST);
for (int i=0; i<1000; i++) {forest.render(randomX(), randomY()); // 外部状态
}

节省效果:1,000,000个地形成分 → 仅需3个享元对象


反模式警示

  1. 强行共享

    • 对象差异过大时,维护成本高于内存节省
  2. 忽略外部状态成本

    • 频繁计算外部状态导致CPU开销剧增
  3. 过度设计

    • 小规模对象池(<1000实例)无需享元模式

性能优化技巧

  1. 懒加载 + 预加载结合

    public class OptimizedFactory {private ConcurrentDictionary<char, Lazy<ITextCharacter>> _pool = new ConcurrentDictionary<>();public ITextCharacter GetChar(char key) {return _pool.GetOrAdd(key, k => new Lazy<ITextCharacter>(() => new Character(k))).Value;}
    }
    
  2. 使用值对象(Value Object)

    • C# 中 readonly struct / Java 中 record
    • 确保内部状态不可变
  3. 分级存储策略

    强引用
    弱引用
    序列化
    高频对象
    内存缓存
    低频对象
    二级缓存
    历史对象
    磁盘存储

总结

适用场景:存在大量重复对象、对象状态可分拆、内存压力显著
规避场景:对象差异性大、外部状态维护成本高、系统规模小
最佳实践

  • 严格区分内部/外部状态
  • 工厂类添加内存监控钩子
  • 与对象池模式结合处理非共享对象
  • 在游戏引擎、文档处理器等重资源场景优先采用
  1. 代理

代理模式详解

核心概念

代理模式是一种结构型设计模式,通过创建代理对象控制对目标对象的访问。代理在客户端和目标对象之间充当中介,提供额外的逻辑层(如访问控制、延迟加载、日志记录等),遵循开闭原则

三种角色
  1. Subject(抽象主题)
    定义目标对象和代理的公共接口
  2. RealSubject(真实主题)
    实际执行业务逻辑的目标对象
  3. Proxy(代理)
    持有真实主题的引用,控制访问并添加增强功能

应用场景与代码示例

1. 虚拟代理(延迟加载)

场景:初始化开销大的对象(如图片/文件加载)

// C# 示例
public interface IImage { void Display(); }public class HighResImage : IImage {public HighResImage(string path) => LoadImage(path); // 高开销操作public void Display() => Console.WriteLine("显示高清图片");
}public class ImageProxy : IImage {private string _path;private HighResImage _realImage;public void Display() {_realImage ??= new HighResImage(_path); // 延迟初始化_realImage.Display();}
}
// Java 示例
interface Image { void display(); }class RealImage implements Image {public RealImage(String path) { loadFromDisk(path); }public void display() { System.out.println("显示图片"); }
}class ProxyImage implements Image {private String path;private RealImage realImage;@Overridepublic void display() {if (realImage == null) realImage = new RealImage(path);realImage.display();}
}
2. 保护代理(访问控制)

场景:敏感操作权限验证

// C# 示例
public interface IDatabase { void Query(string sql); }public class RealDatabase : IDatabase {public void Query(string sql) => Console.WriteLine($"执行: {sql}");
}public class AuthProxy : IDatabase {private RealDatabase _db = new();private string _userRole;public void Query(string sql) {if (_userRole == "Admin") _db.Query(sql);else throw new UnauthorizedAccessException("权限不足");}
}
3. 远程代理(网络通信)

场景:分布式系统跨进程调用(Java RMI 示例)

// Java RMI 接口
public interface RemoteService extends Remote {String process() throws RemoteException;
}// 客户端调用
Registry registry = LocateRegistry.getRegistry("host", 1099);
RemoteService service = (RemoteService) registry.lookup("ServiceName");
service.process(); // 代理处理网络通信
4. 日志记录代理

场景:审计关键操作

// C# 日志代理
public class LoggingProxy : IDatabase {private IDatabase _target;public void Query(string sql) {Log($"执行SQL: {sql} 时间: {DateTime.Now}");_target.Query(sql);}
}

架构建议与注意事项

最佳实践
  1. 接口一致性原则

    实现
    实现
    Client
    Subject
    RealSubject
    Proxy

    确保代理与真实主题实现相同接口

  2. 动态代理优先

    • Java: 使用 java.lang.reflect.Proxy
    • C#: 使用 DispatchProxy 或第三方库(如 Castle DynamicProxy)
    // Java 动态代理示例
    InvocationHandler handler = (proxy, method, args) -> {System.out.println("前置处理");return method.invoke(target, args);
    };
    Subject proxy = (Subject) Proxy.newProxyInstance(loader, new Class[]{Subject.class}, handler);
    
  3. 代理链组合
    通过责任链模式组合多个代理:

    客户端 -> [日志代理] -> [缓存代理] -> [真实对象]
    
注意事项
  1. 性能影响

    • 避免多层嵌套代理(特别是远程代理)
    • 高频调用场景慎用
  2. 初始化陷阱
    虚拟代理需注意线程安全问题:

    // C# 线程安全延迟初始化
    private Lazy<RealSubject> _subject = new Lazy<RealSubject>(() => new RealSubject(), LazyThreadSafetyMode.ExecutionAndPublication);
    
  3. 循环依赖
    代理与真实对象避免相互引用

  4. 异常处理
    远程代理需处理网络异常:

    try {remoteService.process();
    } catch (RemoteException e) {logger.error("网络调用失败", e);
    }
    
典型应用框架
框架代理类型作用
Spring AOPJDK动态代理切面编程
Entity Framework延迟加载代理按需加载关联数据
WCF服务代理远程服务调用
Hibernate字节码增强属性延迟加载

总结

代理模式适用场景

  • 需要控制对象访问(权限/生命周期)
  • 添加与核心逻辑无关的横切关注点(日志/监控)
  • 优化资源使用(延迟加载/缓存)
  • 简化复杂系统访问(远程调用)

替代方案

  • 装饰器模式:侧重功能增强而非访问控制
  • 外观模式:封装子系统接口,不控制单个对象

模式选择速查表

问题类型推荐模式
全局访问点单例模式
灵活创建对象工厂方法/抽象工厂
分步构建复杂对象建造者模式
接口不兼容适配器模式
多维度扩展桥接模式
树形结构处理组合模式
动态添加功能装饰器模式
简化复杂系统外观模式
状态驱动行为状态模式
算法自由切换策略模式
事件通知机制观察者模式
操作封装命令模式

黄金法则

  1. 优先组合而非继承
  2. 面向接口编程
  3. 高内聚低耦合
  4. 对修改关闭,对扩展开放(开闭原则)

实际案例:电商系统典型模式组合

  • 支付模块:策略模式+工厂方法
  • 订单管理:状态模式+观察者模式
  • 商品展示:装饰器模式(价格修饰)
  • 权限控制:代理模式
  • 日志系统:责任链模式+适配器模式
http://www.dtcms.com/a/323111.html

相关文章:

  • [Linux]学习笔记系列 -- [arm][lds]
  • qt文件操作与qss基础
  • 3.5.2_1 随机访问介质访问控制
  • Docker容器部署Tomcat线上商城
  • 组件通信的方式
  • AI编程工具 | Trae介绍
  • [SC]高效地调试SystemC模型中的语法错误
  • 如何用OpenAI SDK调用Ollama LLM
  • 智慧养老场景跌倒检测准确率↑32%:陌讯多模态融合算法实战解析
  • GPT-5深度解析:革命性AI模型的全面报告与实战指南
  • windows10 ubuntu 24.04 双系统 安装教程
  • ubuntu dpkg命令使用指南
  • 【排序算法】②希尔排序
  • Delphi:TList/TObjectList 设计中的 Notify 设计范式
  • Day38--动态规划--322. 零钱兑换,279. 完全平方数,139. 单词拆分,56. 携带矿石资源(卡码网),背包问题总结
  • 10 分钟用 FastAPI 将机器学习模型上线为 REST API
  • day28 IPC通信机制
  • C++隐式转换的魔法与陷阱:explicit关键字的救赎
  • RecyclerView 缓存机制
  • centos 怎么将一些命令设置为快捷命令
  • 2025华数杯数学建模C题:可调控生物节律LED光源全解析
  • LLM表征的提取方式
  • 【Python 高频 API 速学 ⑥】
  • 【Mac】MLX:Lora微调工作流
  • 【排序算法】①直接插入排序
  • QT第二讲-信号和槽
  • uniapp实现的圆形滚盘组件模板
  • ThingsBoard配置邮件发送保姆级教程(新版qq邮箱)
  • SkyWalking-2--Java Agent是什么?
  • Qt与嵌入式设备中的字节序问题