概述
行为型设计模式(Behavioral Patterns)是软件工程中专注于对象间职责分配与算法封装的核心方法论,其核心价值在于通过灵活的交互机制解耦对象行为,提升系统的可扩展性与可维护性。在Rust语言环境下,这一模式体系被赋予了独特的技术内涵——通过trait抽象、闭包捕获、枚举状态机与零成本泛型,行为型模式不仅保留了传统设计模式的解耦能力,更实现了编译期类型安全与运行时性能的完美平衡。
Rust行为型模式的核心优势:相较于传统面向对象语言中依赖继承导致的脆弱基类问题(如Java的策略类层次膨胀)和运行时多态开销(如C++的虚函数表查找),Rust通过trait组合实现行为复用,结合枚举与模式匹配处理状态流转,利用闭包与函数指针实现轻量级策略注入,从根本上重构了对象行为协作的表达边界。
本文聚焦七种经典行为型模式在Rust中的实现与演化:策略模式通过trait或函数指针实现算法替换;观察者模式利用回调闭包与通道实现事件驱动;状态模式借助枚举与模式匹配构建类型安全状态机;命令模式通过trait封装请求实现撤销/重做;责任链模式利用Option链式调用实现请求过滤;模板方法模式通过trait默认方法定义算法骨架;访问者模式结合双重分发实现操作与数据结构解耦。这些模式共同构成了Rust生态下行为协作的完整解决方案,为复杂业务逻辑开发提供了兼顾灵活性与安全性的工程实践范式。
核心概念
什么是行为型模式?
- 策略模式:定义一系列算法,封装每个算法并使它们可互换,让算法的变化独立于使用它的客户
- 观察者模式:定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都会收到通知
- 状态模式:允许对象在内部状态改变时改变其行为,对象看起来像是修改了它的类
- 命令模式:将请求封装为对象,从而支持参数化、队列化、日志化请求,以及可撤销操作
- 责任链模式:使多个对象都有机会处理请求,从而避免请求发送者与接收者之间的耦合
- 模板方法模式:定义算法骨架,将具体步骤延迟到子类实现,复用不变部分
- 访问者模式:在不修改数据结构的前提下,定义作用于元素的新操作
为什么需要行为型模式?
Rust的组合优先原则与类型系统默认提供了强大的行为抽象能力,但在某些复杂场景中,直接实现会导致代码耦合或扩展困难:
- 算法替换需求:需要在运行时动态切换业务逻辑而不修改调用方
- 事件驱动架构:需要实现松耦合的发布-订阅机制支持异步通知
- 状态机管理:需要类型安全地表达复杂状态流转,避免非法状态组合
- 请求封装需求:需要将操作参数化、队列化,支持事务/撤销/日志
- 处理流程编排:需要灵活组合多个处理器,支持动态过滤与短路
- 算法骨架复用:需要定义通用流程,允许子类定制特定步骤
- 操作与数据解耦:需要为稳定数据结构添加新操作而不修改源码
策略模式详解
定义与作用
策略模式(Strategy Pattern)是一种行为型设计模式,其核心定义是”定义一系列算法,封装每个算法并使它们可互换,让算法的变化独立于使用它的客户”。在Rust语境下,这一模式通过trait抽象、函数指针与闭包三种方式实现,分别适用于不同场景的类型安全与性能需求。
// 方式1: Trait抽象(适合复杂策略)
pub trait SortStrategy {
fn sort(&self, data: &mut [i32]);
}
pub struct QuickSort;
impl SortStrategy for QuickSort {
fn sort(&self, data: &mut [i32]) {
// 快速排序实现
data.sort(); // 简化
}
}
pub struct Context {
strategy: Box<dyn SortStrategy>,
}
impl Context {
pub fn new(strategy: Box<dyn SortStrategy>) -> Self {
Context { strategy }
}
pub fn execute(&mut self, data: &mut [i32]) {
self.strategy.sort(data);
}
}
Rust策略模式的三种实现方式
1. Trait对象策略(动态分发)
适合策略逻辑复杂、需要运行时切换的场景:
pub trait PaymentStrategy {
fn pay(&self, amount: f64) -> Result<String, PaymentError>;
}
pub struct PaymentContext {
strategy: Box<dyn PaymentStrategy>,
}
impl PaymentContext {
pub fn set_strategy(&mut self, strategy: Box<dyn PaymentStrategy>) {
self.strategy = strategy;
}
}
优势:运行时灵活切换,支持插件扩展 劣势:动态分发有~1-2纳秒开销,需要堆分配
2. 泛型策略(静态分发)
适合策略固定、追求零开销的场景:
pub trait SortStrategy {
fn sort(data: &mut [i32]);
}
pub struct Context<S: SortStrategy> {
_phantom: std::marker::PhantomData<S>,
}
impl<S: SortStrategy> Context<S> {
pub fn execute(data: &mut [i32]) {
S::sort(data);
}
}
优势:编译期确定类型,零运行时开销,可内联优化 劣势:策略需在编译期确定,灵活性较低
3. 函数指针/闭包策略(轻量级)
适合简单策略、追求极简实现的场景:
pub type FilterFn = fn(&i32) -> bool;
pub struct DataProcessor {
filter: FilterFn,
}
impl DataProcessor {
pub fn new(filter: FilterFn) -> Self {
DataProcessor { filter }
}
pub fn process(&self, data: &[i32]) -> Vec<i32> {
data.iter().filter(|&x| (self.filter)(x)).copied().collect()
}
}
// 使用闭包
let processor = DataProcessor::new(|x| x > 0);
优势:实现极简,无额外类型定义,闭包可捕获环境变量 劣势:复杂策略难以管理,类型信息较弱
代码示例
电商折扣策略系统
// ========== 策略trait定义 ==========
pub trait DiscountStrategy {
fn calculate(&self, original_price: f64) -> f64;
fn description(&self) -> &str;
}
// ========== 具体策略实现 ==========
pub struct NoDiscount;
impl DiscountStrategy for NoDiscount {
fn calculate(&self, price: f64) -> f64 { price }
fn description(&self) -> &str { "无折扣" }
}
pub struct PercentageDiscount {
pub percent: f64, // 0.0 ~ 1.0
}
impl DiscountStrategy for PercentageDiscount {
fn calculate(&self, price: f64) -> f64 {
price * (1.0 - self.percent)
}
fn description(&self) -> &str { "百分比折扣" }
}
pub struct FixedDiscount {
pub amount: f64,
}
impl DiscountStrategy for FixedDiscount {
fn calculate(&self, price: f64) -> f64 {
(price - self.amount).max(0.0)
}
fn description(&self) -> &str { "固定金额折扣" }
}
pub struct VIPDiscount;
impl DiscountStrategy for VIPDiscount {
fn calculate(&self, price: f64) -> f64 {
// VIP:满100减20,再打9折
if price >= 100.0 {
(price - 20.0) * 0.9
} else {
price * 0.95
}
}
fn description(&self) -> &str { "VIP专享折扣" }
}
// ========== 上下文:订单 ==========
pub struct Order {
pub items: Vec<OrderItem>,
pub strategy: Box<dyn DiscountStrategy>,
}
pub struct OrderItem {
pub name: String,
pub price: f64,
pub quantity: u32,
}
impl Order {
pub fn new(strategy: Box<dyn DiscountStrategy>) -> Self {
Order {
items: Vec::new(),
strategy,
}
}
pub fn add_item(&mut self, item: OrderItem) {
self.items.push(item);
}
pub fn total(&self) -> f64 {
let original: f64 = self.items.iter()
.map(|item| item.price * item.quantity as f64)
.sum();
self.strategy.calculate(original)
}
pub fn set_strategy(&mut self, strategy: Box<dyn DiscountStrategy>) {
self.strategy = strategy;
}
}
// ========== 使用示例 ==========
fn main() {
let mut order = Order::new(Box::new(NoDiscount));
order.add_item(OrderItem {
name: "Rust Book".to_string(),
price: 89.0,
quantity: 2,
});
println!("原价: ¥{:.2}", order.total());
// 运行时切换策略
order.set_strategy(Box::new(PercentageDiscount { percent: 0.1 }));
println!("9折后: ¥{:.2}", order.total());
order.set_strategy(Box::new(VIPDiscount));
println!("VIP价: ¥{:.2}", order.total());
println!("策略: {}", order.strategy.description());
}
应用场景
- 支付渠道选择:支付宝/微信/信用卡等支付策略动态切换
- 数据压缩算法:gzip/zstd/brotli等压缩策略按需选择
- 缓存淘汰策略:LRU/LFU/TTL等策略配置化
- 日志输出格式:JSON/Plain/Structured等格式策略
Rust优势:通过trait对象支持运行时策略切换,通过泛型支持编译期零开销策略,通过闭包实现轻量级策略注入,满足不同场景的性能与灵活性需求。
观察者模式详解
定义与作用
观察者模式(Observer Pattern)是一种行为型设计模式,其核心定义是”定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都会自动收到通知并更新”。在Rust语境下,这一模式通过回调闭包、通道(Channel)与trait对象实现,分别适用于同步通知、异步事件流与多态订阅场景。
// 方式1: 闭包回调(简单同步)
pub struct Subject {
observers: Vec<Box<dyn Fn(&str)>>,
}
impl Subject {
pub fn subscribe<F>(&mut self, callback: F)
where F: Fn(&str) + 'static {
self.observers.push(Box::new(callback));
}
pub fn notify(&self, message: &str) {
for observer in &self.observers {
observer(message);
}
}
}
Rust观察者模式的三种实现方式
1. 闭包回调(同步通知)
适合简单场景、同步执行、无并发需求:
pub trait Observer {
fn update(&self, event: &Event);
}
pub struct Subject {
observers: Vec<Box<dyn Observer>>,
}
优势:实现简单,类型安全,易于调试 劣势:同步阻塞,不适合耗时操作
2. 通道+线程(异步事件流)
适合跨线程通知、异步处理、高并发场景:
use std::sync::mpsc::{channel, Sender};
pub struct EventBus {
senders: Vec<Sender<Event>>,
}
impl EventBus {
pub fn subscribe(&mut self) -> Receiver<Event> {
let (tx, rx) = channel();
self.senders.push(tx);
rx
}
pub fn publish(&self, event: Event) {
for tx in &self.senders {
let _ = tx.send(event.clone());
}
}
}
优势:支持跨线程异步通知,解耦生产消费 劣势:需要处理通道错误,内存开销略高
3. Arc+Mutex共享状态(多线程安全)
适合需要共享状态、多线程读写场景:
use std::sync::{Arc, Mutex};
pub struct SharedState {
observers: Arc<Mutex<Vec<Box<dyn Fn(&State) + Send>>>>,
}
impl SharedState {
pub fn notify(&self, state: &State) {
let observers = self.observers.lock().unwrap();
for observer in observers.iter() {
observer(state);
}
}
}
优势:线程安全,状态共享灵活 劣势:锁竞争可能影响性能
代码示例
股票价格通知系统
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
// ========== 事件定义 ==========
#[derive(Clone, Debug)]
pub struct StockEvent {
pub symbol: String,
pub price: f64,
pub change: f64,
pub timestamp: u64,
}
// ========== 观察者trait ==========
pub trait StockObserver: Send {
fn on_price_update(&self, event: &StockEvent);
fn id(&self) -> &str;
}
// ========== 具体观察者实现 ==========
pub struct EmailNotifier {
pub id: String,
pub email: String,
}
impl StockObserver for EmailNotifier {
fn on_price_update(&self, event: &StockEvent) {
println!("[Email] To: {} | {} price: ${:.2} ({:+.2}%)",
self.email, event.symbol, event.price, event.change);
}
fn id(&self) -> &str { &self.id }
}
pub struct SMSNotifier {
pub id: String,
pub phone: String,
}
impl StockObserver for SMSNotifier {
fn on_price_update(&self, event: &StockEvent) {
println!("[SMS] To: {} | {} ${:.2}",
self.phone, event.symbol, event.price);
}
fn id(&self) -> &str { &self.id }
}
pub struct Dashboard {
pub id: String,
pub prices: Mutex<HashMap<String, f64>>,
}
impl StockObserver for Dashboard {
fn on_price_update(&self, event: &StockEvent) {
let mut prices = self.prices.lock().unwrap();
prices.insert(event.symbol.clone(), event.price);
println!("[Dashboard] Updated {}: ${:.2}", event.symbol, event.price);
}
fn id(&self) -> &str { &self.id }
}
// ========== 主题:股票行情 ==========
pub struct StockTicker {
pub symbol: String,
observers: Vec<Box<dyn StockObserver>>,
}
impl StockTicker {
pub fn new(symbol: &str) -> Self {
StockTicker {
symbol: symbol.to_string(),
observers: Vec::new(),
}
}
pub fn attach(&mut self, observer: Box<dyn StockObserver>) {
self.observers.push(observer);
}
pub fn detach(&mut self, observer_id: &str) {
self.observers.retain(|obs| obs.id() != observer_id);
}
pub fn update_price(&self, price: f64, change: f64) {
let event = StockEvent {
symbol: self.symbol.clone(),
price,
change,
timestamp: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs(),
};
for observer in &self.observers {
observer.on_price_update(&event);
}
}
}
// ========== 使用示例 ==========
fn main() {
let mut aapl = StockTicker::new("AAPL");
// 订阅者
aapl.attach(Box::new(EmailNotifier {
id: "email1".to_string(),
email: "user@example.com".to_string(),
}));
aapl.attach(Box::new(SMSNotifier {
id: "sms1".to_string(),
phone: "+86-138-0000-0000".to_string(),
}));
let dashboard = Arc::new(Dashboard {
id: "dash1".to_string(),
prices: Mutex::new(HashMap::new()),
});
aapl.attach(Box::new(Arc::clone(&dashboard) as Box<dyn StockObserver>));
// 价格更新触发通知
aapl.update_price(178.5, 2.3);
aapl.update_price(180.2, 0.95);
// 取消订阅
aapl.detach("sms1");
aapl.update_price(179.8, -0.22);
}
应用场景
- GUI事件系统:按钮点击、窗口大小变化等事件通知
- 微服务事件总线:服务间通过事件解耦通信
- 实时数据推送:股票/物联网/游戏状态同步
- 配置热更新:配置变更自动通知相关模块
Rust优势:通过trait对象支持多态观察者,通过通道实现跨线程异步通知,通过Arc+Mutex确保多线程安全,结合所有权系统避免观察者生命周期问题。
状态模式详解
定义与作用
状态模式(State Pattern)是一种行为型设计模式,其核心定义是”允许对象在内部状态改变时改变其行为,对象看起来像是修改了它的类”。在Rust语境下,这一模式通过枚举状态机、trait对象状态与类型状态模式三种方式实现,分别适用于不同复杂度与类型安全需求。
// 方式1: 枚举+模式匹配(推荐)
pub enum OrderState {
Created,
Paid,
Shipped,
Delivered,
Cancelled,
}
pub struct Order {
pub id: u64,
pub state: OrderState,
}
impl Order {
pub fn pay(&mut self) -> Result<(), String> {
match self.state {
OrderState::Created => {
self.state = OrderState::Paid;
Ok(())
}
_ => Err("Only created orders can be paid".into()),
}
}
}
Rust状态模式的三种实现方式
1. 枚举状态机(类型安全+零开销)
适合状态固定、转换逻辑清晰的场景:
pub enum ConnectionState {
Disconnected,
Connecting { retry: u32 },
Connected { session_id: String },
}
impl ConnectionState {
fn can_send(&self) -> bool {
matches!(self, ConnectionState::Connected { .. })
}
}
优势:编译期检查状态合法性,无运行时开销,模式匹配清晰 劣势:新增状态需修改枚举定义
2. Trait对象状态(运行时多态)
适合状态行为复杂、需要动态扩展的场景:
pub trait State {
fn handle(&self, ctx: &mut Context, event: Event);
fn name(&self) -> &str;
}
pub struct Context {
state: Box<dyn State>,
}
优势:支持运行时状态切换,行为封装灵活 劣势:动态分发开销,类型信息部分丢失
3. 类型状态模式(编译期状态验证)
适合对状态流转有严格约束的场景:
// 状态标记类型
pub struct Created;
pub struct Paid;
pub struct Shipped;
// 泛型订单,状态由类型参数约束
pub struct Order<S> {
pub id: u64,
_state: std::marker::PhantomData<S>,
}
impl Order<Created> {
pub fn pay(self) -> Order<Paid> {
Order { id: self.id, _state: PhantomData }
}
}
impl Order<Paid> {
pub fn ship(self) -> Order<Shipped> {
Order { id: self.id, _state: PhantomData }
}
}
优势:编译期确保状态流转合法,零运行时开销 劣势:实现复杂,类型签名冗长
代码示例
订单生命周期状态机
// ========== 状态定义 ==========
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum OrderState {
Created,
Paid,
Processing,
Shipped,
Delivered,
Cancelled,
Refunded,
}
impl OrderState {
// 状态转换规则
pub fn can_transition_to(self, next: OrderState) -> bool {
use OrderState::*;
matches!(
(self, next),
(Created, Paid | Cancelled) |
(Paid, Processing | Cancelled | Refunded) |
(Processing, Shipped | Cancelled) |
(Shipped, Delivered | Cancelled) |
(Delivered, Refunded)
)
}
pub fn is_terminal(self) -> bool {
matches!(self, Delivered | Cancelled | Refunded)
}
}
// ========== 订单实体 ==========
#[derive(Debug)]
pub struct Order {
pub id: u64,
pub state: OrderState,
pub history: Vec<(OrderState, u64)>, // 状态变更日志
}
impl Order {
pub fn new(id: u64) -> Self {
Order {
id,
state: OrderState::Created,
history: vec![(OrderState::Created, now())],
}
}
pub fn transition(&mut self, next: OrderState) -> Result<(), String> {
if !self.state.can_transition_to(next) {
return Err(format!(
"Invalid transition: {:?} -> {:?}",
self.state, next
));
}
if self.state.is_terminal() {
return Err("Cannot transition from terminal state".into());
}
self.history.push((next, now()));
self.state = next;
Ok(())
}
pub fn pay(&mut self) -> Result<(), String> {
self.transition(OrderState::Paid)
}
pub fn ship(&mut self) -> Result<(), String> {
self.transition(OrderState::Shipped)
}
pub fn deliver(&mut self) -> Result<(), String> {
self.transition(OrderState::Delivered)
}
pub fn cancel(&mut self) -> Result<(), String> {
self.transition(OrderState::Cancelled)
}
pub fn refund(&mut self) -> Result<(), String> {
self.transition(OrderState::Refunded)
}
}
fn now() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
}
// ========== 使用示例 ==========
fn main() {
let mut order = Order::new(1001);
println!("Order #{} created: {:?}", order.id, order.state);
// 正常流程
order.pay().unwrap();
println!("Paid: {:?}", order.state);
order.ship().unwrap();
println!("Shipped: {:?}", order.state);
order.deliver().unwrap();
println!("Delivered: {:?}", order.state);
// 非法操作:已送达的订单不能取消
assert!(order.cancel().is_err());
// 状态历史
println!("\nState history:");
for (state, ts) in &order.history {
println!(" {:?} @ {}", state, ts);
}
}
应用场景
- 工作流引擎:审批流程、订单流程等状态驱动业务
- 网络协议实现:TCP连接状态机、HTTP请求生命周期
- UI组件状态:按钮启用/禁用、表单验证状态
- 游戏角色状态:站立/移动/攻击/死亡等状态切换
Rust优势:通过枚举+模式匹配实现类型安全的状态转换,编译期捕获非法状态组合;通过类型状态模式可实现零开销的编译期状态验证;结合Result类型优雅处理状态转换错误。
命令模式详解
定义与作用
命令模式(Command Pattern)是一种行为型设计模式,其核心定义是”将请求封装为对象,从而支持参数化、队列化、日志化请求,以及可撤销操作”。在Rust语境下,这一模式通过trait封装、枚举命令与闭包命令三种方式实现,分别适用于复杂命令、固定命令集与轻量级操作场景。
// 方式1: Trait封装(适合复杂命令)
pub trait Command {
fn execute(&mut self) -> Result<(), String>;
fn undo(&mut self) -> Result<(), String>;
fn name(&self) -> &str;
}
pub struct TextEditor {
pub content: String,
}
pub struct InsertText {
editor: *mut TextEditor, // 注意:实际应使用更安全的引用方式
text: String,
position: usize,
}
impl Command for InsertText {
fn execute(&mut self) -> Result<(), String> {
unsafe {
(*self.editor).content.insert_str(self.position, &self.text);
}
Ok(())
}
fn undo(&mut self) -> Result<(), String> {
unsafe {
let end = self.position + self.text.len();
(*self.editor).content.replace_range(self.position..end, "");
}
Ok(())
}
fn name(&self) -> &str { "InsertText" }
}
Rust命令模式的三种实现方式
1. Trait对象命令(支持撤销/重做)
适合需要记录历史、支持事务的复杂场景:
pub trait Command: Any {
fn execute(&mut self) -> Result<(), Error>;
fn undo(&mut self) -> Result<(), Error>;
}
pub struct CommandHistory {
history: Vec<Box<dyn Command>>,
}
优势:支持撤销/重做,命令可序列化,易于测试 劣势:需要手动管理生命周期,动态分发有开销
2. 枚举命令(类型安全+零开销)
适合命令集固定、追求性能的场景:
pub enum EditorCommand {
Insert { text: String, pos: usize },
Delete { range: Range<usize> },
Format { style: Style },
}
impl EditorCommand {
fn execute(&self, editor: &mut Editor) -> Result<(), Error> {
match self {
EditorCommand::Insert { text, pos } => {
editor.content.insert_str(*pos, text);
Ok(())
}
// ... 其他分支
}
}
}
优势:编译期类型检查,无虚表开销,模式匹配清晰 劣势:新增命令需修改枚举,扩展性略低
3. 闭包命令(轻量级)
适合简单操作、无需撤销的场景:
pub type SimpleCommand = Box<dyn FnOnce() -> Result<(), Error> + Send>;
pub struct TaskQueue {
tasks: Vec<SimpleCommand>,
}
impl TaskQueue {
pub fn push<F>(&mut self, task: F)
where F: FnOnce() -> Result<(), Error> + Send + 'static {
self.tasks.push(Box::new(task));
}
pub fn execute_all(&mut self) -> Result<(), Error> {
for task in self.tasks.drain(..) {
task()?;
}
Ok(())
}
}
优势:实现极简,闭包可捕获环境变量,无额外类型定义 劣势:不支持撤销,类型信息弱,调试困难
代码示例
文本编辑器命令系统(支持撤销)
use std::any::Any;
// ========== 命令trait ==========
pub trait Command: Any {
fn execute(&mut self) -> Result<(), String>;
fn undo(&mut self) -> Result<(), String>;
fn name(&self) -> &str;
}
// ========== 编辑器状态 ==========
#[derive(Clone, Debug)]
pub struct EditorState {
pub content: String,
pub cursor: usize,
}
pub struct TextEditor {
pub state: EditorState,
pub history: Vec<Box<dyn Command>>,
pub redo_stack: Vec<Box<dyn Command>>,
}
impl TextEditor {
pub fn new() -> Self {
TextEditor {
state: EditorState {
content: String::new(),
cursor: 0,
},
history: Vec::new(),
redo_stack: Vec::new(),
}
}
pub fn execute(&mut self, mut cmd: Box<dyn Command>) -> Result<(), String> {
cmd.execute()?;
self.redo_stack.clear(); // 执行新命令,清空重做栈
self.history.push(cmd);
Ok(())
}
pub fn undo(&mut self) -> Result<(), String> {
if let Some(mut cmd) = self.history.pop() {
cmd.undo()?;
self.redo_stack.push(cmd);
Ok(())
} else {
Err("Nothing to undo".into())
}
}
pub fn redo(&mut self) -> Result<(), String> {
if let Some(mut cmd) = self.redo_stack.pop() {
cmd.execute()?;
self.history.push(cmd);
Ok(())
} else {
Err("Nothing to redo".into())
}
}
}
// ========== 具体命令:插入文本 ==========
pub struct InsertText {
text: String,
position: usize,
// 保存执行前的状态用于撤销
snapshot: Option<String>,
}
impl InsertText {
pub fn new(text: String, position: usize) -> Self {
InsertText {
text,
position,
snapshot: None,
}
}
}
impl Command for InsertText {
fn execute(&mut self) -> Result<(), String> {
// 实际执行时需要访问编辑器,这里简化处理
// 真实场景应通过引用或回调传递编辑器
println!("Insert '{}' at {}", self.text, self.position);
Ok(())
}
fn undo(&mut self) -> Result<(), String> {
println!("Undo insert at {}", self.position);
Ok(())
}
fn name(&self) -> &str { "InsertText" }
}
// ========== 具体命令:删除文本 ==========
pub struct DeleteText {
start: usize,
end: usize,
deleted: Option<String>,
}
impl DeleteText {
pub fn new(start: usize, end: usize) -> Self {
DeleteText {
start,
end,
deleted: None,
}
}
}
impl Command for DeleteText {
fn execute(&mut self) -> Result<(), String> {
println!("Delete [{}..{})", self.start, self.end);
Ok(())
}
fn undo(&mut self) -> Result<(), String> {
println!("Restore deleted text");
Ok(())
}
fn name(&self) -> &str { "DeleteText" }
}
// ========== 使用示例 ==========
fn main() {
let mut editor = TextEditor::new();
// 执行命令
editor.execute(Box::new(InsertText::new("Hello, ".to_string(), 0)))?;
editor.execute(Box::new(InsertText::new("Rust!".to_string(), 7)))?;
println!("Content: {:?}", editor.state.content);
// 撤销
editor.undo()?;
println!("After undo: {:?}", editor.state.content);
// 重做
editor.redo()?;
println!("After redo: {:?}", editor.state.content);
Ok::<(), String>(())
}
应用场景
- 编辑器操作:插入/删除/格式化等支持撤销的操作
- 事务系统:数据库操作的提交/回滚
- 宏录制:记录用户操作序列并回放
- 任务队列:异步任务的封装与调度
Rust优势:通过trait对象支持命令的多态与撤销,通过枚举实现类型安全的命令集,通过闭包实现轻量级任务封装;结合Result类型优雅处理命令执行错误。
责任链模式详解
定义与作用
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,其核心定义是”使多个对象都有机会处理请求,从而避免请求发送者与接收者之间的耦合,请求沿着链传递直到被处理”。在Rust语境下,这一模式通过Option链式调用、trait对象链与枚举处理器三种方式实现,分别适用于不同复杂度与类型安全需求。
// 方式1: Option链式调用(函数式风格)
pub type HandlerFn = fn(Request) -> Option<Response>;
pub struct Chain {
handlers: Vec<HandlerFn>,
}
impl Chain {
pub fn new(handlers: Vec<HandlerFn>) -> Self {
Chain { handlers }
}
pub fn handle(&self, request: Request) -> Option<Response> {
for handler in &self.handlers {
if let Some(response) = handler(request) {
return Some(response);
}
}
None
}
}
Rust责任链模式的三种实现方式
1. Option链式调用(函数式风格)
适合处理逻辑简单、追求简洁表达的场景:
pub fn handle_request(req: Request) -> Option<Response> {
validate_auth(&req)
.or_else(|| parse_payload(&req))
.or_else(|| route_request(&req))
.or_else(|| fallback_handler(&req))
}
优势:代码简洁,利用Option的组合语义,短路求值 劣势:难以动态配置处理器顺序,调试信息有限
2. Trait对象链(运行时配置)
适合处理器动态加载、顺序可配置的场景:
pub trait Handler {
fn handle(&self, ctx: &mut Context) -> HandleResult;
fn set_next(&mut self, next: Box<dyn Handler>);
}
pub struct Chain {
head: Option<Box<dyn Handler>>,
}
优势:运行时动态组装处理链,支持插件扩展 劣势:动态分发开销,生命周期管理复杂
3. 枚举处理器(编译期类型安全)
适合处理器集合固定、追求零开销的场景:
pub enum Handler {
Auth(AuthHandler),
Parse(ParseHandler),
Route(RouteHandler),
}
impl Handler {
fn handle(&self, ctx: &mut Context) -> HandleResult {
match self {
Handler::Auth(h) => h.handle(ctx),
Handler::Parse(h) => h.handle(ctx),
Handler::Route(h) => h.handle(ctx),
}
}
}
优势:编译期类型检查,无虚表开销,模式匹配清晰 劣势:新增处理器需修改枚举,扩展性略低
代码示例
HTTP请求处理管道
// ========== 请求/响应定义 ==========
#[derive(Debug, Clone)]
pub struct Request {
pub path: String,
pub method: String,
pub headers: std::collections::HashMap<String, String>,
pub body: Option<String>,
}
#[derive(Debug, Clone)]
pub struct Response {
pub status: u16,
pub headers: std::collections::HashMap<String, String>,
pub body: Option<String>,
}
#[derive(Debug)]
pub enum HandleResult {
Continue(Request),
Respond(Response),
Error(String),
}
// ========== 处理器trait ==========
pub trait Handler: Send + Sync {
fn handle(&self, req: Request) -> HandleResult;
fn name(&self) -> &str;
}
// ========== 具体处理器:认证 ==========
pub struct AuthHandler {
pub required_token: Option<String>,
}
impl Handler for AuthHandler {
fn handle(&self, req: Request) -> HandleResult {
if let Some(required) = &self.required_token {
match req.headers.get("Authorization") {
Some(token) if token == required => {
println!("[Auth] ✓ Passed");
HandleResult::Continue(req)
}
_ => {
println!("[Auth] ✗ Failed");
HandleResult::Respond(Response {
status: 401,
headers: [("WWW-Authenticate".into(), "Bearer".into())]
.into_iter().collect(),
body: Some("Unauthorized".into()),
})
}
}
} else {
HandleResult::Continue(req)
}
}
fn name(&self) -> &str { "AuthHandler" }
}
// ========== 具体处理器:日志 ==========
pub struct LoggingHandler {
pub prefix: String,
}
impl Handler for LoggingHandler {
fn handle(&self, req: Request) -> HandleResult {
println!("[{}] {} {}", self.prefix, req.method, req.path);
HandleResult::Continue(req)
}
fn name(&self) -> &str { "LoggingHandler" }
}
// ========== 具体处理器:路由 ==========
pub struct RouteHandler {
pub routes: std::collections::HashMap<String, fn(Request) -> Response>,
}
impl Handler for RouteHandler {
fn handle(&self, req: Request) -> HandleResult {
if let Some(handler) = self.routes.get(&req.path) {
println!("[Route] Matched {}", req.path);
HandleResult::Respond(handler(req))
} else {
HandleResult::Respond(Response {
status: 404,
headers: std::collections::HashMap::new(),
body: Some("Not Found".into()),
})
}
}
fn name(&self) -> &str { "RouteHandler" }
}
// ========== 责任链执行器 ==========
pub struct Pipeline {
handlers: Vec<Box<dyn Handler>>,
}
impl Pipeline {
pub fn new() -> Self {
Pipeline { handlers: Vec::new() }
}
pub fn add<H: Handler + 'static>(&mut self, handler: H) -> &mut Self {
self.handlers.push(Box::new(handler));
self
}
pub fn handle(&self, req: Request) -> Response {
let mut current_req = req;
for handler in &self.handlers {
println!("[Pipeline] Processing: {}", handler.name());
match handler.handle(current_req) {
HandleResult::Continue(req) => current_req = req,
HandleResult::Respond(resp) => return resp,
HandleResult::Error(msg) => {
return Response {
status: 500,
headers: std::collections::HashMap::new(),
body: Some(format!("Internal error: {}", msg)),
};
}
}
}
// 默认响应
Response {
status: 200,
headers: std::collections::HashMap::new(),
body: Some("OK".into()),
}
}
}
// ========== 使用示例 ==========
fn main() {
let mut pipeline = Pipeline::new();
// 组装处理链:日志 → 认证 → 路由
pipeline
.add(LoggingHandler { prefix: "API".into() })
.add(AuthHandler {
required_token: Some("secret-token".into())
})
.add(RouteHandler {
routes: [
("/hello".into(), |req| Response {
status: 200,
headers: std::collections::HashMap::new(),
body: Some(format!("Hello from {}", req.path)),
}),
].into_iter().collect(),
});
// 请求1: 无认证头 → 401
let req1 = Request {
path: "/hello".into(),
method: "GET".into(),
headers: std::collections::HashMap::new(),
body: None,
};
let resp1 = pipeline.handle(req1);
println!("Response 1: {}\n", resp1.status);
// 请求2: 有认证头 → 200
let req2 = Request {
path: "/hello".into(),
method: "GET".into(),
headers: [("Authorization".into(), "secret-token".into())]
.into_iter().collect(),
body: None,
};
let resp2 = pipeline.handle(req2);
println!("Response 2: {} - {:?}", resp2.status, resp2.body);
}
应用场景
- Web中间件:认证、日志、限流、CORS等请求处理链
- 数据验证管道:格式校验→业务校验→持久化校验
- 事件过滤器:日志级别过滤、敏感词过滤、权限过滤
- 插件系统:动态加载处理器实现功能扩展
Rust优势:通过trait对象支持运行时动态组装处理链,通过Option组合实现函数式短路求值,通过枚举实现编译期类型安全的处理器集合;结合Result类型优雅处理链式错误传播。
模板方法模式详解
定义与作用
模板方法模式(Template Method Pattern)是一种行为型设计模式,其核心定义是”定义算法骨架,将具体步骤延迟到子类实现,复用不变部分”。在Rust语境下,这一模式通过trait默认方法、泛型约束与闭包注入三种方式实现,分别适用于不同灵活性与类型安全需求。
// 方式1: Trait默认方法(推荐)
pub trait DataProcessor {
// 模板方法:定义算法骨架
fn process(&self, input: &str) -> String {
let validated = self.validate(input);
let transformed = self.transform(validated);
self.format(transformed)
}
// 钩子方法:子类可选重写
fn validate(&self, input: &str) -> &str {
input.trim()
}
// 抽象方法:子类必须实现
fn transform(&self, input: &str) -> String;
fn format(&self, input: String) -> String;
}
pub struct UpperCaseProcessor;
impl DataProcessor for UpperCaseProcessor {
fn transform(&self, input: &str) -> String {
input.to_uppercase()
}
fn format(&self, input: String) -> String {
format!("[UPPER] {}", input)
}
}
Rust模板方法模式的三种实现方式
1. Trait默认方法(标准实现)
适合算法骨架固定、步骤可定制的场景:
pub trait Pipeline {
fn execute(&self, data: Input) -> Output {
let pre = self.pre_process(data);
let core = self.core_logic(pre);
self.post_process(core)
}
fn pre_process(&self, data: Input) -> Input { data }
fn core_logic(&self, data: Input) -> Output;
fn post_process(&self, output: Output) -> Output { output }
}
优势:代码复用清晰,子类只需实现必要步骤,默认方法提供扩展点 劣势:子类可能意外覆盖关键步骤,需文档约束
2. 泛型约束(编译期多态)
适合追求零开销、步骤类型固定的场景:
pub struct Algorithm<P: PreProcess, C: CoreLogic, Po: PostProcess> {
_phantom: PhantomData<(P, C, Po)>,
}
impl<P, C, Po> Algorithm<P, C, Po>
where
P: PreProcess,
C: CoreLogic,
Po: PostProcess,
{
pub fn execute(input: Input) -> Output {
let pre = P::process(input);
let core = C::process(pre);
Po::process(core)
}
}
优势:编译期确定类型,零运行时开销,类型安全 劣势:类型签名复杂,泛型爆炸可能增加编译时间
3. 闭包注入(轻量级定制)
适合简单定制、追求极简实现的场景:
pub struct ConfigurableProcessor {
pre: Box<dyn Fn(&str) -> String>,
core: Box<dyn Fn(String) -> String>,
post: Box<dyn Fn(String) -> String>,
}
impl ConfigurableProcessor {
pub fn new<F1, F2, F3>(pre: F1, core: F2, post: F3) -> Self
where
F1: Fn(&str) -> String + 'static,
F2: Fn(String) -> String + 'static,
F3: Fn(String) -> String + 'static,
{
ConfigurableProcessor {
pre: Box::new(pre),
core: Box::new(core),
post: Box::new(post),
}
}
pub fn process(&self, input: &str) -> String {
let pre = (self.pre)(input);
let core = (self.core)(pre);
(self.post)(core)
}
}
优势:实现极简,闭包可捕获环境变量,运行时灵活配置 劣势:类型信息弱,调试困难,动态分发有开销
代码示例
数据导入管道模板
// ========== 模板trait ==========
pub trait ImportPipeline {
// 模板方法:定义导入流程骨架
fn import(&self, source: &str) -> Result<ImportResult, ImportError> {
println!("[Pipeline] Starting import from: {}", source);
// 步骤1: 连接数据源(可定制)
let connection = self.connect(source)?;
// 步骤2: 读取数据(可定制)
let raw = self.read(&connection)?;
// 步骤3: 验证数据(钩子方法,可选)
let validated = self.validate(raw)?;
// 步骤4: 转换数据(必须实现)
let transformed = self.transform(validated)?;
// 步骤5: 持久化(可定制)
let result = self.persist(transformed)?;
// 步骤6: 清理(钩子方法,可选)
self.cleanup(&connection)?;
println!("[Pipeline] Import completed");
Ok(result)
}
// 抽象方法:子类必须实现
fn transform(&self, data: RawData) -> Result<TransformedData, ImportError>;
// 默认实现:子类可选重写
fn connect(&self, source: &str) -> Result<Connection, ImportError> {
println!("[Default] Connecting to: {}", source);
Ok(Connection { id: 1 })
}
fn read(&self, conn: &Connection) -> Result<RawData, ImportError> {
println!("[Default] Reading data");
Ok(RawData { rows: vec![] })
}
fn validate(&self, data: RawData) -> Result<RawData, ImportError> {
println!("[Default] Validation passed");
Ok(data)
}
fn persist(&self, data: TransformedData) -> Result<ImportResult, ImportError> {
println!("[Default] Persisting {} records", data.records.len());
Ok(ImportResult { count: data.records.len() })
}
fn cleanup(&self, _conn: &Connection) -> Result<(), ImportError> {
println!("[Default] Cleanup completed");
Ok(())
}
}
// ========== 辅助类型 ==========
#[derive(Debug)]
pub struct Connection { pub id: u64 }
#[derive(Debug)]
pub struct RawData { pub rows: Vec<String> }
#[derive(Debug)]
pub struct TransformedData { pub records: Vec<Record> }
#[derive(Debug)]
pub struct Record { pub fields: std::collections::HashMap<String, String> }
#[derive(Debug)]
pub struct ImportResult { pub count: usize }
#[derive(Debug)]
pub enum ImportError {
ConnectionFailed(String),
ReadError(String),
ValidationError(String),
TransformError(String),
}
// ========== 具体实现:CSV导入 ==========
pub struct CsvImportPipeline {
pub delimiter: char,
pub has_header: bool,
}
impl ImportPipeline for CsvImportPipeline {
fn transform(&self, data: RawData) -> Result<TransformedData, ImportError> {
println!("[CSV] Transforming with delimiter '{}'", self.delimiter);
let records = data.rows.iter().map(|row| {
let fields: Vec<&str> = row.split(self.delimiter).collect();
let mut map = std::collections::HashMap::new();
for (i, field) in fields.iter().enumerate() {
map.insert(format!("col_{}", i), field.to_string());
}
Record { fields: map }
}).collect();
Ok(TransformedData { records })
}
// 重写验证步骤:检查CSV格式
fn validate(&self, data: RawData) -> Result<RawData, ImportError> {
for (i, row) in data.rows.iter().enumerate() {
if row.matches(self.delimiter).count() < 2 {
return Err(ImportError::ValidationError(
format!("Row {} has insufficient columns", i)
));
}
}
println!("[CSV] Validation passed: {} rows", data.rows.len());
Ok(data)
}
}
// ========== 具体实现:JSON导入 ==========
pub struct JsonImportPipeline;
impl ImportPipeline for JsonImportPipeline {
fn transform(&self, data: RawData) -> Result<TransformedData, ImportError> {
println!("[JSON] Parsing JSON data");
// 简化:实际应使用serde_json
let records = data.rows.iter().map(|row| {
Record {
fields: [("raw".into(), row.clone())].into_iter().collect(),
}
}).collect();
Ok(TransformedData { records })
}
// 重写连接步骤:模拟HTTP连接
fn connect(&self, source: &str) -> Result<Connection, ImportError> {
if !source.starts_with("http") {
return Err(ImportError::ConnectionFailed(
"JSON source must be HTTP URL".into()
));
}
println!("[JSON] HTTP connection established");
Ok(Connection { id: 2 })
}
}
// ========== 使用示例 ==========
fn main() -> Result<(), ImportError> {
// CSV导入
let csv_pipeline = CsvImportPipeline {
delimiter: ',',
has_header: true,
};
let csv_result = csv_pipeline.import("data/users.csv")?;
println!("CSV import: {} records\n", csv_result.count);
// JSON导入
let json_pipeline = JsonImportPipeline;
let json_result = json_pipeline.import("https://api.example.com/users")?;
println!("JSON import: {} records", json_result.count);
Ok(())
}
应用场景
- 数据导入导出:不同格式(CSV/JSON/XML)的导入流程复用
- 测试框架:setup→test→teardown的测试生命周期
- 构建系统:编译→链接→打包的构建流程定制
- 工作流引擎:审批→执行→通知的流程模板
Rust优势:通过trait默认方法实现算法骨架复用,子类只需关注差异化步骤;通过泛型约束实现编译期零开销的模板实例化;结合Result类型优雅处理各步骤的错误传播。
访问者模式详解
定义与作用
访问者模式(Visitor Pattern)是一种行为型设计模式,其核心定义是”在不修改数据结构的前提下,定义作用于元素的新操作,将操作与对象结构解耦”。在Rust语境下,这一模式通过双重分发、枚举匹配与泛型访问者三种方式实现,分别适用于不同复杂度与类型安全需求。
// 方式1: 双重分发(经典实现)
pub trait Element {
fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result;
}
pub trait Visitor {
type Result;
fn visit_concrete_a(&mut self, element: &ConcreteA) -> Self::Result;
fn visit_concrete_b(&mut self, element: &ConcreteB) -> Self::Result;
}
pub struct ConcreteA { pub value: i32 }
impl Element for ConcreteA {
fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
visitor.visit_concrete_a(self)
}
}
pub struct ConcreteB { pub text: String }
impl Element for ConcreteB {
fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
visitor.visit_concrete_b(self)
}
}
Rust访问者模式的三种实现方式
1. 双重分发Trait(标准实现)
适合元素类型固定、操作需要多态的场景:
pub trait Shape {
fn accept<V: ShapeVisitor>(&self, visitor: &mut V) -> V::Output;
}
pub trait ShapeVisitor {
type Output;
fn visit_circle(&mut self, c: &Circle) -> Self::Output;
fn visit_rect(&mut self, r: &Rectangle) -> Self::Output;
}
优势:操作与数据结构完全解耦,新增操作无需修改元素 劣势:新增元素类型需修改所有访问者,双重分发有性能开销
2. 枚举+模式匹配(简化实现)
适合元素集合固定、追求简洁的场景:
pub enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
impl Shape {
pub fn area(&self) -> f64 {
match self {
Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
Shape::Rectangle { width, height } => width * height,
}
}
}
优势:实现简洁,编译期类型检查,无虚表开销 劣势:新增操作需修改枚举匹配,操作与数据耦合
3. 泛型访问者(编译期多态)
适合追求零开销、访问者类型固定的场景:
pub trait Element {
fn accept<V>(&self, visitor: &mut V) -> V::Result
where V: Visitor<Self>;
}
pub trait Visitor<E> {
type Result;
fn visit(&mut self, element: &E) -> Self::Result;
}
优势:编译期确定类型,零运行时开销,类型安全 劣势:泛型代码膨胀,类型签名复杂
代码示例
AST表达式求值访问者
// ========== 元素trait ==========
pub trait Expr: std::fmt::Debug {
fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result;
}
// ========== 访问者trait ==========
pub trait Visitor {
type Result;
fn visit_literal(&mut self, lit: &Literal) -> Self::Result;
fn visit_binary(&mut self, bin: &BinaryExpr) -> Self::Result;
fn visit_unary(&mut self, unary: &UnaryExpr) -> Self::Result;
}
// ========== 具体元素:字面量 ==========
#[derive(Debug)]
pub struct Literal {
pub value: f64,
}
impl Expr for Literal {
fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
visitor.visit_literal(self)
}
}
// ========== 具体元素:二元表达式 ==========
#[derive(Debug)]
pub enum BinaryOp { Add, Sub, Mul, Div }
#[derive(Debug)]
pub struct BinaryExpr {
pub op: BinaryOp,
pub left: Box<dyn Expr>,
pub right: Box<dyn Expr>,
}
impl Expr for BinaryExpr {
fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
visitor.visit_binary(self)
}
}
// ========== 具体元素:一元表达式 ==========
#[derive(Debug)]
pub enum UnaryOp { Neg, Abs }
#[derive(Debug)]
pub struct UnaryExpr {
pub op: UnaryOp,
pub operand: Box<dyn Expr>,
}
impl Expr for UnaryExpr {
fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
visitor.visit_unary(self)
}
}
// ========== 访问者实现1: 求值 ==========
pub struct EvalVisitor;
impl Visitor for EvalVisitor {
type Result = Result<f64, String>;
fn visit_literal(&mut self, lit: &Literal) -> Self::Result {
Ok(lit.value)
}
fn visit_binary(&mut self, bin: &BinaryExpr) -> Self::Result {
let left = bin.left.accept(self)?;
let right = bin.right.accept(self)?;
match bin.op {
BinaryOp::Add => Ok(left + right),
BinaryOp::Sub => Ok(left - right),
BinaryOp::Mul => Ok(left * right),
BinaryOp::Div => {
if right == 0.0 {
Err("Division by zero".into())
} else {
Ok(left / right)
}
}
}
}
fn visit_unary(&mut self, unary: &UnaryExpr) -> Self::Result {
let operand = unary.operand.accept(self)?;
match unary.op {
UnaryOp::Neg => Ok(-operand),
UnaryOp::Abs => Ok(operand.abs()),
}
}
}
// ========== 访问者实现2: 打印 ==========
pub struct PrintVisitor {
pub output: String,
}
impl Visitor for PrintVisitor {
type Result = ();
fn visit_literal(&mut self, lit: &Literal) {
self.output.push_str(&format!("{}", lit.value));
}
fn visit_binary(&mut self, bin: &BinaryExpr) {
self.output.push('(');
bin.left.accept(self);
let op = match bin.op {
BinaryOp::Add => '+',
BinaryOp::Sub => '-',
BinaryOp::Mul => '*',
BinaryOp::Div => '/',
};
self.output.push(op);
bin.right.accept(self);
self.output.push(')');
}
fn visit_unary(&mut self, unary: &UnaryExpr) {
let prefix = match unary.op {
UnaryOp::Neg => "-",
UnaryOp::Abs => "abs(",
};
self.output.push_str(prefix);
unary.operand.accept(self);
if matches!(unary.op, UnaryOp::Abs) {
self.output.push(')');
}
}
}
// ========== 使用示例 ==========
fn main() -> Result<(), String> {
// 构建表达式: (3 + 4) * 2
let expr: Box<dyn Expr> = Box::new(BinaryExpr {
op: BinaryOp::Mul,
left: Box::new(BinaryExpr {
op: BinaryOp::Add,
left: Box::new(Literal { value: 3.0 }),
right: Box::new(Literal { value: 4.0 }),
}),
right: Box::new(Literal { value: 2.0 }),
});
// 求值
let mut eval = EvalVisitor;
let result = expr.accept(&mut eval)?;
println!("Result: {}", result); // 14.0
// 打印
let mut print = PrintVisitor { output: String::new() };
expr.accept(&mut print);
println!("Expression: {}", print.output); // ((3+4)*2)
Ok(())
}
应用场景
- 编译器/解释器:AST遍历实现类型检查、代码生成、优化
- 文档处理:对不同节点类型执行渲染、导出、统计等操作
- 配置校验:对配置树执行验证、转换、序列化等操作
- UI框架:对组件树执行布局计算、事件分发、渲染等操作
性能对比: | 实现方式 | 新增元素开销 | 新增操作开销 | 运行时开销 | |———-|————-|————-|———–| | 双重分发 | 高(修改所有Visitor) | 低(新增Visitor) | 虚表调用×2 | | 枚举匹配 | 低(修改enum) | 高(修改所有match) | 无 | | 泛型访问者 | 中(泛型实例化) | 低(新增类型) | 无(内联) |
Rust优势:通过trait系统实现类型安全的双重分发,编译期确保访问者方法完整性;通过枚举+模式匹配提供简化替代方案;结合Result类型优雅处理访问过程中的错误。
实践应用
综合案例:工作流引擎
本案例设计为”可配置工作流引擎”,通过整合策略、状态、命令、责任链、模板方法五种行为型模式,构建灵活可靠的任务执行系统。系统架构中:
- 状态模式:
TaskState管理任务生命周期(待执行→执行中→完成/失败) - 策略模式:
RetryStrategy实现不同重试策略(固定间隔/指数退避/不重试) - 命令模式:
TaskCommand封装任务执行逻辑,支持撤销与日志 - 责任链模式:
MiddlewareChain实现任务预处理(鉴权→限流→日志) - 模板方法模式:
WorkflowTemplate定义工作流执行骨架,支持自定义步骤
协作流程:
- 客户端提交任务,责任链执行预处理中间件
- 模板方法定义任务执行流程:准备→执行→清理
- 状态机确保任务状态合法流转
- 策略模式决定失败后的重试行为
- 命令模式记录执行历史,支持回滚
各模式协同解决了任务调度、错误处理、流程定制、可观测性等复杂需求。
核心实现(简化版)
use std::sync::Arc;
use std::time::{Duration, Instant};
// ========== 状态模式:任务状态 ==========
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TaskState {
Pending,
Running,
Completed,
Failed { retries: u32 },
}
impl TaskState {
pub fn can_transition_to(self, next: TaskState) -> bool {
use TaskState::*;
matches!(
(self, next),
(Pending, Running) |
(Running, Completed | Failed { .. }) |
(Failed { retries: r }, Pending) if r < 3
)
}
}
// ========== 策略模式:重试策略 ==========
pub trait RetryStrategy: Send + Sync {
fn should_retry(&self, attempt: u32, error: &str) -> bool;
fn delay(&self, attempt: u32) -> Duration;
}
pub struct NoRetry;
impl RetryStrategy for NoRetry {
fn should_retry(&self, _attempt: u32, _error: &str) -> bool { false }
fn delay(&self, _attempt: u32) -> Duration { Duration::ZERO }
}
pub struct ExponentialBackoff {
pub base: Duration,
pub max_delay: Duration,
}
impl RetryStrategy for ExponentialBackoff {
fn should_retry(&self, attempt: u32, _error: &str) -> bool {
attempt < 3
}
fn delay(&self, attempt: u32) -> Duration {
let delay = self.base * (2u32.pow(attempt));
delay.min(self.max_delay)
}
}
// ========== 命令模式:任务命令 ==========
pub trait TaskCommand: Send {
fn execute(&mut self) -> Result<TaskResult, TaskError>;
fn name(&self) -> &str;
}
pub struct TaskResult {
pub output: String,
pub duration: Duration,
}
pub struct TaskError {
pub message: String,
pub retryable: bool,
}
// 示例命令:模拟任务
pub struct SimulateTask {
pub name: String,
pub should_fail: bool,
pub attempt: u32,
}
impl TaskCommand for SimulateTask {
fn execute(&mut self) -> Result<TaskResult, TaskError> {
println!("[Task] Executing: {} (attempt {})", self.name, self.attempt);
if self.should_fail && self.attempt < 2 {
return Err(TaskError {
message: "Simulated failure".into(),
retryable: true,
});
}
std::thread::sleep(Duration::from_millis(100));
Ok(TaskResult {
output: format!("{} completed", self.name),
duration: Duration::from_millis(100),
})
}
fn name(&self) -> &str { &self.name }
}
// ========== 责任链模式:中间件 ==========
pub trait Middleware: Send + Sync {
fn handle(&self, ctx: &mut TaskContext) -> Result<(), String>;
}
pub struct AuthMiddleware {
pub required_role: Option<String>,
}
impl Middleware for AuthMiddleware {
fn handle(&self, ctx: &mut TaskContext) -> Result<(), String> {
if let Some(role) = &self.required_role {
if ctx.user_role.as_ref() != Some(role) {
return Err("Unauthorized".into());
}
}
Ok(())
}
}
pub struct LoggingMiddleware;
impl Middleware for LoggingMiddleware {
fn handle(&self, ctx: &mut TaskContext) -> Result<(), String> {
println!("[Middleware] Task: {} by user: {:?}",
ctx.task_name, ctx.user_id);
Ok(())
}
}
pub struct RateLimitMiddleware {
pub max_per_minute: u32,
pub current: std::sync::atomic::AtomicU32,
}
impl Middleware for RateLimitMiddleware {
fn handle(&self, _ctx: &mut TaskContext) -> Result<(), String> {
// 简化:实际应实现滑动窗口限流
Ok(())
}
}
pub struct TaskContext {
pub task_name: String,
pub user_id: Option<u64>,
pub user_role: Option<String>,
pub metadata: std::collections::HashMap<String, String>,
}
// ========== 模板方法:工作流执行 ==========
pub trait WorkflowTemplate: Send {
// 模板方法:定义执行骨架
fn run(&self, ctx: &mut TaskContext) -> Result<TaskResult, TaskError> {
self.before_execute(ctx)?;
let result = self.execute_core(ctx)?;
self.after_execute(ctx, &result)?;
Ok(result)
}
// 钩子方法:子类可选重写
fn before_execute(&self, _ctx: &mut TaskContext) -> Result<(), TaskError> {
Ok(())
}
fn after_execute(&self, _ctx: &mut TaskContext, _result: &TaskResult)
-> Result<(), TaskError> { Ok(()) }
// 抽象方法:子类必须实现
fn execute_core(&self, ctx: &mut TaskContext) -> Result<TaskResult, TaskError>;
}
// ========== 具体工作流:带重试的任务执行 ==========
pub struct RetryableWorkflow {
pub command: Box<dyn TaskCommand>,
pub retry_strategy: Box<dyn RetryStrategy>,
pub middlewares: Vec<Arc<dyn Middleware>>,
}
impl WorkflowTemplate for RetryableWorkflow {
fn execute_core(&self, ctx: &mut TaskContext) -> Result<TaskResult, TaskError> {
// 执行中间件链
for mw in &self.middlewares {
mw.handle(ctx).map_err(|e| TaskError {
message: format!("Middleware failed: {}", e),
retryable: false,
})?;
}
// 执行命令
self.command.execute()
}
fn after_execute(&self, ctx: &mut TaskContext, result: &TaskResult)
-> Result<(), TaskError>
{
println!("[Workflow] Task completed in {:?}", result.duration);
Ok(())
}
}
// ========== 任务执行器 ==========
pub struct TaskExecutor {
pub state: TaskState,
pub workflow: Box<dyn WorkflowTemplate>,
pub retry_count: u32,
}
impl TaskExecutor {
pub fn new(workflow: Box<dyn WorkflowTemplate>) -> Self {
TaskExecutor {
state: TaskState::Pending,
workflow,
retry_count: 0,
}
}
pub fn execute(&mut self, ctx: &mut TaskContext) -> Result<TaskResult, TaskError> {
// 状态检查
if !self.state.can_transition_to(TaskState::Running) {
return Err(TaskError {
message: format!("Invalid state transition: {:?}", self.state),
retryable: false,
});
}
self.state = TaskState::Running;
// 执行工作流
match self.workflow.run(ctx) {
Ok(result) => {
self.state = TaskState::Completed;
Ok(result)
}
Err(error) => {
let strategy = &self.workflow; // 实际应获取策略
if error.retryable && self.retry_strategy_should_retry() {
self.retry_count += 1;
self.state = TaskState::Failed { retries: self.retry_count };
// 实际应实现延迟重试
Err(TaskError {
message: format!("Will retry (attempt {})", self.retry_count),
retryable: true,
})
} else {
self.state = TaskState::Failed { retries: self.retry_count };
Err(error)
}
}
}
}
fn retry_strategy_should_retry(&self) -> bool {
// 简化:实际应委托给策略对象
self.retry_count < 3
}
}
// ========== 使用示例 ==========
fn main() -> Result<(), TaskError> {
// 构建工作流
let workflow = Box::new(RetryableWorkflow {
command: Box::new(SimulateTask {
name: "DataSync".into(),
should_fail: true,
attempt: 1,
}),
retry_strategy: Box::new(ExponentialBackoff {
base: Duration::from_secs(1),
max_delay: Duration::from_secs(10),
}),
middlewares: vec![
Arc::new(AuthMiddleware { required_role: Some("admin".into()) }),
Arc::new(LoggingMiddleware),
],
});
let mut executor = TaskExecutor::new(workflow);
let mut ctx = TaskContext {
task_name: "DataSync".into(),
user_id: Some(1001),
user_role: Some("admin".into()),
metadata: std::collections::HashMap::new(),
};
// 执行任务(可能重试)
match executor.execute(&mut ctx) {
Ok(result) => println!("✓ Success: {}", result.output),
Err(e) => println!("✗ Failed: {} (retryable: {})", e.message, e.retryable),
}
println!("Final state: {:?}", executor.state);
Ok(())
}
模式协作优势:
- 状态模式确保任务生命周期合法流转,避免非法状态组合
- 策略模式灵活配置重试行为,支持不同业务场景的容错需求
- 命令模式封装任务逻辑,支持执行历史追踪与回滚
- 责任链模式解耦预处理逻辑,便于动态组合鉴权/限流/日志等中间件
- 模板方法模式复用执行骨架,子类只需关注核心业务逻辑
常见错误与解决
错误1:策略模式 - 生命周期管理不当
错误表现:策略对象持有引用时未正确处理生命周期,导致悬垂引用。
错误代码:
pub struct PaymentContext<'a> {
strategy: &'a dyn PaymentStrategy, // 生命周期绑定
}
fn problematic() {
let ctx;
{
let strat = PercentageDiscount { percent: 0.1 };
ctx = PaymentContext { strategy: &strat }; // strat即将被丢弃
} // strat在此处被drop
ctx.calculate(100.0); // ❌ 悬垂引用!
}
解决方案:使用Box或Arc转移所有权确保生命周期安全。
修正代码:
pub struct PaymentContext {
strategy: Box<dyn PaymentStrategy>, // 拥有所有权
}
// 或共享所有权
pub struct PaymentContext {
strategy: Arc<dyn PaymentStrategy>,
}
错误2:观察者模式 - 迭代时修改集合
错误表现:通知观察者时修改观察者列表,导致迭代器失效。
错误代码:
impl Subject {
fn notify(&mut self, event: &Event) {
for observer in &self.observers {
observer.update(event);
// ❌ 可能在update中调用detach,修改self.observers
}
}
}
解决方案:先收集需要移除的观察者,迭代完成后再统一处理。
修正代码:
impl Subject {
fn notify(&mut self, event: &Event) {
// 先收集需要移除的观察者ID
let to_remove: Vec<String> = self.observers.iter()
.filter(|obs| obs.should_remove_after_notify(event))
.map(|obs| obs.id().to_string())
.collect();
// 通知所有观察者
for observer in &self.observers {
observer.update(event);
}
// 最后统一移除
for id in to_remove {
self.observers.retain(|obs| obs.id() != id);
}
}
}
错误3:状态模式 - 非法状态转换
错误表现:未验证状态转换合法性,导致业务逻辑错误。
错误代码:
impl Order {
fn ship(&mut self) {
// ❌ 未检查当前状态,已取消的订单也能发货
self.state = OrderState::Shipped;
}
}
解决方案:在状态转换方法中验证前置状态。
修正代码:
impl Order {
fn ship(&mut self) -> Result<(), String> {
match self.state {
OrderState::Paid | OrderState::Processing => {
self.state = OrderState::Shipped;
Ok(())
}
_ => Err(format!(
"Cannot ship order in state: {:?}",
self.state
)),
}
}
}
错误4:命令模式 - 撤销状态不一致
错误表现:命令执行后未保存足够信息,导致撤销失败。
错误代码:
pub struct DeleteText {
range: Range<usize>,
// ❌ 未保存被删除的内容
}
impl Command for DeleteText {
fn undo(&mut self) -> Result<(), String> {
// ❌ 无法恢复已删除的文本
Err("Cannot undo: original content lost".into())
}
}
解决方案:命令执行前保存必要状态用于撤销。
修正代码:
pub struct DeleteText {
range: Range<usize>,
deleted_content: Option<String>, // 执行后填充
}
impl Command for DeleteText {
fn execute(&mut self, editor: &mut Editor) -> Result<(), String> {
self.deleted_content = Some(
editor.content[self.range.clone()].to_string()
);
editor.content.replace_range(self.range.clone(), "");
Ok(())
}
fn undo(&mut self, editor: &mut Editor) -> Result<(), String> {
if let Some(content) = &self.deleted_content {
editor.content.insert_str(self.range.start, content);
Ok(())
} else {
Err("Cannot undo: no content to restore".into())
}
}
}
错误5:访问者模式 - 忘记实现访问方法
错误表现:新增元素类型后,忘记在访问者中实现对应方法,导致编译错误或运行时恐慌。
错误代码:
// 新增元素类型
pub struct Triangle { /* ... */ }
impl Element for Triangle {
fn accept<V: Visitor>(&self, visitor: &mut V) -> V::Result {
// ❌ Visitor trait没有visit_triangle方法
// 编译错误!
}
}
解决方案:使用宏或代码生成确保访问者方法完整性。
修正代码:
// 方案1: 使用macro_rules!生成访问者代码
macro_rules! define_visitor {
($($elem:ident => $method:ident),*) => {
pub trait Visitor {
type Result;
$(fn $method(&mut self, e: &$elem) -> Self::Result;)*
}
$(impl Element for $elem {
fn accept<V: Visitor>(&self, v: &mut V) -> V::Result {
v.$method(self)
}
})*
};
}
// 使用宏定义所有元素和访问方法
define_visitor! {
Literal => visit_literal,
BinaryExpr => visit_binary,
UnaryExpr => visit_unary,
Triangle => visit_triangle // 新增时只需在此添加
}
// 方案2: 使用enum+match替代双重分发(简化场景)
pub enum Expr {
Literal(Literal),
Binary(BinaryExpr),
Triangle(Triangle), // 新增时修改此处
}
impl Expr {
pub fn accept<V: ExprVisitor>(&self, v: &mut V) -> V::Result {
match self {
Expr::Literal(e) => v.visit_literal(e),
Expr::Binary(e) => v.visit_binary(e),
Expr::Triangle(e) => v.visit_triangle(e), // 新增分支
}
}
}
总结要点
Rust行为型模式的核心价值
- 组合优于继承:通过trait组合与闭包注入实现行为复用,避免继承层次僵化
- 零成本抽象:泛型与内联优化确保设计模式不引入运行时开销
- 编译期安全:类型系统提前捕获状态非法转换、访问者方法缺失等问题
- 并发友好:
Send/Synctrait与Arc/Mutex原语简化线程安全的行为协作
模式选择指南
| 场景需求 | 推荐模式 | Rust实现要点 |
|---|---|---|
| 算法动态替换 | 策略模式 | trait对象 或 闭包 + 泛型 |
| 事件通知机制 | 观察者模式 | 回调闭包 或 通道+线程 |
| 状态机管理 | 状态模式 | 枚举+模式匹配 或 类型状态 |
| 请求封装/撤销 | 命令模式 | trait封装 + 历史记录 |
| 处理流程编排 | 责任链模式 | Option链式 或 trait对象链 |
| 算法骨架复用 | 模板方法 | trait默认方法 + 钩子函数 |
| 操作与数据解耦 | 访问者模式 | 双重分发trait 或 枚举匹配 |
性能优化建议
- 优先静态分发:能用泛型就不用trait对象,减少虚表调用开销
- 避免过度抽象:简单场景直接使用函数/闭包,无需引入完整模式
- 状态机优化:使用
#[repr(u8)]枚举减少内存占用,模式匹配可被LLVM优化 - 观察者批量通知:避免在通知循环中修改集合,先收集后处理
Rust惯用法融合
- 利用
?操作符简化错误传播:各模式中的步骤方法统一返回Result - 使用
impl Trait简化返回类型:避免暴露具体策略/命令类型 - 结合
derive宏减少样板代码:Clone/Debug/PartialEq等 - 采用
PhantomData处理类型参数:类型状态模式中标记状态类型
进阶资源
- Rust Design Patterns - Behavioral
- The Rust Book - Traits
- Rust Async Book - Channels
- State Machines in Rust
- Rust API Guidelines - Error Handling
Rust社区风采
https://example.com/rust-behavioral-patterns.jpg
Rust社区通过类型系统与创新抽象,为传统行为型设计模式注入了新的活力。在保持模式解耦与复用核心价值的同时,借助trait、枚举、闭包与零成本泛型等特性,实现了前所未有的类型安全与性能保障。这些实践不仅提升了代码质量,更为构建可靠、高效、可维护的大型系统提供了坚实的方法论基础。🦀✨