rust-patterns 0.1.0

A modern Rust design patterns library with type-safe, efficient implementations
Documentation
use std::sync::{Arc, Weak};

/// 观察者 trait
///
/// 定义观察者必须实现的接口。观察者可以订阅主题的状态变化,
/// 并在状态更新时通过 `update` 方法接收通知。
///
/// # 类型参数
///
/// - `State`: 观察者关注的状态类型
/// - `Error`: 观察者处理更新时可能返回的错误类型
///
/// # 实现要求
///
/// 实现者需要提供具体的状态类型和错误类型,并实现 `update` 方法。
/// `update` 方法应该快速返回,避免阻塞通知过程。
///
/// # 线程安全
///
/// 实现者应确保 `update` 方法是线程安全的,因为可能从多个线程调用。
pub trait Observer {
    /// 观察者关注的状态类型
    ///
    /// 当主题状态变化时,会传递此类型的值给观察者。
    type State;

    /// 观察者处理更新时可能返回的错误类型
    ///
    /// 如果观察者处理更新失败,可以返回此类型的错误。
    type Error;

    /// 接收状态更新通知
    ///
    /// 当主题状态发生变化时调用此方法。实现者应该:
    ///
    /// 1. 处理传入的状态
    /// 2. 返回 `Ok(())` 表示处理成功
    /// 3. 返回 `Err(error)` 表示处理失败
    ///
    /// # 参数
    ///
    /// - `state`: 当前的主题状态引用
    ///
    /// # 返回值
    ///
    /// - `Ok(())`: 成功处理状态更新
    /// - `Err(Self::Error)`: 处理状态更新时发生错误
    ///
    /// # 错误处理
    ///
    /// 如果此方法返回错误,主题的 `notify` 方法会根据指定的通知策略
    /// 决定是否继续通知其他观察者。
    fn update(&self, state: &Self::State) -> Result<(), Self::Error>;
}

/// 通知策略
///
/// 定义当观察者处理更新失败时的行为。
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NotifyStrategy {
    /// 立即停止并返回错误
    ///
    /// 这是默认策略,当一个观察者失败时立即停止通知过程。
    StopOnError,

    /// 忽略错误并继续通知
    ///
    /// 即使某个观察者失败,也继续通知其他观察者。
    /// 错误会被忽略,继续执行。
    IgnoreError,
}

/// 主题(被观察者)
///
/// 管理一组观察者并在状态变化时通知它们。主题维护观察者的弱引用列表,
/// 避免强引用循环导致的内存泄漏。
///
/// # 类型参数
///
/// - `T`: 状态类型,必须与观察者的 `State` 类型匹配
/// - `E`: 错误类型,必须与观察者的 `Error` 类型匹配
///
/// # 设计特点
///
/// - **弱引用管理**: 使用 `Weak` 引用存储观察者,允许观察者在不再需要时被释放
/// - **自动清理**: 可选地自动清理已释放的观察者弱引用
/// - **通知策略**: 支持两种通知策略
pub struct Subject<T, E> {
    /// 观察者弱引用列表
    ///
    /// 使用弱引用避免循环引用。当观察者被释放时,
    /// 对应的弱引用会自动变为无效。
    observers: Vec<Weak<dyn Observer<State = T, Error = E>>>,
}

impl<T, E> Subject<T, E> {
    /// 创建新的主题实例
    ///
    /// # 返回值
    ///
    /// 返回一个空的主题,不包含任何观察者。
    pub fn new() -> Self {
        Self {
            observers: Vec::new(),
        }
    }

    /// 创建具有初始容量的主题实例
    ///
    /// # 参数
    ///
    /// - `capacity`: 初始容量,用于预分配内存
    ///
    /// # 返回值
    ///
    /// 返回一个具有指定初始容量的空主题。
    ///
    /// # 性能
    ///
    /// 预分配容量可以避免后续添加观察者时的多次内存重新分配,
    /// 当已知观察者数量时建议使用此方法。
    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            observers: Vec::with_capacity(capacity),
        }
    }

    /// 附加观察者
    ///
    /// 将观察者附加到主题。方法内部会将观察者的强引用转换为弱引用,
    /// 并确保不会重复添加相同的观察者。
    ///
    /// # 参数
    ///
    /// - `observer`: 要附加的观察者强引用
    ///
    /// # 注意
    ///
    /// - 使用 `Arc::downgrade` 将强引用转换为弱引用,避免循环引用
    /// - 使用 `Weak::ptr_eq` 检查观察者是否已存在,防止重复添加
    /// - 观察者将在下次调用 `notify` 方法时收到状态更新通知
    pub fn attach(&mut self, observer: Arc<dyn Observer<State = T, Error = E>>) {
        let weak = Arc::downgrade(&observer);
        if !self.observers.iter().any(|item| item.ptr_eq(&weak)) {
            self.observers.push(weak);
        }
    }

    /// 分离观察者
    ///
    /// 从主题中分离指定的观察者。分离后,该观察者将不再收到状态更新通知。
    ///
    /// # 参数
    ///
    /// - `observer`: 要分离的观察者强引用
    ///
    /// # 注意
    ///
    /// - 使用 `Arc::downgrade` 将强引用转换为弱引用进行匹配
    /// - 使用 `Weak::ptr_eq` 进行引用相等性比较
    /// - 如果观察者不存在于列表中,此方法不会有任何效果
    pub fn detach(&mut self, observer: Arc<dyn Observer<State = T, Error = E>>) {
        let weak = Arc::downgrade(&observer);
        self.observers.retain(|item| !item.ptr_eq(&weak));
    }

    /// 通知所有观察者
    ///
    /// 向所有有效的观察者发送状态更新通知。
    ///
    /// # 参数
    ///
    /// - `state`: 要通知的新状态引用
    /// - `error_strategy`: 通知策略,指定观察者失败时的行为
    ///   使用 `NotifyStrategy::StopOnError` 或 `NotifyStrategy::IgnoreError`
    ///
    /// # 返回值
    ///
    /// - `Ok(())`: 所有观察者都成功处理了更新,或错误被忽略
    /// - `Err(E)`: 某个观察者处理更新时返回了错误(当使用 `StopOnError` 策略时)
    ///
    /// # 通知策略
    ///
    /// 根据指定的通知策略决定行为:
    /// - `StopOnError`: 立即返回第一个错误,停止通知其他观察者
    /// - `IgnoreError`: 忽略错误,继续通知其他观察者,总是返回 `Ok(())`
    pub fn notify(&self, state: &T, strategy: NotifyStrategy) -> Result<(), E> {
        self.observers
            .iter()
            .flat_map(Weak::upgrade)
            .try_for_each(|observer| match observer.update(state) {
                Ok(()) => Ok(()),
                Err(e) => match strategy {
                    NotifyStrategy::StopOnError => Err(e),
                    NotifyStrategy::IgnoreError => Ok(()),
                },
            })
    }
}

impl<T, E> Default for Subject<T, E> {
    /// 创建默认的主题实例
    ///
    /// 等同于调用 `Subject::new()`。
    fn default() -> Self {
        Self::new()
    }
}