快速复习常见设计模式(以Rust为例)
设计模式是解决软件设计问题的经典方案,掌握它们能显著提升代码的可维护性和扩展性。本文以rust为例,快速回顾部分常用GoF设计模式的核心思想与典型应用场景,涵盖创建型(如工厂、单例)、结构型(如适配器、装饰器)和行为型(如观察者、策略)三大类,并通过简洁代码示例展示实现要点。我们可以发现Rust的特性能让我们省掉很多不必要的模式。例如,不再需要策略模式——在Rust里可以直接用traits。
一、创建型模式
Ⅰ、原型模式(Prototype)
“复印机”:直接复制一个现有的对象,不用从头开始造(比如克隆羊多利,直接复制原版)。
通过克隆现有对象生成新对象,避免重复初始化。
trait Prototype: Clone {
fn use_it(&self);
}
#[derive(Clone)]
struct ConcretePrototype {
name: String,
}
impl Prototype for ConcretePrototype {
fn use_it(&self) {
println!("Using prototype: {}", self.name);
}
}
fn main() {
let original = ConcretePrototype { name: "Original".to_string() };
let cloned = original.clone();
cloned.use_it(); // Output: Using prototype: Original
}
Ⅱ、建造者模式(Builder)
“分步组装”:就像组装电脑:先选CPU,再选显卡,最后装内存,一步步拼成最终成品,避免一次性塞进所有零件。
分步骤构造复杂对象,解耦构造过程与具体表示。
struct Computer {
cpu: String,
gpu: String,
ram: String,
}
struct ComputerBuilder {
cpu: Option
gpu: Option
ram: Option
}
impl ComputerBuilder {
fn new() -> Self {
ComputerBuilder {
cpu: None,
gpu: None,
ram: None,
}
}
fn cpu(mut self, cpu: &str) -> Self {
self.cpu = Some(cpu.to_string());
self
}
fn gpu(mut self, gpu: &str) -> Self {
self.gpu = Some(gpu.to_string());
self
}
fn ram(mut self, ram: &str) -> Self {
self.ram = Some(ram.to_string());
self
}
fn build(self) -> Computer {
Computer {
cpu: self.cpu.unwrap_or_default(),
gpu: self.gpu.unwrap_or_default(),
ram: self.ram.unwrap_or_default(),
}
}
}
fn main() {
let computer = ComputerBuilder::new()
.cpu("Intel i7")
.gpu("NVIDIA RTX 3080")
.ram("16GB")
.build();
println!("Computer: CPU={}, GPU={}, RAM={}", computer.cpu, computer.gpu, computer.ram);
// Output: Computer: CPU=Intel i7, GPU=NVIDIA RTX 3080, RAM=16GB
}
Ⅲ、工厂方法模式(Factory Method)
“点单取货”:告诉奶茶店“我要一杯珍珠奶茶”,店员按标准流程做好给你,你不需要关心奶茶具体怎么做的。
定义创建对象的接口,由子类决定实例化的具体类。
trait MilkTea {
fn drink(&self);
}
struct PearlMilkTea;
impl MilkTea for PearlMilkTea {
fn drink(&self) {
println!("Drinking Pearl Milk Tea");
}
}
trait MilkTeaFactory {
fn create_milk_tea(&self) -> Box
}
struct PearlMilkTeaFactory;
impl MilkTeaFactory for PearlMilkTeaFactory {
fn create_milk_tea(&self) -> Box
Box::new(PearlMilkTea)
}
}
fn main() {
let factory = PearlMilkTeaFactory;
let milk_tea = factory.create_milk_tea();
milk_tea.drink(); // Output: Drinking Pearl Milk Tea
}
Ⅳ、抽象工厂(Abstract Factory)
“全家桶套餐”:买一套“北欧风家具”(沙发+桌子+柜子),工厂保证风格统一,不用自己一件件挑。
创建一组相关对象家族,屏蔽具体实现类。
trait Furniture {
fn sit(&self);
}
struct Sofa;
impl Furniture for Sofa {
fn sit(&self) {
println!("Sitting on a sofa");
}
}
struct Table;
impl Furniture for Table {
fn sit(&self) {
println!("Cannot sit on a table");
}
}
trait FurnitureFactory {
fn create_sofa(&self) -> Box
fn create_table(&self) -> Box
}
struct NordicFurnitureFactory;
impl FurnitureFactory for NordicFurnitureFactory {
fn create_sofa(&self) -> Box
Box::new(Sofa)
}
fn create_table(&self) -> Box
Box::new(Table)
}
}
fn main() {
let factory = NordicFurnitureFactory;
let sofa = factory.create_sofa();
let table = factory.create_table();
sofa.sit(); // Output: Sitting on a sofa
table.sit(); // Output: Cannot sit on a table
}
Ⅴ、单例模式(Singleton)
“唯一管理员”:整个公司只有一个CEO,谁需要CEO办事都找同一个人,不允许有第二个。
确保类仅有一个实例,并提供全局访问入口。
use std::sync::{Arc, Mutex};
use lazy_static::lazy_static;
struct CEO {
name: String,
}
impl CEO {
fn new(name: &str) -> Self {
CEO { name: name.to_string() }
}
fn work(&self) {
println!("{} is working", self.name);
}
}
lazy_static! {
static ref CEO_INSTANCE: Arc
}
fn get_ceo() -> Arc
CEO_INSTANCE.clone()
}
fn main() {
let ceo = get_ceo();
let ceo_guard = ceo.lock().unwrap();
ceo_guard.work(); // Output: John is working
}
二、结构型模式
Ⅰ、适配器模式(Adapter)
“转接头”:把Type-C接口转换成USB,让旧手机也能用新耳机(让不兼容的接口能一起工作)。
转换接口使不兼容的类协同工作(类/对象适配)。
struct OldDevice {
pub old_interface: String,
}
impl OldDevice {
fn use_old_interface(&self) {
println!("Using old interface: {}", self.old_interface);
}
}
trait NewInterface {
fn use_new_interface(&self);
}
struct Adapter {
old_device: OldDevice,
}
impl NewInterface for Adapter {
fn use_new_interface(&self) {
self.old_device.use_old_interface();
}
}
fn main() {
let old_device = OldDevice { old_interface: "Old USB".to_string() };
let adapter = Adapter { old_device };
adapter.use_new_interface(); // 输出: Using old interface: Old USB
}
Ⅱ、桥接模式(Bridge)
“遥控器与电器”:遥控器可以控制电视、空调等不同电器。遥控器(抽象部分)与电器(实现部分)分离,互不影响。这样,遥控器不用管电器是什么,只要电器支持“开关”功能就能被控制。遥控器加个音量键,电器不用改;电器换成智能音箱,遥控器也不用变。
分离抽象与实现,允许两者独立变化(如渲染器与形状的组合)。
trait Device {
fn operate(&self);
}
struct TV;
impl Device for TV {
fn operate(&self) {
println!("TV is operating");
}
}
struct AirConditioner;
impl Device for AirConditioner {
fn operate(&self) {
println!("Air Conditioner is operating");
}
}
struct RemoteControl
device: T,
}
impl
fn new(device: T) -> Self {
RemoteControl { device }
}
fn control(&self) {
self.device.operate();
}
}
fn main() {
let tv = TV;
let ac = AirConditioner;
let remote_tv = RemoteControl::new(tv);
let remote_ac = RemoteControl::new(ac);
remote_tv.control(); // 输出: TV is operating
remote_ac.control(); // 输出: Air Conditioner is operating
}
Ⅲ、装饰器模式(Decorator)
“叠Buff”:给咖啡加糖、加奶、加巧克力,一层层包装,让基础咖啡变豪华版,但咖啡还是那杯咖啡。
动态包装对象以扩展功能,替代继承的灵活方案。
trait Coffee {
fn cost(&self) -> f64;
fn description(&self) -> String;
}
struct SimpleCoffee;
impl Coffee for SimpleCoffee {
fn cost(&self) -> f64 {
5.0
}
fn description(&self) -> String {
"Simple Coffee".to_string()
}
}
struct CoffeeDecorator {
coffee: Box
}
impl CoffeeDecorator {
fn new(coffee: Box
CoffeeDecorator { coffee }
}
}
impl Coffee for CoffeeDecorator {
fn cost(&self) -> f64 {
self.coffee.cost()
}
fn description(&self) -> String {
self.coffee.description()
}
}
struct MilkDecorator {
coffee: Box
}
impl MilkDecorator {
fn new(coffee: Box
MilkDecorator { coffee }
}
}
impl Coffee for MilkDecorator {
fn cost(&self) -> f64 {
self.coffee.cost() + 1.0
}
fn description(&self) -> String {
format!("{} + Milk", self.coffee.description())
}
}
fn main() {
let simple_coffee = Box::new(SimpleCoffee);
let milk_coffee = MilkDecorator::new(simple_coffee);
println!("Cost: {}, Description: {}", milk_coffee.cost(), milk_coffee.description());
// 输出: Cost: 6.0, Description: Simple Coffee + Milk
}
Ⅳ、享元模式(Flyweight)
“共享单车”:城市里有很多单车,但它们共享相同的属性(如品牌、型号),避免重复创建,减少资源占用。比如系统中很多对象有相同状态(如字体、颜色),可以把这些状态抽出来共享,节省内存。
共享细粒度对象以减少内存占用(如缓存常用字符串或配置)。
use std::sync::Arc;
use std::collections::HashMap;
struct Bike {
brand: Arc
model: Arc
}
impl Bike {
fn new(brand: Arc
Bike { brand, model }
}
}
struct BikeFactory {
brands: HashMap
models: HashMap
}
impl BikeFactory {
fn new() -> Self {
BikeFactory {
brands: HashMap::new(),
models: HashMap::new(),
}
}
fn get_brand(&mut self, brand: &str) -> Arc
self.brands.entry(brand.to_string()).or_insert_with(|| Arc::new(brand.to_string())).clone()
}
fn get_model(&mut self, model: &str) -> Arc
self.models.entry(model.to_string()).or_insert_with(|| Arc::new(model.to_string())).clone()
}
fn create_bike(&mut self, brand: &str, model: &str) -> Bike {
let brand = self.get_brand(brand);
let model = self.get_model(model);
Bike::new(brand, model)
}
}
fn main() {
let mut factory = BikeFactory::new();
let bike1 = factory.create_bike("Giant", "XTC");
let bike2 = factory.create_bike("Giant", "XTC");
println!("Bike1 brand: {}, model: {}", bike1.brand, bike1.model);
println!("Bike2 brand: {}, model: {}", bike2.brand, bike2.model);
// bike1 和 bike2 共享相同的 brand 和 model 字符串
}
Ⅴ、新类型模式(Newtype)
“避免混淆”:就像把普通数字“标签化”成“用户ID”,避免混淆普通数字和用户ID,增强类型安全。例如,UserId(1)和PostId(1)虽然都是1,但类型不同,不能混用,防止错误传递参数。
通过元组结构体包装基础类型,增强类型安全与行为扩展(如区分 UserId 和 PostId)。
struct UserId(u32);
struct PostId(u32);
fn get_user(id: UserId) {
println!("Getting user with ID: {}", id.0);
}
fn main() {
let user_id = UserId(1);
let post_id = PostId(2);
get_user(user_id); // 正确
// get_user(post_id); // 编译错误: expected UserId, found PostId
}
三、行为模式
Ⅰ、观察者模式(Observer)
“微信群通知”:老板在群里发消息,所有员工自动收到提醒(一个发布者,多个订阅者自动同步)。
一对多的依赖关系,状态变更时自动通知所有订阅者。
use std::cell::RefCell;
use std::rc::Rc;
trait Observer {
fn update(&self, message: &str);
}
struct Employee {
name: String,
}
impl Observer for Employee {
fn update(&self, message: &str) {
println!("{} received message: {}", self.name, message);
}
}
struct Boss {
observers: RefCell
}
impl Boss {
fn new() -> Self {
Boss { observers: RefCell::new(Vec::new()) }
}
fn add_observer(&self, observer: Rc
self.observers.borrow_mut().push(observer);
}
fn notify(&self, message: &str) {
for observer in self.observers.borrow().iter() {
observer.update(message);
}
}
}
fn main() {
let boss = Boss::new();
let employee1 = Rc::new(Employee { name: "Alice".to_string() });
let employee2 = Rc::new(Employee { name: "Bob".to_string() });
boss.add_observer(employee1);
boss.add_observer(employee2);
boss.notify("Meeting at 10 AM"); // Alice 和 Bob 都会收到通知
}
Ⅱ、访问者模式(Visitor)
想象一个博物馆(数据结构)中有不同类型的展品(元素类:油画、雕塑、古董)。当不同身份的访客(访问者:普通游客、修复专家、鉴定师)参观时,每类访客对同个展品会有不同的处理方式(操作)。展品不需要为每种访客修改自身,只需"接受"访问者即可执行对应操作。
将数据结构与数据操作分离,允许在不修改元素类的前提下添加新的操作。
// 1. 定义元素接口(展品)
trait Artifact {
fn accept(&self, visitor: &dyn Visitor);
}
// 2. 具体元素实现
struct Painting {
title: String,
artist: String,
}
impl Artifact for Painting {
fn accept(&self, visitor: &dyn Visitor) {
visitor.visit_painting(self);
}
}
struct Sculpture {
material: String,
height: u32,
}
impl Artifact for Sculpture {
fn accept(&self, visitor: &dyn Visitor) {
visitor.visit_sculpture(self);
}
}
// 3. 定义访问者接口(访客)
trait Visitor {
fn visit_painting(&self, painting: &Painting);
fn visit_sculpture(&self, sculpture: &Sculpture);
}
// 4. 具体访问者实现(普通游客)
struct Tourist;
impl Visitor for Tourist {
fn visit_painting(&self, painting: &Painting) {
println!(
"Tourist admiring '{}' by {}",
painting.title, painting.artist
);
}
fn visit_sculpture(&self, sculpture: &Sculpture) {
println!(
"Tourist taking photo of {} sculpture ({} cm)",
sculpture.material, sculpture.height
);
}
}
// 5. 具体访问者实现(修复专家)
struct Restorer;
impl Visitor for Restorer {
fn visit_painting(&self, painting: &Painting) {
println!(
"Restorer checking '{}' for canvas damage",
painting.title
);
}
fn visit_sculpture(&self, sculpture: &Sculpture) {
println!(
"Restorer cleaning {} surface",
sculpture.material
);
}
}
// 6. 博物馆(数据结构)
struct Museum {
artifacts: Vec
}
impl Museum {
fn new() -> Self {
Museum { artifacts: Vec::new() }
}
fn add_artifact(&mut self, artifact: Box
self.artifacts.push(artifact);
}
fn accept_visitor(&self, visitor: &dyn Visitor) {
for artifact in &self.artifacts {
artifact.accept(visitor);
}
}
}
fn main() {
// 创建博物馆并添加展品
let mut museum = Museum::new();
museum.add_artifact(Box::new(Painting {
title: "Starry Night".to_string(),
artist: "Van Gogh".to_string(),
}));
museum.add_artifact(Box::new(Sculpture {
material: "Marble".to_string(),
height: 150,
}));
// 不同访客参观
let tourist = Tourist;
let restorer = Restorer;
println!("===== Tourist visit =====");
museum.accept_visitor(&tourist);
println!("\n===== Restorer visit =====");
museum.accept_visitor(&restorer);
}
Ⅲ、命令模式(Command)
“点餐小票”:顾客点菜后,服务员把小票交给厨房,厨房按顺序做菜;支持撤销(退菜)或重做(加菜)。
命令模式的基本概念是,将(一连串的)动作分离为单独的对象,并且作为参数传递它们。
pub trait Migration {
fn execute(&self) -> &str;
fn rollback(&self) -> &str;
}
pub struct CreateTable;
impl Migration for CreateTable {
fn execute(&self) -> &str {
"create table"
}
fn rollback(&self) -> &str {
"drop table"
}
}
pub struct AddField;
impl Migration for AddField {
fn execute(&self) -> &str {
"add field"
}
fn rollback(&self) -> &str {
"remove field"
}
}
struct Schema {
commands: Vec
}
impl Schema {
fn new() -> Self {
Self { commands: vec![] }
}
fn add_migration(&mut self, cmd: Box
self.commands.push(cmd);
}
fn execute(&self) -> Vec<&str> {
self.commands.iter().map(|cmd| cmd.execute()).collect()
}
fn rollback(&self) -> Vec<&str> {
self.commands
.iter()
.rev() // reverse iterator's direction
.map(|cmd| cmd.rollback())
.collect()
}
}
fn main() {
let mut schema = Schema::new();
let cmd = Box::new(CreateTable);
schema.add_migration(cmd);
let cmd = Box::new(AddField);
schema.add_migration(cmd);
assert_eq!(vec!["create table", "add field"], schema.execute());
assert_eq!(vec!["remove field", "drop table"], schema.rollback());
}
Ⅳ、状态模式(State)
“自动售货机”:投币后按钮才亮(状态变化),没投币时按按钮无效(行为随状态改变)。
对象内部状态改变时,动态调整其行为表现。
trait State {
fn press_button(&self) -> String;
}
struct NoCoinState;
impl State for NoCoinState {
fn press_button(&self) -> String {
"No coin inserted".to_string()
}
}
struct HasCoinState;
impl State for HasCoinState {
fn press_button(&self) -> String {
"Dispensing product".to_string()
}
}
struct VendingMachine {
state: Box
}
impl VendingMachine {
fn new() -> Self {
VendingMachine { state: Box::new(NoCoinState) }
}
fn set_state(&mut self, state: Box
self.state = state;
}
fn press_button(&self) -> String {
self.state.press_button()
}
}
fn main() {
let mut machine = VendingMachine::new();
println!("{}", machine.press_button()); // 输出: No coin inserted
machine.set_state(Box::new(HasCoinState));
println!("{}", machine.press_button()); // 输出: Dispensing product
}
Ⅴ、责任链模式(Chain of Responsibility)
“请假审批”:员工请假先找组长,组长不能批再找经理,经理不能批再找总监。请求沿处理链传递,直到有对象处理。
请求沿处理链传递,直到有对象处理(如中间件管道)。
trait Handler {
fn handle_request(&self, request: &str) -> Option
fn set_next(&mut self, next: Box
}
struct TeamLeader {
next: Option
}
impl Handler for TeamLeader {
fn handle_request(&self, request: &str) -> Option
if request == "leave" {
Some("Team Leader approved".to_string())
} else if let Some(next) = &self.next {
next.handle_request(request)
} else {
None
}
}
fn set_next(&mut self, next: Box
self.next = Some(next);
}
}
struct Manager {
next: Option
}
impl Handler for Manager {
fn handle_request(&self, request: &str) -> Option
if request == "salary" {
Some("Manager approved".to_string())
} else if let Some(next) = &self.next {
next.handle_request(request)
} else {
None
}
}
fn set_next(&mut self, next: Box
self.next = Some(next);
}
}
fn main() {
let mut team_leader = TeamLeader { next: None };
let manager = Manager { next: None };
team_leader.set_next(Box::new(manager));
println!("{}", team_leader.handle_request("leave").unwrap()); // 输出: Team Leader approved
println!("{}", team_leader.handle_request("salary").unwrap()); // 输出: Manager approved
}
延伸阅读
Rust常用设计模式
设计模式 - Rust设计模式
当Rust邂逅GOF