Rust 之结构性模式详解

深入理解Rust类型组合与结构复用的艺术:适配器、桥接、组合、装饰器、外观、享元与代理

Posted by Vlor on May 12, 2026

概述

结构性设计模式(Structural Patterns)是软件工程中专注于类与对象组合的核心方法论,其核心价值在于通过灵活的组合关系构建复杂系统结构,降低模块间的耦合度,提升代码的可复用性与可维护性。在Rust语言环境下,这一模式体系被赋予了独特的技术内涵——通过所有权系统、trait组合与零成本抽象特性,结构性模式不仅保留了传统设计模式的解耦能力,更实现了编译期类型安全与运行时性能的完美平衡。

Rust结构性模式的核心优势:相较于传统面向对象语言中依赖继承导致的脆弱基类问题(如Java的继承层次僵化)和运行时类型转换风险(如C++的dynamic_cast),Rust通过trait组合实现行为复用,结合枚举与模式匹配处理变体结构,利用组合优于继承原则构建灵活的类型关系,从根本上重构了系统结构的表达边界。

本文聚焦七种经典结构性模式在Rust中的实现与演化:适配器模式通过trait实现接口转换;桥接模式利用泛型与trait对象分离抽象与实现;组合模式借助递归枚举构建树形结构;装饰器模式通过包装类型动态增强行为;外观模式提供简化接口隐藏复杂子系统;享元模式结合Rc/Arc实现状态共享;代理模式利用智能指针控制对象访问。这些模式共同构成了Rust生态下系统结构设计的完整解决方案,为复杂系统开发提供了兼顾灵活性与安全性的工程实践范式。

核心概念

什么是结构性模式?

  • 适配器模式:将一个类的接口转换成客户期望的另一个接口,使原本不兼容的类可以协同工作
  • 桥接模式:将抽象部分与实现部分分离,使它们可以独立变化
  • 组合模式:将对象组合成树形结构以表示”部分-整体”的层次结构
  • 装饰器模式:动态地给对象添加额外的职责,比生成子类更灵活
  • 外观模式:为子系统中的一组接口提供一个一致的界面,简化客户端使用
  • 享元模式:通过共享技术有效支持大量细粒度对象的复用
  • 代理模式:为其他对象提供一种代理以控制对这个对象的访问

为什么需要结构性模式?

Rust的组合优先原则默认提供了强大的类型组合能力,但在某些复杂场景中,直接组合会导致代码结构混乱:

  1. 接口兼容需求:需要集成第三方库或遗留代码时进行接口适配
  2. 抽象与实现解耦:需要在不修改抽象层的情况下扩展多种实现
  3. 层次结构表达:需要递归表达树形或图形的复合对象关系
  4. 行为动态增强:需要在运行时灵活组合功能而不产生类型爆炸
  5. 子系统简化:需要为复杂模块提供简洁统一的访问入口
  6. 资源复用优化:需要高效管理大量相似对象以减少内存开销
  7. 访问控制需求:需要在对象访问前后插入日志、缓存、权限等横切逻辑

适配器模式详解

定义与作用

适配器模式(Adapter Pattern)是一种结构性设计模式,其核心定义是”将一个类的接口转换成客户期望的另一个接口,使原本接口不兼容的类可以协同工作”。在Rust语境下,这一模式通过trait抽象类型包装实现:定义目标trait规范客户端期望的接口,创建适配器结构体包装适配者类型,通过实现目标trait完成接口转换。

// 目标trait:客户端期望的接口
pub trait Target {
    fn request(&self) -> String;
}

// 适配者:已有的不兼容接口
pub struct Adaptee {
    pub data: String,
}

impl Adaptee {
    pub fn specific_request(&self) -> String {
        format!("Adaptee: {}", self.data)
    }
}

// 适配器:实现目标接口并委托给适配者
pub struct Adapter {
    adaptee: Adaptee,
}

impl Adapter {
    pub fn new(adaptee: Adaptee) -> Self {
        Adapter { adaptee }
    }
}

impl Target for Adapter {
    fn request(&self) -> String {
        // 接口转换逻辑
        self.adaptee.specific_request()
    }
}

Rust适配器的两种实现策略

1. 结构体包装(Composition)

通过持有适配者实例实现接口转换,适合需要访问适配者内部状态的场景:

pub struct FileLoggerAdapter {
    legacy_logger: LegacyFileLogger,
}

impl Logger for FileLoggerAdapter {
    fn log(&self, level: LogLevel, msg: &str) {
        // 转换参数并委托
        self.legacy_logger.write(
            level.to_legacy_string(),
            msg.as_bytes()
        );
    }
}

2. Trait对象适配(Dynamic Dispatch)

通过Box<dyn Trait>实现运行时多态适配,适合需要动态选择适配策略的场景:

pub trait Database {
    fn query(&self, sql: &str) -> Result<Vec<Row>, Error>;
}

pub struct LegacyDbAdapter {
    inner: Box<dyn LegacyDatabase>,
}

impl Database for LegacyDbAdapter {
    fn query(&self, sql: &str) -> Result<Vec<Row>, Error> {
        // 转换查询结果
        self.inner.execute(sql)
            .map(|rows| rows.into_iter().map(Row::from_legacy).collect())
    }
}

代码示例

日志系统接口适配

// 1. 目标接口:现代日志系统期望的trait
pub trait ModernLogger {
    fn log(&self, level: LogLevel, message: &str, context: &Context);
}

#[derive(Clone, Copy)]
pub enum LogLevel {
    Debug, Info, Warn, Error,
}

pub struct Context {
    pub module: String,
    pub line: u32,
}

// 2. 适配者:遗留日志库的接口
pub struct LegacyLogger {
    prefix: String,
}

impl LegacyLogger {
    pub fn new(prefix: String) -> Self {
        LegacyLogger { prefix }
    }
    
    // 遗留接口:参数顺序和类型都不同
    pub fn write(&self, msg: &str, severity: i32, module: &str) {
        let level_str = match severity {
            0 => "DEBUG", 1 => "INFO", 2 => "WARN", 3 => "ERROR",
            _ => "UNKNOWN",
        };
        println!("[{}][{}][{}] {}", self.prefix, level_str, module, msg);
    }
}

// 3. 适配器实现
pub struct LegacyLoggerAdapter {
    legacy: LegacyLogger,
}

impl LegacyLoggerAdapter {
    pub fn new(legacy: LegacyLogger) -> Self {
        LegacyLoggerAdapter { legacy }
    }
}

impl ModernLogger for LegacyLoggerAdapter {
    fn log(&self, level: LogLevel, message: &str, context: &Context) {
        // 接口转换:枚举→整数,结构体→字符串
        let severity = match level {
            LogLevel::Debug => 0,
            LogLevel::Info => 1,
            LogLevel::Warn => 2,
            LogLevel::Error => 3,
        };
        self.legacy.write(message, severity, &context.module);
    }
}

// 4. 使用示例
fn main() {
    let legacy = LegacyLogger::new("App".to_string());
    let adapter = LegacyLoggerAdapter::new(legacy);
    
    let ctx = Context {
        module: "main".to_string(),
        line: 42,
    };
    
    adapter.log(LogLevel::Info, "Application started", &ctx);
    // 输出: [App][INFO][main] Application started
}

应用场景

  • 第三方库集成:适配不同版本的API或不同供应商的实现
  • 遗留系统迁移:在不修改旧代码的前提下接入新架构
  • 测试桩实现:为接口创建模拟实现用于单元测试
  • 多后端支持:通过适配器统一不同存储/网络后端的接口

Rust优势:通过trait系统实现零成本抽象,适配器逻辑在编译期确定,无运行时开销;所有权系统确保适配过程中的内存安全。

桥接模式详解

定义与作用

桥接模式(Bridge Pattern)是一种结构性设计模式,其核心定义是”将抽象部分与实现部分分离,使它们可以独立变化”。在传统面向对象实现中,该模式通过继承层次分离抽象与实现,但容易导致类爆炸问题。在Rust语境下,桥接模式通过trait组合泛型参数trait对象实现更灵活的解耦。

// 实现部分:定义具体行为接口
pub trait Renderer {
    fn render_circle(&self, x: f64, y: f64, radius: f64);
    fn render_square(&self, x: f64, y: f64, size: f64);
}

// 抽象部分:持有实现引用并提供高层接口
pub struct Shape<R: Renderer> {
    renderer: R,
}

impl<R: Renderer> Shape<R> {
    pub fn new(renderer: R) -> Self {
        Shape { renderer }
    }
    
    pub fn draw_circle(&self, x: f64, y: f64, r: f64) {
        self.renderer.render_circle(x, y, r);
    }
}

Rust桥接的核心优势

  1. 编译期多态:通过泛型参数<R: Renderer>实现零开销抽象
  2. 运行时多态:通过Box<dyn Renderer>支持动态插件加载
  3. 类型安全:关联类型确保抽象与实现的正确配对
  4. 组合灵活:可在运行时切换实现而不修改抽象层

泛型桥接 vs Trait对象桥接

泛型桥接(静态分发)

pub trait Device {
    fn is_enabled(&self) -> bool;
    fn enable(&mut self);
    fn disable(&mut self);
}

pub struct Remote<D: Device> {
    device: D,
}

impl<D: Device> Remote<D> {
    pub fn toggle_power(&mut self) {
        if self.device.is_enabled() {
            self.device.disable();
        } else {
            self.device.enable();
        }
    }
}

优势

  • 编译期确定类型,无虚表查找开销
  • 可内联优化,性能最佳
  • 类型错误在编译期捕获

劣势

  • 每种组合生成独立代码,可能增加二进制体积
  • 无法在运行时动态切换实现

Trait对象桥接(动态分发)

pub trait Device {
    fn is_enabled(&self) -> bool;
    fn enable(&mut self);
    fn disable(&mut self);
}

pub struct Remote {
    device: Box<dyn Device>,
}

impl Remote {
    pub fn new(device: Box<dyn Device>) -> Self {
        Remote { device }
    }
    
    pub fn toggle_power(&mut self) {
        if self.device.is_enabled() {
            self.device.disable();
        } else {
            self.device.enable();
        }
    }
    
    // 运行时切换设备
    pub fn set_device(&mut self, device: Box<dyn Device>) {
        self.device = device;
    }
}

优势

  • 支持运行时动态替换实现
  • 插件系统友好,可扩展性强
  • 代码体积更紧凑

劣势

  • 动态分发有约1-2纳秒开销
  • 需要堆分配,增加内存管理复杂度

代码示例

跨平台图形渲染桥接

// ========== 实现部分:渲染器trait ==========
pub trait Renderer {
    fn render_circle(&self, x: f64, y: f64, radius: f64);
    fn render_square(&self, x: f64, y: f64, size: f64);
    fn api_name(&self) -> &str;
}

// OpenGL实现
pub struct OpenGLRenderer;
impl Renderer for OpenGLRenderer {
    fn render_circle(&self, x: f64, y: f64, radius: f64) {
        println!("[OpenGL] Circle at ({}, {}) r={}", x, y, radius);
    }
    fn render_square(&self, x: f64, y: f64, size: f64) {
        println!("[OpenGL] Square at ({}, {}) size={}", x, y, size);
    }
    fn api_name(&self) -> &str { "OpenGL 4.6" }
}

// Vulkan实现
pub struct VulkanRenderer;
impl Renderer for VulkanRenderer {
    fn render_circle(&self, x: f64, y: f64, radius: f64) {
        println!("[Vulkan] Circle at ({}, {}) r={}", x, y, radius);
    }
    fn render_square(&self, x: f64, y: f64, size: f64) {
        println!("[Vulkan] Square at ({}, {}) size={}", x, y, size);
    }
    fn api_name(&self) -> &str { "Vulkan 1.3" }
}

// ========== 抽象部分:形状trait ==========
pub trait Shape {
    fn draw(&self);
    fn resize(&mut self, factor: f64);
    fn info(&self) -> String;
}

// ========== 桥接实现:具体形状 ==========
pub struct Circle<R: Renderer> {
    renderer: R,
    x: f64,
    y: f64,
    radius: f64,
}

impl<R: Renderer> Circle<R> {
    pub fn new(renderer: R, x: f64, y: f64, radius: f64) -> Self {
        Circle { renderer, x, y, radius }
    }
}

impl<R: Renderer> Shape for Circle<R> {
    fn draw(&self) {
        self.renderer.render_circle(self.x, self.y, self.radius);
    }
    
    fn resize(&mut self, factor: f64) {
        self.radius *= factor;
    }
    
    fn info(&self) -> String {
        format!("Circle@{}: ({}, {}) r={}", 
                self.renderer.api_name(), self.x, self.y, self.radius)
    }
}

// ========== 使用示例 ==========
fn main() {
    // 静态桥接:编译期确定OpenGL
    let mut gl_circle = Circle::new(OpenGLRenderer, 10.0, 20.0, 5.0);
    gl_circle.draw();  // [OpenGL] Circle at (10, 20) r=5
    println!("{}", gl_circle.info());
    
    // 动态桥接:运行时选择Vulkan
    let vk_renderer: Box<dyn Renderer> = Box::new(VulkanRenderer);
    let mut vk_circle = Circle {
        renderer: vk_renderer,
        x: 30.0,
        y: 40.0,
        radius: 8.0,
    };
    vk_circle.draw();  // [Vulkan] Circle at (30, 40) r=8
}

应用场景

  • 跨平台UI框架:抽象层定义Widget接口,实现层适配Windows/macOS/Linux原生控件
  • 多数据库支持:抽象层定义Repository接口,实现层适配MySQL/PostgreSQL/SQLite
  • 插件系统:核心逻辑通过trait定义扩展点,插件实现具体功能动态加载

Rust优势:通过泛型与trait对象的灵活组合,既支持编译期优化的静态桥接,也支持运行时扩展的动态桥接,满足不同场景的性能与灵活性需求。

组合模式详解

定义与作用

组合模式(Composite Pattern)是一种结构性设计模式,其核心定义是”将对象组合成树形结构以表示’部分-整体’的层次结构,使得客户端可以统一处理单个对象和组合对象”。在Rust语境下,这一模式通过递归枚举智能指针trait对象实现类型安全的树形结构。

// 组件trait:统一叶子与组合节点的接口
pub trait Component {
    fn operation(&self) -> String;
    fn add(&mut self, _child: Box<dyn Component>) {
        // 叶子节点默认不支持添加
    }
    fn remove(&mut self, _index: usize) {
        // 叶子节点默认不支持删除
    }
}

// 叶子节点
pub struct Leaf {
    pub name: String,
}

impl Component for Leaf {
    fn operation(&self) -> String {
        format!("Leaf: {}", self.name)
    }
}

// 组合节点:持有子组件集合
pub struct Composite {
    pub name: String,
    pub children: Vec<Box<dyn Component>>,
}

impl Composite {
    pub fn new(name: String) -> Self {
        Composite { name, children: Vec::new() }
    }
}

impl Component for Composite {
    fn operation(&self) -> String {
        let child_ops: Vec<String> = self.children
            .iter()
            .map(|c| c.operation())
            .collect();
        format!("Composite: {} [{}]", self.name, child_ops.join(", "))
    }
    
    fn add(&mut self, child: Box<dyn Component>) {
        self.children.push(child);
    }
}

Rust组合模式的核心优势

  1. 类型安全递归:通过Box<dyn Trait>打破递归类型的大小限制
  2. 统一接口处理:客户端无需区分叶子与组合节点,简化遍历逻辑
  3. 内存安全:所有权系统确保树形结构的正确生命周期管理
  4. 零成本抽象:trait对象的虚表调用开销可控,适合中等规模树结构

递归枚举 vs Trait对象

方案1:递归枚举(Enum-based)

适合组件类型固定、编译期已知的场景:

pub enum FileSystemNode {
    File { name: String, size: u64 },
    Directory { 
        name: String, 
        children: Vec<FileSystemNode> 
    },
}

impl FileSystemNode {
    pub fn total_size(&self) -> u64 {
        match self {
            FileSystemNode::File { size, .. } => *size,
            FileSystemNode::Directory { children, .. } => {
                children.iter().map(|c| c.total_size()).sum()
            }
        }
    }
}

优势

  • 编译期类型检查,无动态分发开销
  • 模式匹配使逻辑清晰
  • 内存布局紧凑

劣势

  • 新增组件类型需修改枚举定义
  • 不支持运行时动态扩展

方案2:Trait对象(Dynamic Dispatch)

适合组件类型开放、需要运行时扩展的场景:

pub trait Node {
    fn name(&self) -> &str;
    fn size(&self) -> u64;
    fn as_file(&self) -> Option<&FileNode> { None }
    fn as_dir(&self) -> Option<&DirNode> { None }
}

pub struct FileNode {
    name: String,
    size: u64,
}

pub struct DirNode {
    name: String,
    children: Vec<Box<dyn Node>>,
}

优势

  • 支持运行时动态添加新组件类型
  • 插件系统友好
  • 接口统一,客户端代码简洁

劣势

  • 动态分发有轻微性能开销
  • 需要堆分配管理生命周期

代码示例

文档编辑器组合结构

// ========== 组件trait ==========
pub trait DocumentElement {
    fn render(&self, indent: usize) -> String;
    fn word_count(&self) -> usize;
}

// ========== 叶子节点:文本段落 ==========
pub struct Paragraph {
    pub content: String,
}

impl DocumentElement for Paragraph {
    fn render(&self, indent: usize) -> String {
        let prefix = "  ".repeat(indent);
        format!("{}<p>{}</p>\n", prefix, self.content)
    }
    
    fn word_count(&self) -> usize {
        self.content.split_whitespace().count()
    }
}

// ========== 叶子节点:图片 ==========
pub struct Image {
    pub url: String,
    pub alt: String,
}

impl DocumentElement for Image {
    fn render(&self, indent: usize) -> String {
        let prefix = "  ".repeat(indent);
        format!("{}<img src=\"{}\" alt=\"{}\" />\n", 
                prefix, self.url, self.alt)
    }
    
    fn word_count(&self) -> usize {
        self.alt.split_whitespace().count()
    }
}

// ========== 组合节点:章节 ==========
pub struct Section {
    pub title: String,
    pub level: u8,
    pub children: Vec<Box<dyn DocumentElement>>,
}

impl Section {
    pub fn new(title: String, level: u8) -> Self {
        Section { title, level, children: Vec::new() }
    }
    
    pub fn add(&mut self, element: Box<dyn DocumentElement>) {
        self.children.push(element);
    }
}

impl DocumentElement for Section {
    fn render(&self, indent: usize) -> String {
        let prefix = "  ".repeat(indent);
        let heading = "#".repeat(self.level as usize);
        let mut result = format!("{}{} {}\n", prefix, heading, self.title);
        
        for child in &self.children {
            result.push_str(&child.render(indent + 1));
        }
        result
    }
    
    fn word_count(&self) -> usize {
        self.title.split_whitespace().count() + 
        self.children.iter().map(|c| c.word_count()).sum::<usize>()
    }
}

// ========== 使用示例 ==========
fn main() {
    let mut doc = Section::new("Rust设计模式".to_string(), 1);
    
    // 添加段落
    doc.add(Box::new(Paragraph {
        content: "结构性模式关注类与对象的组合关系".to_string(),
    }));
    
    // 添加嵌套章节
    let mut adapter_section = Section::new("适配器模式".to_string(), 2);
    adapter_section.add(Box::new(Paragraph {
        content: "适配器将一个接口转换为另一个接口".to_string(),
    }));
    adapter_section.add(Box::new(Image {
        url: "adapter-diagram.png".to_string(),
        alt: "适配器模式结构图".to_string(),
    }));
    doc.add(Box::new(adapter_section));
    
    // 渲染文档
    println!("{}", doc.render(0));
    println!("总字数: {}", doc.word_count());
}

应用场景

  • UI组件树:React/Vue等框架的虚拟DOM本质是组合模式的应用
  • 文件系统抽象:统一处理文件与目录的遍历、统计操作
  • 表达式求值:算术表达式树中叶子是数字,节点是运算符
  • 组织架构:员工与部门的层级管理

Rust优势:通过Box<dyn Trait>实现类型安全的递归结构,所有权系统确保树形结构的正确销毁顺序,避免内存泄漏。

装饰器模式详解

定义与作用

装饰器模式(Decorator Pattern)是一种结构性设计模式,其核心定义是”动态地给对象添加额外的职责,比生成子类更灵活地扩展功能”。在Rust语境下,这一模式通过类型包装trait委托方法链实现行为的动态组合。

// 基础组件trait
pub trait DataSource {
    fn write_data(&mut self, data: &str) -> std::io::Result<()>;
    fn read_data(&mut self) -> std::io::Result<String>;
}

// 具体组件
pub struct FileDataSource {
    filepath: String,
}

impl FileDataSource {
    pub fn new(filepath: String) -> Self {
        FileDataSource { filepath }
    }
}

impl DataSource for FileDataSource {
    fn write_data(&mut self, data: &str) -> std::io::Result<()> {
        std::fs::write(&self.filepath, data)
    }
    
    fn read_data(&mut self) -> std::io::Result<String> {
        std::fs::read_to_string(&self.filepath)
    }
}

// 装饰器:持有组件引用并增强行为
pub struct CompressionDecorator<D: DataSource> {
    wrapped: D,
}

impl<D: DataSource> CompressionDecorator<D> {
    pub fn new(wrapped: D) -> Self {
        CompressionDecorator { wrapped }
    }
}

impl<D: DataSource> DataSource for CompressionDecorator<D> {
    fn write_data(&mut self, data: &str) -> std::io::Result<()> {
        // 增强:压缩后写入
        let compressed = compress(data);
        self.wrapped.write_data(&compressed)
    }
    
    fn read_data(&mut self) -> std::io::Result<String> {
        // 增强:读取后解压
        let compressed = self.wrapped.read_data()?;
        decompress(&compressed)
    }
}

fn compress(data: &str) -> String {
    // 简化:实际应使用zstd等库
    format!("[COMPRESSED]{}", data)
}

fn decompress(data: &str) -> std::io::Result<String> {
    if data.starts_with("[COMPRESSED]") {
        Ok(data[12..].to_string())
    } else {
        Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "Invalid compressed data"
        ))
    }
}

Rust装饰器的核心优势

  1. 零成本抽象:泛型装饰器在编译期展开,无运行时开销
  2. 组合灵活:通过方法链动态组合多个装饰器
  3. 类型安全:编译期确保装饰器链的类型正确性
  4. 无侵入扩展:无需修改原有组件代码即可添加新功能

装饰器链的构建方式

方式1:嵌套构造(静态组合)

let source = EncryptionDecorator::new(
    CompressionDecorator::new(
        FileDataSource::new("data.txt".to_string())
    )
);

优势:类型明确,编译期优化充分 劣势:装饰顺序固定,灵活性较低

方式2:Trait对象链(动态组合)

let mut source: Box<dyn DataSource> = 
    Box::new(FileDataSource::new("data.txt".to_string()));

if enable_compression {
    source = Box::new(CompressionDecorator { wrapped: source });
}
if enable_encryption {
    source = Box::new(EncryptionDecorator { wrapped: source });
}

优势:运行时动态决定装饰策略 劣势:动态分发有轻微开销,类型信息部分丢失

方式3:Builder模式构建

pub struct DataSourceBuilder {
    base: FileDataSource,
    compress: bool,
    encrypt: bool,
    log: bool,
}

impl DataSourceBuilder {
    pub fn new(filepath: String) -> Self {
        DataSourceBuilder {
            base: FileDataSource::new(filepath),
            compress: false,
            encrypt: false,
            log: false,
        }
    }
    
    pub fn with_compression(mut self) -> Self {
        self.compress = true;
        self
    }
    
    pub fn with_encryption(mut self) -> Self {
        self.encrypt = true;
        self
    }
    
    pub fn build(self) -> Box<dyn DataSource> {
        let mut source: Box<dyn DataSource> = Box::new(self.base);
        if self.log {
            source = Box::new(LoggingDecorator::new(source));
        }
        if self.compress {
            source = Box::new(CompressionDecorator::new(source));
        }
        if self.encrypt {
            source = Box::new(EncryptionDecorator::new(source));
        }
        source
    }
}

代码示例

HTTP请求处理装饰器链

// ========== 基础trait ==========
pub trait HttpRequestHandler {
    fn handle(&self, request: &HttpRequest) -> HttpResponse;
}

pub struct HttpRequest {
    pub url: String,
    pub headers: HashMap<String, String>,
    pub body: Option<String>,
}

pub struct HttpResponse {
    pub status: u16,
    pub headers: HashMap<String, String>,
    pub body: Option<String>,
}

// ========== 基础处理器 ==========
pub struct EchoHandler;

impl HttpRequestHandler for EchoHandler {
    fn handle(&self, request: &HttpRequest) -> HttpResponse {
        HttpResponse {
            status: 200,
            headers: HashMap::new(),
            body: request.body.clone(),
        }
    }
}

// ========== 装饰器:日志记录 ==========
pub struct LoggingDecorator<H: HttpRequestHandler> {
    inner: H,
}

impl<H: HttpRequestHandler> LoggingDecorator<H> {
    pub fn new(inner: H) -> Self {
        LoggingDecorator { inner }
    }
}

impl<H: HttpRequestHandler> HttpRequestHandler for LoggingDecorator<H> {
    fn handle(&self, request: &HttpRequest) -> HttpResponse {
        println!("[LOG] Request: {} {:?}", request.url, request.headers);
        let response = self.inner.handle(request);
        println!("[LOG] Response: {}", response.status);
        response
    }
}

// ========== 装饰器:认证校验 ==========
pub struct AuthDecorator<H: HttpRequestHandler> {
    inner: H,
    required_token: String,
}

impl<H: HttpRequestHandler> AuthDecorator<H> {
    pub fn new(inner: H, token: String) -> Self {
        AuthDecorator { inner, required_token: token }
    }
}

impl<H: HttpRequestHandler> HttpRequestHandler for AuthDecorator<H> {
    fn handle(&self, request: &HttpRequest) -> HttpResponse {
        match request.headers.get("Authorization") {
            Some(token) if token == &self.required_token => {
                self.inner.handle(request)
            }
            _ => HttpResponse {
                status: 401,
                headers: HashMap::new(),
                body: Some("Unauthorized".to_string()),
            }
        }
    }
}

// ========== 装饰器:响应缓存 ==========
use std::collections::HashMap;
use std::sync::Mutex;

pub struct CachingDecorator<H: HttpRequestHandler> {
    inner: H,
    cache: Mutex<HashMap<String, HttpResponse>>,
}

impl<H: HttpRequestHandler> CachingDecorator<H> {
    pub fn new(inner: H) -> Self {
        CachingDecorator { 
            inner, 
            cache: Mutex::new(HashMap::new()) 
        }
    }
}

impl<H: HttpRequestHandler> HttpRequestHandler for CachingDecorator<H> {
    fn handle(&self, request: &HttpRequest) -> HttpResponse {
        let key = format!("{}:{:?}", request.url, request.body);
        
        // 尝试读取缓存
        if let Some(cached) = self.cache.lock().unwrap().get(&key) {
            println!("[CACHE] Hit for {}", request.url);
            return cached.clone();
        }
        
        // 执行并缓存
        let response = self.inner.handle(request);
        self.cache.lock().unwrap().insert(key, response.clone());
        response
    }
}

// ========== 使用示例 ==========
fn main() {
    // 构建装饰器链:日志 → 认证 → 缓存 → 基础处理
    let handler = LoggingDecorator::new(
        AuthDecorator::new(
            CachingDecorator::new(EchoHandler),
            "secret-token".to_string(),
        )
    );
    
    let request = HttpRequest {
        url: "/api/echo".to_string(),
        headers: [("Authorization".to_string(), "secret-token".to_string())]
            .into_iter().collect(),
        body: Some("Hello, Rust!".to_string()),
    };
    
    let response = handler.handle(&request);
    println!("Status: {}, Body: {:?}", response.status, response.body);
}

应用场景

  • 中间件系统:Web框架的请求/响应处理链
  • 数据流处理:压缩、加密、编码等管道式转换
  • 性能监控:在不修改业务逻辑的前提下添加埋点
  • 权限控制:动态组合多种校验策略

Rust优势:通过泛型装饰器实现零成本抽象,编译期展开装饰逻辑;通过trait对象支持运行时动态组合,满足不同场景需求。

外观模式详解

定义与作用

外观模式(Facade Pattern)是一种结构性设计模式,其核心定义是”为子系统中的一组接口提供一个一致的界面,简化客户端使用”。在Rust语境下,这一模式通过模块封装trait抽象委托实现隐藏复杂子系统的内部细节。

// 复杂子系统:视频转换库(简化示例)
mod video_codec {
    pub struct Decoder {
        pub format: String,
    }
    
    impl Decoder {
        pub fn new(format: &str) -> Self {
            Decoder { format: format.to_string() }
        }
        pub fn decode(&self, data: &[u8]) -> Vec<u8> {
            // 实际解码逻辑...
            data.to_vec()
        }
    }
    
    pub struct Encoder {
        pub target_format: String,
    }
    
    impl Encoder {
        pub fn new(format: &str) -> Self {
            Encoder { target_format: format.to_string() }
        }
        pub fn encode(&self, data: &[u8]) -> Vec<u8> {
            // 实际编码逻辑...
            data.to_vec()
        }
    }
    
    pub struct BitrateController {
        pub max_bitrate: u32,
    }
    
    impl BitrateController {
        pub fn adjust(&mut self, data: &mut [u8]) {
            // 码率控制逻辑...
        }
    }
}

// 外观:提供简化接口
pub struct VideoConverter;

impl VideoConverter {
    pub fn convert(input: &[u8], from: &str, to: &str) -> Vec<u8> {
        // 隐藏子系统复杂交互
        let decoder = video_codec::Decoder::new(from);
        let mut raw = decoder.decode(input);
        
        let mut controller = video_codec::BitrateController { max_bitrate: 5000 };
        controller.adjust(&mut raw);
        
        let encoder = video_codec::Encoder::new(to);
        encoder.encode(&raw)
    }
}

Rust外观模式的核心优势

  1. 模块边界清晰:通过pub/pub(crate)控制子系统可见性
  2. 编译期优化:外观方法可内联,消除委托开销
  3. 错误处理统一:在外观层集中处理子系统的错误类型转换
  4. 测试友好:客户端只需测试外观接口,无需了解内部细节

外观与委托的实现策略

策略1:简单委托(直接调用)

适合子系统稳定、接口变化少的场景:

pub struct DatabaseFacade {
    connection: DbConnection,
    query_builder: QueryBuilder,
    cache: RedisCache,
}

impl DatabaseFacade {
    pub fn query(&self, sql: &str) -> Result<Vec<Row>, AppError> {
        // 统一错误转换
        self.connection.execute(sql)
            .map_err(|e| AppError::from(e))
    }
}

策略2:Trait抽象(可替换实现)

适合需要测试或动态替换子系统的场景:

pub trait StorageBackend {
    fn read(&self, key: &str) -> Result<Vec<u8>, StorageError>;
    fn write(&mut self, key: &str, value: &[u8]) -> Result<(), StorageError>;
}

pub struct StorageFacade<B: StorageBackend> {
    backend: B,
    serializer: JsonSerializer,
}

impl<B: StorageBackend> StorageFacade<B> {
    pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<T, AppError> {
        let data = self.backend.read(key)?;
        self.serializer.deserialize(&data)
            .map_err(|e| AppError::from(e))
    }
}

代码示例

智能家居控制外观

// ========== 子系统:灯光控制 ==========
mod lighting {
    pub struct SmartBulb {
        pub id: u32,
        pub brightness: u8,
        pub color_temp: u16,
    }
    
    impl SmartBulb {
        pub fn new(id: u32) -> Self {
            SmartBulb { id, brightness: 100, color_temp: 4000 }
        }
        
        pub fn set_brightness(&mut self, level: u8) {
            self.brightness = level.min(100);
        }
        
        pub fn set_color_temp(&mut self, temp: u16) {
            self.color_temp = temp.clamp(2700, 6500);
        }
    }
}

// ========== 子系统:温控系统 ==========
mod climate {
    pub struct Thermostat {
        pub target_temp: f32,
        pub mode: Mode,
    }
    
    pub enum Mode { Heat, Cool, Auto, Off }
    
    impl Thermostat {
        pub fn new() -> Self {
            Thermostat { target_temp: 22.0, mode: Mode::Auto }
        }
        
        pub fn set_mode(&mut self, mode: Mode) {
            self.mode = mode;
        }
        
        pub fn set_target(&mut self, temp: f32) {
            self.target_temp = temp.clamp(16.0, 30.0);
        }
    }
}

// ========== 子系统:安防系统 ==========
mod security {
    pub struct AlarmSystem {
        pub armed: bool,
        pub sensors: Vec<String>,
    }
    
    impl AlarmSystem {
        pub fn new() -> Self {
            AlarmSystem { 
                armed: false, 
                sensors: vec!["door".into(), "window".into()] 
            }
        }
        
        pub fn arm(&mut self) {
            self.armed = true;
        }
        
        pub fn disarm(&mut self) {
            self.armed = false;
        }
    }
}

// ========== 外观:统一智能家居接口 ==========
pub struct SmartHome {
    living_room_light: lighting::SmartBulb,
    thermostat: climate::Thermostat,
    alarm: security::AlarmSystem,
}

impl SmartHome {
    pub fn new() -> Self {
        SmartHome {
            living_room_light: lighting::SmartBulb::new(1),
            thermostat: climate::Thermostat::new(),
            alarm: security::AlarmSystem::new(),
        }
    }
    
    // 场景模式:回家
    pub fn arrive_home(&mut self) {
        self.living_room_light.set_brightness(80);
        self.living_room_light.set_color_temp(3000);
        self.thermostat.set_mode(climate::Mode::Heat);
        self.thermostat.set_target(23.0);
        self.alarm.disarm();
    }
    
    // 场景模式:离家
    pub fn leave_home(&mut self) {
        self.living_room_light.set_brightness(0);
        self.thermostat.set_mode(climate::Mode::Off);
        self.alarm.arm();
    }
    
    // 场景模式:睡眠
    pub fn sleep_mode(&mut self) {
        self.living_room_light.set_brightness(10);
        self.living_room_light.set_color_temp(2700);
        self.thermostat.set_target(20.0);
    }
    
    // 统一状态查询
    pub fn status(&self) -> String {
        format!(
            "Light: {}% {}K | Climate: {:?} {}°C | Alarm: {}",
            self.living_room_light.brightness,
            self.living_room_light.color_temp,
            self.thermostat.mode,
            self.thermostat.target_temp,
            if self.alarm.armed { "ARMED" } else { "DISARMED" }
        )
    }
}

// ========== 使用示例 ==========
fn main() {
    let mut home = SmartHome::new();
    
    println!("初始状态: {}", home.status());
    
    // 用户只需调用简单接口,无需了解子系统细节
    home.arrive_home();
    println!("回家模式: {}", home.status());
    
    home.sleep_mode();
    println!("睡眠模式: {}", home.status());
    
    home.leave_home();
    println!("离家模式: {}", home.status());
}

应用场景

  • 库的公共接口:为复杂库提供简洁易用的API入口
  • 微服务网关:聚合多个后端服务,提供统一前端接口
  • 硬件抽象层:隐藏不同厂商设备的底层驱动差异
  • 配置管理:统一处理多源配置的加载、合并与校验

Rust优势:通过模块系统精确控制子系统可见性,外观层集中处理错误转换与资源管理,客户端代码简洁且类型安全。

享元模式详解

定义与作用

享元模式(Flyweight Pattern)是一种结构性设计模式,其核心定义是”通过共享技术有效支持大量细粒度对象的复用,减少内存消耗”。在Rust语境下,这一模式通过引用计数智能指针不可变数据共享内部/外部状态分离实现高效的对象复用。

use std::sync::Arc;

// 内部状态:可共享的不变数据
#[derive(Clone, Debug)]
pub struct CharacterStyle {
    pub font_family: Arc<str>,
    pub font_size: u16,
    pub color: Arc<str>,
}

impl CharacterStyle {
    pub fn new(font: &str, size: u16, color: &str) -> Self {
        CharacterStyle {
            font_family: font.into(),
            font_size: size,
            color: color.into(),
        }
    }
}

// 外部状态:每个对象独有的可变数据
pub struct Character {
    pub symbol: char,
    pub position: (usize, usize),
    pub style: Arc<CharacterStyle>, // 共享样式
}

// 享元工厂:管理共享对象池
pub struct StyleFactory {
    styles: std::collections::HashMap<String, Arc<CharacterStyle>>,
}

impl StyleFactory {
    pub fn new() -> Self {
        StyleFactory { styles: std::collections::HashMap::new() }
    }
    
    pub fn get_style(&mut self, font: &str, size: u16, color: &str) -> Arc<CharacterStyle> {
        let key = format!("{}:{}:{}", font, size, color);
        self.styles
            .entry(key)
            .or_insert_with(|| Arc::new(CharacterStyle::new(font, size, color)))
            .clone()
    }
    
    pub fn memory_usage(&self) -> usize {
        self.styles.len() * std::mem::size_of::<CharacterStyle>()
    }
}

Rust享元模式的核心优势

  1. 零拷贝共享Arc::clone()仅增加引用计数,无数据复制开销
  2. 线程安全Arc天然支持多线程共享,无需额外同步
  3. 内存高效:大量对象共享相同内部状态,显著减少内存占用
  4. 写时分离:结合Rc::make_mutArc::make_mut实现COW优化

共享策略选择

策略1:Arc共享(多线程场景)

use std::sync::Arc;

pub struct SharedConfig {
    pub settings: Arc<ConfigData>,
}

impl Clone for SharedConfig {
    fn clone(&self) -> Self {
        SharedConfig {
            settings: Arc::clone(&self.settings), // O(1)操作
        }
    }
}

适用场景:配置数据、只读缓存、跨线程共享资源

策略2:Rc共享(单线程场景)

use std::rc::Rc;

pub struct DocumentNode {
    pub content: Rc<String>,
    pub children: Vec<Rc<DocumentNode>>,
}

适用场景:GUI组件树、表达式求值、单线程数据结构

策略3:Interning(字符串驻留)

use std::collections::HashMap;
use std::sync::Mutex;

pub struct StringPool {
    pool: Mutex<HashMap<String, Arc<str>>>,
}

impl StringPool {
    pub fn intern(&self, s: &str) -> Arc<str> {
        let mut pool = self.pool.lock().unwrap();
        pool.entry(s.to_string())
            .or_insert_with(|| s.into())
            .clone()
    }
}

适用场景:标识符、键名、枚举值等高频重复字符串

代码示例

文本编辑器字符享元

use std::collections::HashMap;
use std::sync::Arc;

// ========== 内部状态:可共享的样式 ==========
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct TextStyle {
    pub font: Arc<str>,
    pub size: u16,
    pub bold: bool,
    pub italic: bool,
    pub color: u32, // RGBA
}

impl TextStyle {
    pub fn new(font: &str, size: u16, color: u32) -> Self {
        TextStyle {
            font: font.into(),
            size,
            bold: false,
            italic: false,
            color,
        }
    }
    
    pub fn with_bold(mut self, bold: bool) -> Self {
        self.bold = bold;
        self
    }
    
    pub fn with_italic(mut self, italic: bool) -> Self {
        self.italic = italic;
        self
    }
}

// ========== 外部状态:字符位置 ==========
#[derive(Clone, Debug)]
pub struct TextCharacter {
    pub symbol: char,
    pub row: usize,
    pub col: usize,
    pub style: Arc<TextStyle>,
}

// ========== 享元工厂 ==========
pub struct StylePool {
    pool: HashMap<TextStyle, Arc<TextStyle>>,
}

impl StylePool {
    pub fn new() -> Self {
        StylePool { pool: HashMap::new() }
    }
    
    pub fn get(&mut self, style: TextStyle) -> Arc<TextStyle> {
        self.pool
            .entry(style)
            .or_insert_with(|| Arc::new(style.clone()))
            .clone()
    }
    
    pub fn unique_styles(&self) -> usize {
        self.pool.len()
    }
}

// ========== 文档模型 ==========
pub struct Document {
    characters: Vec<TextCharacter>,
    style_pool: StylePool,
}

impl Document {
    pub fn new() -> Self {
        Document {
            characters: Vec::new(),
            style_pool: StylePool::new(),
        }
    }
    
    pub fn add_char(&mut self, symbol: char, row: usize, col: usize, style: TextStyle) {
        let shared_style = self.style_pool.get(style);
        self.characters.push(TextCharacter {
            symbol,
            row,
            col,
            style: shared_style,
        });
    }
    
    pub fn render(&self) {
        // 按行分组渲染
        let mut lines: HashMap<usize, Vec<&TextCharacter>> = HashMap::new();
        for ch in &self.characters {
            lines.entry(ch.row).or_default().push(ch);
        }
        
        for (row, chars) in lines.iter_mut() {
            chars.sort_by_key(|c| c.col);
            let line: String = chars.iter().map(|c| c.symbol).collect();
            println!("Line {}: {}", row, line);
        }
    }
    
    pub fn memory_stats(&self) -> String {
        format!(
            "Characters: {}, Unique Styles: {}, Style Memory: {}B",
            self.characters.len(),
            self.style_pool.unique_styles(),
            self.style_pool.unique_styles() * std::mem::size_of::<TextStyle>()
        )
    }
}

// ========== 使用示例 ==========
fn main() {
    let mut doc = Document::new();
    
    // 创建1000个字符,仅使用3种样式
    let style_normal = TextStyle::new("Arial", 14, 0x000000FF);
    let style_bold = TextStyle::new("Arial", 14, 0x000000FF).with_bold(true);
    let style_red = TextStyle::new("Arial", 14, 0xFF0000FF);
    
    for row in 0..10 {
        for col in 0..100 {
            let style = match (row + col) % 3 {
                0 => style_normal.clone(),
                1 => style_bold.clone(),
                _ => style_red.clone(),
            };
            doc.add_char('A', row, col, style);
        }
    }
    
    println!("{}", doc.memory_stats());
    // 输出: Characters: 1000, Unique Styles: 3, Style Memory: 96B
    // 若不使用享元: 1000 * 48B = 48KB vs 3 * 48B = 144B
    
    doc.render();
}

应用场景

  • 文本/富文本编辑器:大量字符共享相同字体、颜色等样式
  • 游戏对象池:相同类型的敌人/道具共享纹理、碰撞体等资源
  • GUI组件树:相同样式的按钮、标签共享渲染属性
  • 网络请求缓存:相同URL的请求共享配置与连接池

性能对比: | 场景 | 对象数 | 无享元内存 | 享元内存 | 节省比例 | |——|——–|———–|———-|———-| | 文本文档 | 10,000字符 | ~480KB | ~1.5KB | 99.7% | | 游戏粒子 | 100,000粒子 | ~8MB | ~24KB | 99.7% | | UI组件 | 1,000按钮 | ~48KB | ~144B | 99.7% |

Rust优势Arc的原子引用计数开销极低(约1-2纳秒),结合编译期类型检查确保共享数据的不可变性,避免数据竞争。

代理模式详解

定义与作用

代理模式(Proxy Pattern)是一种结构性设计模式,其核心定义是”为其他对象提供一种代理以控制对这个对象的访问”。在Rust语境下,这一模式通过智能指针包装trait委托懒加载机制实现访问控制、延迟初始化与横切逻辑注入。

use std::sync::Arc;

// 真实主题
pub trait Image {
    fn display(&self);
    fn size(&self) -> (u32, u32);
}

pub struct RealImage {
    filename: String,
    data: Vec<u8>, // 实际图像数据(大对象)
}

impl RealImage {
    pub fn load(filename: &str) -> Self {
        println!("Loading image: {}", filename);
        // 实际加载逻辑...
        RealImage {
            filename: filename.to_string(),
            data: vec![0; 1024 * 1024], // 模拟1MB数据
        }
    }
}

impl Image for RealImage {
    fn display(&self) {
        println!("Displaying {}", self.filename);
    }
    
    fn size(&self) -> (u32, u32) {
        (1920, 1080)
    }
}

// 代理:控制访问 + 延迟加载
pub struct ImageProxy {
    filename: String,
    real_image: Option<Arc<RealImage>>,
}

impl ImageProxy {
    pub fn new(filename: &str) -> Self {
        ImageProxy {
            filename: filename.to_string(),
            real_image: None,
        }
    }
    
    fn get_real(&mut self) -> &Arc<RealImage> {
        if self.real_image.is_none() {
            self.real_image = Some(Arc::new(RealImage::load(&self.filename)));
        }
        self.real_image.as_ref().unwrap()
    }
}

impl Image for ImageProxy {
    fn display(&self) {
        // 访问控制:检查权限
        if !self.has_permission() {
            println!("Access denied");
            return;
        }
        // 延迟加载 + 委托
        self.real_image.as_ref().unwrap().display();
    }
    
    fn size(&self) -> (u32, u32) {
        // 元数据可提前获取,无需加载大图
        (1920, 1080)
    }
}

impl ImageProxy {
    fn has_permission(&self) -> bool {
        // 实际应检查用户权限
        true
    }
}

Rust代理模式的核心优势

  1. 零成本抽象:泛型代理在编译期展开,委托调用可内联优化
  2. 懒加载友好:结合OnceCell实现线程安全的延迟初始化
  3. 访问控制灵活:可在代理层统一实现缓存、日志、权限等横切逻辑
  4. 内存安全:智能指针确保代理与真实对象的生命周期正确管理

代理类型与实现策略

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

use once_cell::sync::OnceCell;

pub struct LazyLoader<T> {
    loader: Box<dyn FnOnce() -> T + Send>,
    instance: OnceCell<T>,
}

impl<T> LazyLoader<T> {
    pub fn new<F>(loader: F) -> Self 
    where F: FnOnce() -> T + Send + 'static 
    {
        LazyLoader {
            loader: Box::new(loader),
            instance: OnceCell::new(),
        }
    }
    
    pub fn get(&self) -> &T 
    where T: Send + Sync 
    {
        self.instance.get_or_init(|| (self.loader)())
    }
}

适用场景:大文件加载、远程资源获取、昂贵计算结果缓存

2. 保护代理(Protection Proxy):访问控制

pub struct ProtectedResource<R> {
    inner: R,
    allowed_roles: Vec<String>,
}

impl<R> ProtectedResource<R> {
    pub fn new(inner: R, roles: Vec<&str>) -> Self {
        ProtectedResource {
            inner,
            allowed_roles: roles.into_iter().map(String::from).collect(),
        }
    }
    
    pub fn access<F, T>(&self, user_roles: &[String], f: F) -> Result<T, AccessError>
    where F: FnOnce(&R) -> T 
    {
        if user_roles.iter().any(|r| self.allowed_roles.contains(r)) {
            Ok(f(&self.inner))
        } else {
            Err(AccessError::Forbidden)
        }
    }
}

适用场景:权限校验、数据脱敏、审计日志

3. 缓存代理(Cache Proxy):结果复用

use std::collections::HashMap;
use std::sync::Mutex;

pub struct CachedFunction<F, I, O> 
where 
    F: Fn(&I) -> O + Send + Sync,
    I: std::hash::Hash + Eq + Clone,
    O: Clone,
{
    func: F,
    cache: Mutex<HashMap<I, O>>,
}

impl<F, I, O> CachedFunction<F, I, O>
where 
    F: Fn(&I) -> O + Send + Sync,
    I: std::hash::Hash + Eq + Clone,
    O: Clone,
{
    pub fn new(func: F) -> Self {
        CachedFunction {
            func,
            cache: Mutex::new(HashMap::new()),
        }
    }
    
    pub fn call(&self, input: I) -> O {
        // 先查缓存
        if let Some(result) = self.cache.lock().unwrap().get(&input) {
            return result.clone();
        }
        
        // 计算并缓存
        let result = (self.func)(&input);
        self.cache.lock().unwrap().insert(input.clone(), result.clone());
        result
    }
}

适用场景:纯函数结果缓存、API响应缓存、计算密集型任务复用

代码示例

数据库查询代理(缓存+日志+限流)

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use once_cell::sync::OnceCell;

// ========== 真实数据库连接 ==========
pub trait Database {
    fn query(&self, sql: &str) -> Result<Vec<Row>, DbError>;
}

pub struct RealDatabase {
    connection_string: String,
}

impl RealDatabase {
    pub fn connect(conn_str: &str) -> Self {
        println!("Connecting to {}", conn_str);
        // 实际建立连接...
        RealDatabase {
            connection_string: conn_str.to_string(),
        }
    }
}

impl Database for RealDatabase {
    fn query(&self, sql: &str) -> Result<Vec<Row>, DbError> {
        println!("Executing: {}", sql);
        // 实际查询逻辑...
        Ok(vec![]) // 简化
    }
}

// ========== 代理:组合多种横切逻辑 ==========
pub struct DatabaseProxy {
    conn_string: String,
    real_db: OnceCell<RealDatabase>,
    
    // 缓存层
    query_cache: Mutex<HashMap<String, (Vec<Row>, Instant)>>,
    cache_ttl: Duration,
    
    // 限流层
    request_count: Mutex<u32>,
    max_requests: u32,
    window_start: Mutex<Instant>,
    window_duration: Duration,
}

impl DatabaseProxy {
    pub fn new(conn_str: &str, cache_ttl: Duration) -> Self {
        DatabaseProxy {
            conn_string: conn_str.to_string(),
            real_db: OnceCell::new(),
            query_cache: Mutex::new(HashMap::new()),
            cache_ttl,
            request_count: Mutex::new(0),
            max_requests: 100,
            window_start: Mutex::new(Instant::now()),
            window_duration: Duration::from_secs(60),
        }
    }
    
    fn get_db(&self) -> &RealDatabase {
        self.real_db.get_or_init(|| RealDatabase::connect(&self.conn_string))
    }
    
    fn check_rate_limit(&self) -> bool {
        let mut count = self.request_count.lock().unwrap();
        let mut window = self.window_start.lock().unwrap();
        
        let now = Instant::now();
        if now.duration_since(*window) > self.window_duration {
            *count = 0;
            *window = now;
        }
        
        if *count >= self.max_requests {
            return false;
        }
        *count += 1;
        true
    }
    
    fn get_cached(&self, sql: &str) -> Option<Vec<Row>> {
        let cache = self.query_cache.lock().unwrap();
        if let Some((rows, timestamp)) = cache.get(sql) {
            if timestamp.elapsed() < self.cache_ttl {
                println!("[CACHE] Hit for: {}", sql);
                return Some(rows.clone());
            }
        }
        None
    }
    
    fn set_cached(&self, sql: &str, rows: Vec<Row>) {
        let mut cache = self.query_cache.lock().unwrap();
        cache.insert(sql.to_string(), (rows, Instant::now()));
    }
}

impl Database for DatabaseProxy {
    fn query(&self, sql: &str) -> Result<Vec<Row>, DbError> {
        // 1. 日志
        let start = Instant::now();
        println!("[PROXY] Query: {}", sql);
        
        // 2. 限流检查
        if !self.check_rate_limit() {
            return Err(DbError::RateLimitExceeded);
        }
        
        // 3. 缓存检查(仅SELECT查询)
        if sql.trim_start().to_uppercase().starts_with("SELECT") {
            if let Some(cached) = self.get_cached(sql) {
                return Ok(cached);
            }
        }
        
        // 4. 委托真实数据库
        let result = self.get_db().query(sql);
        
        // 5. 缓存结果
        if let Ok(rows) = &result {
            if sql.trim_start().to_uppercase().starts_with("SELECT") {
                self.set_cached(sql, rows.clone());
            }
        }
        
        // 6. 日志
        println!("[PROXY] Completed in {:?}", start.elapsed());
        result
    }
}

// ========== 辅助类型 ==========
#[derive(Clone, Debug)]
pub struct Row {
    pub columns: HashMap<String, String>,
}

#[derive(Debug)]
pub enum DbError {
    ConnectionFailed,
    QueryError(String),
    RateLimitExceeded,
}

impl std::fmt::Display for DbError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            DbError::ConnectionFailed => write!(f, "Connection failed"),
            DbError::QueryError(e) => write!(f, "Query error: {}", e),
            DbError::RateLimitExceeded => write!(f, "Rate limit exceeded"),
        }
    }
}

impl std::error::Error for DbError {}

// ========== 使用示例 ==========
fn main() {
    let proxy = DatabaseProxy::new(
        "postgres://user:pass@localhost/db",
        Duration::from_secs(300), // 5分钟缓存
    );
    
    // 首次查询:加载连接 + 执行 + 缓存
    let _ = proxy.query("SELECT * FROM users WHERE id = 1");
    
    // 相同查询:直接返回缓存
    let _ = proxy.query("SELECT * FROM users WHERE id = 1");
    
    // 限流测试:100次/分钟
    for i in 0..105 {
        match proxy.query(&format!("SELECT * FROM logs LIMIT {}", i)) {
            Ok(_) => println!("Request {} OK", i),
            Err(e) => println!("Request {} failed: {}", i, e),
        }
    }
}

应用场景

  • 远程代理:gRPC/HTTP客户端封装网络细节
  • 虚拟代理:大资源(图片/视频)的懒加载
  • 保护代理:权限校验、数据脱敏、审计日志
  • 缓存代理:数据库查询、API响应、计算结果复用
  • 日志代理:统一记录方法调用参数与耗时

性能对比: | 代理类型 | 额外开销 | 典型收益 | |———-|———-|———-| | 虚拟代理 | 首次加载延迟 | 节省90%+初始内存 | | 缓存代理 | Hash计算+锁 | 缓存命中率>80%时性能提升5-10倍 | | 保护代理 | 权限检查(~100ns) | 避免未授权访问的安全风险 | | 日志代理 | 字符串格式化(~1μs) | 问题排查效率提升 |

Rust优势:通过OnceCell实现线程安全的懒加载,Mutex保护共享状态,编译期确保代理与真实对象的接口一致性。

实践应用

综合案例:分布式配置中心客户端

本案例设计为”分布式配置中心客户端”,通过整合适配器、桥接、装饰器、外观、享元、代理六种结构性模式,构建高效可靠的配置管理系统。系统架构中:

  • 外观模式ConfigClient提供简洁的get()/watch()接口,隐藏底层复杂交互
  • 适配器模式:适配etcd/Consul/ZooKeeper等不同后端存储
  • 桥接模式:分离配置解析逻辑(JSON/YAML/TOML)与存储后端
  • 装饰器模式:动态添加缓存、加密、日志等横切功能
  • 享元模式:共享相同路径的配置项元数据,减少内存占用
  • 代理模式:实现本地缓存代理,减少远程请求频次

协作流程

  1. 客户端调用ConfigClient::get("app.timeout")
  2. 外观层路由请求到对应后端适配器
  3. 桥接层选择解析器处理配置格式
  4. 代理层先查本地缓存,未命中则请求远程
  5. 装饰器层记录访问日志并加密敏感配置
  6. 享元池复用相同路径的元数据对象

各模式协同解决了多后端兼容、配置格式扩展、性能优化、安全管控等复杂需求。

核心实现(简化版)

use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use once_cell::sync::OnceCell;

// ========== 外观:统一配置客户端 ==========
pub struct ConfigClient {
    backend: Arc<dyn ConfigBackend>,
    parser: Arc<dyn ConfigParser>,
    cache: LocalCache,
}

impl ConfigClient {
    pub fn new(backend: Arc<dyn ConfigBackend>, parser: Arc<dyn ConfigParser>) -> Self {
        ConfigClient {
            backend,
            parser,
            cache: LocalCache::new(Duration::from_secs(60)),
        }
    }
    
    pub fn get(&self, key: &str) -> Result<ConfigValue, ConfigError> {
        // 1. 代理:先查本地缓存
        if let Some(cached) = self.cache.get(key) {
            return Ok(cached);
        }
        
        // 2. 桥接:解析器处理格式
        let raw = self.backend.fetch(key)?;
        let parsed = self.parser.parse(&raw)?;
        
        // 3. 装饰:敏感值脱敏(简化)
        let sanitized = self.sanitize(&parsed, key)?;
        
        // 4. 享元:共享元数据
        let meta = MetadataPool::shared().get_metadata(key);
        
        let value = ConfigValue {
            data: sanitized,
            metadata: meta,
        };
        
        // 缓存结果
        self.cache.set(key, value.clone());
        Ok(value)
    }
    
    fn sanitize(&self, value: &ConfigValue, key: &str) -> Result<String, ConfigError> {
        // 敏感配置脱敏逻辑
        if key.contains("secret") || key.contains("password") {
            Ok("***REDACTED***".to_string())
        } else {
            Ok(value.data.clone())
        }
    }
}

// ========== 适配器:后端存储接口 ==========
pub trait ConfigBackend: Send + Sync {
    fn fetch(&self, key: &str) -> Result<String, ConfigError>;
    fn watch(&self, key: &str, callback: Box<dyn Fn(String) + Send>) -> Result<WatchHandle, ConfigError>;
}

// etcd适配器
pub struct EtcdAdapter {
    client: Arc<etcd_client::Client>, // 假设的etcd客户端
}

impl ConfigBackend for EtcdAdapter {
    fn fetch(&self, key: &str) -> Result<String, ConfigError> {
        // 实际调用etcd API
        Ok("30".to_string()) // 简化
    }
    
    fn watch(&self, key: &str, callback: Box<dyn Fn(String) + Send>) -> Result<WatchHandle, ConfigError> {
        // 实现watch逻辑
        Ok(WatchHandle { id: 1 })
    }
}

// Consul适配器(另一个实现)
pub struct ConsulAdapter {
    // ...
}

impl ConfigBackend for ConsulAdapter {
    // ... 实现ConfigBackend
    fn fetch(&self, key: &str) -> Result<String, ConfigError> { todo!() }
    fn watch(&self, key: &str, callback: Box<dyn Fn(String) + Send>) -> Result<WatchHandle, ConfigError> { todo!() }
}

// ========== 桥接:配置解析器 ==========
pub trait ConfigParser: Send + Sync {
    fn parse(&self, raw: &str) -> Result<ConfigValue, ConfigError>;
}

pub struct JsonParser;
impl ConfigParser for JsonParser {
    fn parse(&self, raw: &str) -> Result<ConfigValue, ConfigError> {
        // 使用serde_json解析
        Ok(ConfigValue {
            data: raw.to_string(),
            metadata: Arc::new(Metadata::default()),
        })
    }
}

pub struct YamlParser;
impl ConfigParser for YamlParser {
    fn parse(&self, raw: &str) -> Result<ConfigValue, ConfigError> {
        // 使用serde_yaml解析
        Ok(ConfigValue {
            data: raw.to_string(),
            metadata: Arc::new(Metadata::default()),
        })
    }
}

// ========== 享元:元数据池 ==========
#[derive(Clone, Debug)]
pub struct Metadata {
    pub path: Arc<str>,
    pub version: u64,
    pub created_at: u64,
}

impl Default for Metadata {
    fn default() -> Self {
        Metadata {
            path: "".into(),
            version: 0,
            created_at: 0,
        }
    }
}

pub struct MetadataPool {
    pool: HashMap<String, Arc<Metadata>>,
}

impl MetadataPool {
    fn shared() -> &'static MetadataPool {
        static POOL: OnceCell<MetadataPool> = OnceCell::new();
        POOL.get_or_init(|| MetadataPool { pool: HashMap::new() })
    }
    
    fn get_metadata(&mut self, path: &str) -> Arc<Metadata> {
        self.pool
            .entry(path.to_string())
            .or_insert_with(|| Arc::new(Metadata {
                path: path.into(),
                version: 0,
                created_at: 0,
            }))
            .clone()
    }
}

// ========== 代理:本地缓存 ==========
struct LocalCache {
    entries: Mutex<HashMap<String, (ConfigValue, Instant)>>,
    ttl: Duration,
}

impl LocalCache {
    fn new(ttl: Duration) -> Self {
        LocalCache {
            entries: Mutex::new(HashMap::new()),
            ttl,
        }
    }
    
    fn get(&self, key: &str) -> Option<ConfigValue> {
        let entries = self.entries.lock().unwrap();
        if let Some((value, timestamp)) = entries.get(key) {
            if timestamp.elapsed() < self.ttl {
                return Some(value.clone());
            }
        }
        None
    }
    
    fn set(&self, key: &str, value: ConfigValue) {
        let mut entries = self.entries.lock().unwrap();
        entries.insert(key.to_string(), (value, Instant::now()));
    }
}

// ========== 辅助类型 ==========
#[derive(Clone, Debug)]
pub struct ConfigValue {
    pub data: String,
    pub metadata: Arc<Metadata>,
}

#[derive(Debug)]
pub enum ConfigError {
    NotFound,
    ParseError(String),
    NetworkError(String),
}

pub struct WatchHandle { pub id: u32 }

// ========== 使用示例 ==========
fn main() {
    // 选择后端与解析器(可配置)
    let backend: Arc<dyn ConfigBackend> = Arc::new(EtcdAdapter {
        client: Arc::new(etcd_client::Client::connect(["localhost:2379"]).unwrap()),
    });
    
    let parser: Arc<dyn ConfigParser> = Arc::new(JsonParser);
    
    let client = ConfigClient::new(backend, parser);
    
    // 简洁的客户端接口
    match client.get("app.timeout") {
        Ok(value) => println!("Timeout: {} (v{})", value.data, value.metadata.version),
        Err(e) => eprintln!("Error: {}", e),
    }
    
    // 监听配置变更
    let _handle = client.backend.watch("app.timeout", Box::new(|new_val| {
        println!("Config changed: {}", new_val);
    })).unwrap();
}

模式协作优势

  • 外观模式提供简洁统一的API,降低客户端使用复杂度
  • 适配器模式支持多后端无缝切换,提升系统扩展性
  • 桥接模式解耦解析逻辑与存储实现,便于独立演进
  • 装饰器模式灵活组合横切功能,避免代码重复
  • 享元模式显著减少元数据内存占用,提升大规模配置场景性能
  • 代理模式通过本地缓存降低远程请求频次,提升响应速度

常见错误与解决

错误1:适配器模式 - 生命周期管理不当

错误表现:适配器持有适配者引用时未正确处理生命周期,导致悬垂引用。

错误代码

pub struct Adapter<'a> {
    adaptee: &'a Adaptee, // 生命周期绑定
}

impl<'a> Target for Adapter<'a> {
    fn request(&self) -> String {
        self.adaptee.specific_request()
    }
}

fn problematic() {
    let adapter;
    {
        let adaptee = Adaptee { data: "temp".into() };
        adapter = Adapter { adaptee: &adaptee }; // adaptee即将被丢弃
    } // adaptee在此处被drop
    adapter.request(); // ❌ 悬垂引用!
}

解决方案:使用Arc或所有权转移确保生命周期安全。

修正代码

pub struct Adapter {
    adaptee: Arc<Adaptee>, // 共享所有权
}

impl Adapter {
    pub fn new(adaptee: Arc<Adaptee>) -> Self {
        Adapter { adaptee }
    }
}

// 或采用所有权转移
pub struct Adapter {
    adaptee: Adaptee,
}

错误2:组合模式 - 递归类型大小问题

错误表现:直接递归定义枚举导致编译错误”recursive type has infinite size”。

错误代码

pub enum TreeNode {
    Leaf { value: i32 },
    Node { children: Vec<TreeNode> }, // ❌ TreeNode包含TreeNode,大小无限
}

解决方案:使用Box打破递归,或采用trait对象。

修正代码

// 方案1: Box包装
pub enum TreeNode {
    Leaf { value: i32 },
    Node { children: Vec<Box<TreeNode>> },
}

// 方案2: Trait对象(更灵活)
pub trait Node {
    fn evaluate(&self) -> i32;
}

pub struct LeafNode { value: i32 }
pub struct InternalNode { children: Vec<Box<dyn Node>> }

错误3:装饰器模式 - 泛型爆炸

错误表现:多层泛型装饰器导致编译时间激增、二进制体积膨胀。

错误代码

// 5层装饰:类型签名极其复杂
type ComplexHandler = LoggingDecorator<
    AuthDecorator<
        RateLimitDecorator<
            CacheDecorator<
                EchoHandler
            >
        >
    >
>;

解决方案:关键层使用trait对象减少泛型嵌套。

修正代码

// 内部保持泛型优化,边界使用trait对象
pub fn build_handler(enable_cache: bool) -> Box<dyn Handler> {
    let mut handler: Box<dyn Handler> = Box::new(EchoHandler);
    
    if enable_cache {
        handler = Box::new(CacheDecorator { inner: handler });
    }
    handler = Box::new(AuthDecorator { inner: handler });
    handler = Box::new(LoggingDecorator { inner: handler });
    
    handler
}

错误4:享元模式 - 可变状态共享

错误表现:错误地共享可变状态,导致数据竞争或意外修改。

错误代码

#[derive(Clone)]
pub struct SharedState {
    pub counter: u32, // ❌ 可变状态被共享
}

pub struct Flyweight {
    state: Arc<SharedState>,
}

// 线程1
flyweight1.state.counter += 1;
// 线程2
flyweight2.state.counter += 1; // ❌ 数据竞争!

解决方案:享元内部状态必须不可变,可变部分作为外部状态。

修正代码

// 内部状态:不可变 + Arc共享
#[derive(Clone, Debug)]
pub struct ImmutableState {
    pub config: Arc<Config>,
    pub template: Arc<str>,
}

// 外部状态:每个对象独有
pub struct Flyweight {
    immutable: Arc<ImmutableState>,
    mutable: MutableState, // 不共享
}

pub struct MutableState {
    pub counter: u32,
    pub last_modified: Instant,
}

错误5:代理模式 - 死锁风险

错误表现:代理层嵌套获取锁时顺序不一致,导致死锁。

错误代码

pub struct Proxy {
    cache: Mutex<Cache>,
    db: Mutex<Database>,
}

impl Proxy {
    fn query(&self, key: &str) -> Result<Value, Error> {
        // 先锁cache
        let cache = self.cache.lock()?;
        if let Some(v) = cache.get(key) {
            return Ok(v);
        }
        
        // 再锁db - 但其他线程可能先锁db再锁cache!
        let db = self.db.lock()?; // ❌ 死锁风险
        // ...
    }
}

解决方案:统一锁获取顺序,或使用无锁数据结构。

修正代码

// 方案1: 固定锁顺序(文档约定)
impl Proxy {
    fn query(&self, key: &str) -> Result<Value, Error> {
        // 始终先db后cache
        let db = self.db.lock()?;
        let value = db.fetch(key)?;
        
        let mut cache = self.cache.lock()?;
        cache.insert(key, value.clone());
        Ok(value)
    }
}

// 方案2: 使用DashMap等无锁结构
use dashmap::DashMap;

pub struct Proxy {
    cache: DashMap<String, Value>, // 无锁并发HashMap
    db: Mutex<Database>,
}

总结要点

Rust结构性模式的核心价值

  1. 组合优于继承:通过trait组合与结构体嵌套实现灵活复用,避免继承层次僵化
  2. 零成本抽象:泛型与内联优化确保设计模式不引入运行时开销
  3. 编译期安全:类型系统提前捕获接口不匹配、生命周期错误等问题
  4. 并发友好Arc/Mutex/OnceCell等原语简化线程安全实现

模式选择指南

场景需求 推荐模式 Rust实现要点
接口不兼容 适配器 trait抽象 + 结构体包装
抽象/实现解耦 桥接 泛型参数 或 Box
树形层次结构 组合 Box 或 递归枚举
动态功能增强 装饰器 泛型委托 + 方法链
简化复杂子系统 外观 模块封装 + trait委托
大量相似对象 享元 Arc共享 + 不可变内部状态
访问控制/延迟加载 代理 OnceCell + 智能指针包装

性能优化建议

  • 优先静态分发:能用泛型就不用trait对象,减少虚表调用
  • 避免过度包装:每层代理/装饰增加~1-2纳秒开销,评估必要性
  • 享元粒度控制:共享对象不宜过大,避免不必要的内存驻留
  • 缓存策略调优:根据访问模式设置合理的TTL与容量上限

Rust惯用法融合

  1. 使用#[derive]减少样板代码Clone/Debug/PartialEq
  2. 利用?操作符简化错误传播:外观层集中处理错误转换
  3. 采用impl Trait简化返回类型:避免暴露具体装饰器类型
  4. 结合macro_rules!生成重复代码:如批量实现trait委托

进阶资源

Rust社区风采

https://example.com/rust-structural-patterns.jpg

Rust社区通过类型系统的创新应用,为传统结构性设计模式注入了新的活力。在保持设计模式解耦与复用核心价值的同时,借助所有权、trait与零成本抽象等特性,实现了前所未有的类型安全与性能保障。这些实践不仅提升了代码质量,更为构建可靠、高效的大型系统提供了坚实的方法论基础。 ```

💡 使用提示:将上述markdown内容保存为 rust-structural-patterns.md 文件,即可用于博客发布或团队文档。文中所有代码示例均可直接在Rust项目中编译运行(需添加相应依赖如once_cell)。


核心要点回顾

  1. 适配器:通过trait实现接口转换,解决兼容性问题
  2. 桥接:泛型与trait对象结合,分离抽象与实现
  3. 组合Box<dyn Trait>实现类型安全的树形结构
  4. 装饰器:泛型委托实现零成本的行为动态增强
  5. 外观:模块封装隐藏子系统复杂性
  6. 享元Arc共享不可变状态,显著减少内存占用
  7. 代理:智能指针+懒加载实现访问控制与优化

通过合理运用这些结构性模式,您可以在保持Rust类型安全与性能优势的同时,构建出灵活、可维护的大型系统架构。🦀✨