快速复习常见设计模式(以Rust为例)

快速复习常见设计模式(以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> = Arc::new(Mutex::new(CEO::new("John")));

}

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 RemoteControl {

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) -> Self {

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) -> Self {

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, model: Arc) -> Self {

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