快速复习常见设计模式(以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<String>,
    gpu: Option<String>,
    ram: Option<String>,
}

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<dyn MilkTea>;
}

struct PearlMilkTeaFactory;

impl MilkTeaFactory for PearlMilkTeaFactory {
    fn create_milk_tea(&self) -> Box<dyn MilkTea> {
        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<dyn Furniture>;
    fn create_table(&self) -> Box<dyn Furniture>;
}

struct NordicFurnitureFactory;

impl FurnitureFactory for NordicFurnitureFactory {
    fn create_sofa(&self) -> Box<dyn Furniture> {
        Box::new(Sofa)
    }

    fn create_table(&self) -> Box<dyn Furniture> {
        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<Mutex<CEO>> = Arc::new(Mutex::new(CEO::new("John")));
}

fn get_ceo() -> Arc<Mutex<CEO>> {
    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<T: Device> {
    device: T,
}

impl<T: Device> RemoteControl<T> {
    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<dyn Coffee>,
}

impl CoffeeDecorator {
    fn new(coffee: Box<dyn Coffee>) -> 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<dyn Coffee>,
}

impl MilkDecorator {
    fn new(coffee: Box<dyn Coffee>) -> 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<String>,
    model: Arc<String>,
}

impl Bike {
    fn new(brand: Arc<String>, model: Arc<String>) -> Self {
        Bike { brand, model }
    }
}

struct BikeFactory {
    brands: HashMap<String, Arc<String>>,
    models: HashMap<String, Arc<String>>,
}

impl BikeFactory {
    fn new() -> Self {
        BikeFactory {
            brands: HashMap::new(),
            models: HashMap::new(),
        }
    }

    fn get_brand(&mut self, brand: &str) -> Arc<String> {
        self.brands.entry(brand.to_string()).or_insert_with(|| Arc::new(brand.to_string())).clone()
    }

    fn get_model(&mut self, model: &str) -> Arc<String> {
        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<Vec<Rc<dyn Observer>>>,
}

impl Boss {
    fn new() -> Self {
        Boss { observers: RefCell::new(Vec::new()) }
    }

    fn add_observer(&self, observer: Rc<dyn Observer>) {
        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<Box<dyn Artifact>>,
}
impl Museum {
    fn new() -> Self {
        Museum { artifacts: Vec::new() }
    }
    
    fn add_artifact(&mut self, artifact: Box<dyn Artifact>) {
        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<Box<dyn Migration>>,
}

impl Schema {
    fn new() -> Self {
        Self { commands: vec![] }
    }

    fn add_migration(&mut self, cmd: Box<dyn Migration>) {
        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<dyn State>,
}

impl VendingMachine {
    fn new() -> Self {
        VendingMachine { state: Box::new(NoCoinState) }
    }

    fn set_state(&mut self, state: Box<dyn State>) {
        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<String>;
    fn set_next(&mut self, next: Box<dyn Handler>);
}

struct TeamLeader {
    next: Option<Box<dyn Handler>>,
}

impl Handler for TeamLeader {
    fn handle_request(&self, request: &str) -> Option<String> {
        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<dyn Handler>) {
        self.next = Some(next);
    }
}

struct Manager {
    next: Option<Box<dyn Handler>>,
}

impl Handler for Manager {
    fn handle_request(&self, request: &str) -> Option<String> {
        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<dyn Handler>) {
        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
}

延伸阅读

  1. Rust常用设计模式
  2. 设计模式 - Rust设计模式
  3. 当Rust邂逅GOF
posted @ 2025-06-03 20:56  TfiyuenLau  阅读(114)  评论(0)    收藏  举报