项目结构:

//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : process_dtos.rs
//! DTO(数据传输对象)定义
//!
//! 用于跨层(表现层 → 接口层 → 应用层 → 领域层)传递数据,仅承载数据、无业务逻辑。
//! – `ProcessRequestDto`:业务流程执行请求
//! – `ProcessResponseDto`:业务流程执行响应
use crate::domain::entities::jewelry::Jewelry;
/// 业务流程执行请求 DTO
///
/// `department` / `operator` 为溯源扩展字段(预留给审计场景),
/// 当前演示中同事自行声明所属部门,未读取该两字段。
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ProcessRequestDto {
/// 流程类型标识(如 PROCUREMENT / DESIGN / PRODUCTION 等)
pub process_type: String,
/// 关联珠宝实体
pub jewelry: Jewelry,
/// 发起部门(如 采购部 / 设计部 / 生产部 等)
pub department: String,
/// 操作人(如 Mediator 中介者 / 具体岗位名称)
pub operator: String,
}
impl ProcessRequestDto {
/// 创建业务流程执行请求 DTO
///
/// # 参数
/// – `process_type`:流程类型标识
/// – `jewelry`:关联珠宝
/// – `department`:发起部门
/// – `operator`:操作人
///
/// # 返回
/// 请求 DTO
pub fn new(process_type: &str, jewelry: Jewelry, department: &str, operator: &str) -> Self {
Self {
process_type: process_type.to_string(),
jewelry,
department: department.to_string(),
operator: operator.to_string(),
}
}
}
/// 业务流程执行响应 DTO
///
/// `instance_id` 预留给需要回传实例编号的上层调用方,演示中编号已写入日志。
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ProcessResponseDto {
/// 流程实例编号(如 PROCUREMENT-000001)
pub instance_id: String,
/// 流程名称(中文)
pub process_name: String,
/// 是否成功
pub success: bool,
/// 结果消息(成功摘要或失败原因)
pub message: String,
}
impl ProcessResponseDto {
/// 创建流程响应 DTO
///
/// # 参数
/// – `instance_id`:流程实例编号
/// – `process_name`:流程名称
/// – `success`:是否成功
/// – `message`:结果消息
///
/// # 返回
/// 响应 DTO
pub fn new(instance_id: &str, process_name: &str, success: bool, message: &str) -> Self {
Self {
instance_id: instance_id.to_string(),
process_name: process_name.to_string(),
success,
message: message.to_string(),
}
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : jewelry.rs
//! 珠宝行业领域实体定义
//!
//! 包含:
//! – `Jewelry`:珠宝业务实体(贯穿采购→设计→生产→质检→包装→物流→财务→
//! 营销→销售等全部流程)
//! – `ProcessOutcome`:业务流程执行产出(同事业务执行的返回载体)
//! – 全局自增流水号生成器(线程安全,用于生成唯一编号)
use std::sync::atomic::{AtomicU64, Ordering};
/// 全局自增流水号(线程安全,跨线程共享生成唯一序号)
static NEXT_SEQUENCE: AtomicU64 = AtomicU64::new(1);
/// 获取下一个业务流水号(原子递增,高并发安全)
///
/// # 返回
/// 下一个自增序号
pub fn next_sequence() -> u64 {
NEXT_SEQUENCE.fetch_add(1, Ordering::SeqCst)
}
/// 珠宝业务实体(领域实体,跨全流程共享)
///
/// `id` / `status` / `with_status` 为领域状态演进预留(如 `PROCURED`→`DELIVERED`),
/// 当前演示以值传递共享珠宝实体,未对状态字段做持久化演进,属预留 API。
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Jewelry {
/// 珠宝编号(如 JWL-000001)
pub id: String,
/// 珠宝名称
pub name: String,
/// 材质(黄金 / 铂金 / 钻石 / K金 / 银)
pub material: String,
/// 重量(克)
pub weight_grams: f64,
/// 零售价(元)
pub price: f64,
/// 当前状态(INIT 初始 / PROCURED 已采购 / DESIGNED 已设计 /
/// PRODUCED 已生产 / INSPECTED 已质检 / PACKED 已包装 / DELIVERED 已发货)
pub status: String,
}
impl Jewelry {
/// 创建珠宝实体
///
/// # 参数
/// – `name`:珠宝名称
/// – `material`:材质
/// – `weight_grams`:重量(克)
/// – `price`:零售价(元)
///
/// # 返回
/// 初始状态为 `INIT` 的珠宝实体
pub fn new(name: &str, material: &str, weight_grams: f64, price: f64) -> Self {
Self {
id: format!("JWL-{:06}", next_sequence()),
name: name.to_string(),
material: material.to_string(),
weight_grams,
price,
status: "INIT".to_string(),
}
}
/// 更新珠宝状态(返回新实体,保持不可变语义便于并发共享)
///
/// # 参数
/// – `status`:新状态
///
/// # 返回
/// 更新状态后的珠宝实体副本
#[allow(dead_code)]
pub fn with_status(&self, status: &str) -> Self {
let mut cloned = self.clone();
cloned.status = status.to_string();
cloned
}
}
/// 业务流程执行产出(同事业务执行的返回载体)
///
/// `instance_id` 预留给产出追溯使用,当前已写入执行记录(`ProcessRecord`),
/// 此处字段作为冗余追溯标识保留。
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ProcessOutcome {
/// 流程实例编号
pub instance_id: String,
/// 产出摘要(中文描述)
pub summary: String,
/// 是否成功
pub success: bool,
}
impl ProcessOutcome {
/// 创建成功产出
///
/// # 参数
/// – `instance_id`:流程实例编号
/// – `summary`:产出摘要
///
/// # 返回
/// 成功产出
pub fn success(instance_id: &str, summary: &str) -> Self {
Self {
instance_id: instance_id.to_string(),
summary: summary.to_string(),
success: true,
}
}
/// 创建失败产出
///
/// 预留 API:当前演示业务执行失败时直接返回错误,不构造失败产出;
/// 该构造器预留给需要显式失败产出的场景。
///
/// # 参数
/// – `instance_id`:流程实例编号
/// – `summary`:产出摘要
///
/// # 返回
/// 失败产出
#[allow(dead_code)]
pub fn failure(instance_id: &str, summary: &str) -> Self {
Self {
instance_id: instance_id.to_string(),
summary: summary.to_string(),
success: false,
}
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : business_event.rs
//! 业务事件(Business Event)
//!
//! 领域事件是观察者模式中「主题广播」的载体:
//! – `ProcessStarted` 流程启动事件(广播给所有观察者,演示一对多)
//! – `ProcurementCompleted` … 各部门业务完成事件(对应部门观察者执行核心业务)
//!
//! 事件与「主部门标识」相互映射,供调度器按供应链顺序发布与追溯。
/// 业务流程事件(可复制、可比较,用于主题广播与观察者订阅匹配)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BusinessEvent {
/// 流程启动事件(广播给全部观察者)
ProcessStarted,
/// 采购完成事件(主部门:采购部)
ProcurementCompleted,
/// 设计完成事件(主部门:设计部)
DesignCompleted,
/// 生产完成事件(主部门:生产部)
ProductionCompleted,
/// 质检完成事件(主部门:质检部)
InspectionCompleted,
/// 包装完成事件(主部门:包装部)
PackagingCompleted,
/// 物流完成事件(主部门:物流部)
LogisticsCompleted,
/// 财务完成事件(主部门:财务部)
FinanceCompleted,
/// 营销完成事件(主部门:营销部)
MarketingCompleted,
/// 销售完成事件(主部门:业务销售部)
SalesCompleted,
/// 人事行政完成事件(主部门:人事行政部)
HrAdminCompleted,
/// IT 完成事件(主部门:IT 部)
ItCompleted,
/// 培训完成事件(主部门:培训部)
TrainingCompleted,
}
impl BusinessEvent {
/// 获取事件的中文标签(用于日志输出)
///
/// # 返回
/// 中文事件标签
pub fn tag(&self) -> &'static str {
match self {
BusinessEvent::ProcessStarted => "流程启动",
BusinessEvent::ProcurementCompleted => "采购完成",
BusinessEvent::DesignCompleted => "设计完成",
BusinessEvent::ProductionCompleted => "生产完成",
BusinessEvent::InspectionCompleted => "质检完成",
BusinessEvent::PackagingCompleted => "包装完成",
BusinessEvent::LogisticsCompleted => "物流完成",
BusinessEvent::FinanceCompleted => "财务完成",
BusinessEvent::MarketingCompleted => "营销完成",
BusinessEvent::SalesCompleted => "销售完成",
BusinessEvent::HrAdminCompleted => "人事行政完成",
BusinessEvent::ItCompleted => "IT 完成",
BusinessEvent::TrainingCompleted => "培训完成",
}
}
/// 获取该完成事件对应的「主部门标识」(调度器按供应链发布时使用)
///
/// # 返回
/// 主部门标识(如 PROCUREMENT / DESIGN)
pub fn id(&self) -> &'static str {
match self {
BusinessEvent::ProcessStarted => "ALL",
BusinessEvent::ProcurementCompleted => "PROCUREMENT",
BusinessEvent::DesignCompleted => "DESIGN",
BusinessEvent::ProductionCompleted => "PRODUCTION",
BusinessEvent::InspectionCompleted => "INSPECTION",
BusinessEvent::PackagingCompleted => "PACKAGING",
BusinessEvent::LogisticsCompleted => "LOGISTICS",
BusinessEvent::FinanceCompleted => "FINANCE",
BusinessEvent::MarketingCompleted => "MARKETING",
BusinessEvent::SalesCompleted => "SALES",
BusinessEvent::HrAdminCompleted => "HR_ADMIN",
BusinessEvent::ItCompleted => "IT",
BusinessEvent::TrainingCompleted => "TRAINING",
}
}
/// 由部门标识映射为完成事件
///
/// # 参数
/// – `id`:部门标识(如 PROCUREMENT)
///
/// # 返回
/// – `Some(BusinessEvent)`:映射成功
/// – `None`:未知部门标识
pub fn from_id(id: &str) -> Option<BusinessEvent> {
match id {
"PROCUREMENT" => Some(BusinessEvent::ProcurementCompleted),
"DESIGN" => Some(BusinessEvent::DesignCompleted),
"PRODUCTION" => Some(BusinessEvent::ProductionCompleted),
"INSPECTION" => Some(BusinessEvent::InspectionCompleted),
"PACKAGING" => Some(BusinessEvent::PackagingCompleted),
"LOGISTICS" => Some(BusinessEvent::LogisticsCompleted),
"FINANCE" => Some(BusinessEvent::FinanceCompleted),
"MARKETING" => Some(BusinessEvent::MarketingCompleted),
"SALES" => Some(BusinessEvent::SalesCompleted),
"HR_ADMIN" => Some(BusinessEvent::HrAdminCompleted),
"IT" => Some(BusinessEvent::ItCompleted),
"TRAINING" => Some(BusinessEvent::TrainingCompleted),
_ => None,
}
}
/// 全部核心完成事件(供应链顺序,供调度器顺序/并发发布)
///
/// # 返回
/// 12 个核心完成事件数组(不含流程启动事件)
pub fn all_core_events() -> Vec<BusinessEvent> {
vec![
BusinessEvent::ProcurementCompleted,
BusinessEvent::DesignCompleted,
BusinessEvent::ProductionCompleted,
BusinessEvent::InspectionCompleted,
BusinessEvent::PackagingCompleted,
BusinessEvent::LogisticsCompleted,
BusinessEvent::FinanceCompleted,
BusinessEvent::MarketingCompleted,
BusinessEvent::SalesCompleted,
BusinessEvent::HrAdminCompleted,
BusinessEvent::ItCompleted,
BusinessEvent::TrainingCompleted,
]
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : observer.rs
//! 观察者抽象(Observer Trait)
//!
//! 观察者模式中的「观察者」:订阅主题感兴趣的事件,收到通知后自行响应。
//! 12 个业务部门各自实现本 trait,作为观察者订阅业务事件。
//!
//! 设计要点:
//! – `Send + Sync`:可被 `Arc` 共享到多线程,高并发环境下安全。
//! – `interests()`:声明订阅的事件集合,主题据此决定是否通知该观察者。
//! – `on_event()`:收到事件通知后响应(推模型,观察者自决行为)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
/// 观察者抽象(线程安全、可共享)
pub trait Observer: Send + Sync {
/// 获取观察者标识(如 PROCUREMENT / DESIGN)
///
/// # 返回
/// 观察者标识
fn observer_id(&self) -> &str;
/// 获取观察者名称(如 采购部)
///
/// # 返回
/// 观察者名称
fn observer_name(&self) -> &str;
/// 获取所属部门(如 原料采购部)
///
/// # 返回
/// 部门名称
fn department(&self) -> &str;
/// 声明订阅的事件集合(主题据此匹配是否通知本观察者)
///
/// # 返回
/// 订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent>;
/// 收到事件通知后的响应(执行本观察者业务)
///
/// # 参数
/// – `event`:触发的业务事件
/// – `request`:业务流程执行请求 DTO
///
/// # 返回
/// 执行响应 DTO
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto;
/// 获取统一日志对象(对应 ILogger<T>,由 DI 注入)
///
/// # 返回
/// 统一日志(`Arc<dyn Logger>`)
fn logger(&self) -> Arc<dyn Logger>;
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : subject.rs
//! 主题抽象(Subject Trait)
//!
//! 观察者模式中的「主题(被观察者)」:维护观察者注册表,
//! 状态/事件变化时广播(notify)通知所有订阅该事件的观察者。
//!
//! 设计要点:
//! – 主题不关心订阅者是谁,只负责「订阅/退订 + 广播」,实现发布-订阅解耦。
//! – `Send + Sync`:可被 `Arc` 共享到多线程,高并发广播安全。
use std::sync::Arc;
use crate::common::error::ProcessError;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 主题抽象(线程安全、可共享)
pub trait Subject: Send + Sync {
/// 订阅:注册一个观察者到主题
///
/// # 参数
/// – `observer`:观察者实例
///
/// # 返回
/// – `Ok(())`:订阅成功
/// – `Err(ProcessError)`:订阅失败(如重复订阅)
fn attach(&self, observer: Arc<dyn Observer>) -> Result<(), ProcessError>;
/// 退订:从主题移除指定观察者
///
/// # 参数
/// – `observer_id`:观察者标识
///
/// # 返回
/// – `Ok(())`:退订成功
/// – `Err(ProcessError)`:未找到观察者
#[allow(dead_code)]
fn detach(&self, observer_id: &str) -> Result<(), ProcessError>;
/// 获取全部已订阅观察者
///
/// # 返回
/// 全部观察者集合
fn observers(&self) -> Vec<Arc<dyn Observer>>;
/// 广播事件:通知所有订阅该事件的观察者(同步)
///
/// # 参数
/// – `event`:业务事件
/// – `request`:业务流程执行请求 DTO
///
/// # 返回
/// 各观察者执行响应集合
fn notify(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> Vec<ProcessResponseDto>;
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : process_repository.rs
//! 业务流程仓储接口(领域层抽象,由基础设施层实现)
//!
//! 仓储用于持久化每次同事业务执行的记录,供统计与追溯使用。
//! 领域层只定义接口,具体存储(内存 / 数据库)由基础设施层按 DI 注入。
use crate::common::error::ProcessError;
use crate::domain::entities::jewelry::ProcessOutcome;
/// 业务流程执行记录(持久化载体)
#[derive(Debug, Clone)]
pub struct ProcessRecord {
/// 流程实例编号
pub instance_id: String,
/// 流程名称(中文)
pub process_name: String,
/// 执行产出
pub outcome: ProcessOutcome,
/// 执行时间(格式:YYYY-MM-DD HH:MM:SS)
pub executed_at: String,
}
/// 业务流程仓储抽象接口(线程安全)
pub trait ProcessRepository: Send + Sync {
/// 保存业务执行记录
///
/// # 参数
/// – `record`:执行记录
///
/// # 返回
/// – `Ok(())`:保存成功
/// – `Err(ProcessError)`:保存失败
fn save(&self, record: ProcessRecord) -> Result<(), ProcessError>;
/// 查询全部执行记录
///
/// # 返回
/// 全部执行记录
fn find_all(&self) -> Vec<ProcessRecord>;
/// 统计成功/失败数量
///
/// # 返回
/// `(成功数量, 失败数量)` 元组
fn count(&self) -> (usize, usize);
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : container.rs
//! 依赖注入容器(组合根 Composition Root)
//!
//! 职责:集中装配(new)全部依赖并暴露访问方法,实现构造器注入。
//! – 统一日志(`Arc<dyn Logger>`)单例
//! – 重试 + 熔断适配器单例(`Arc<RetryCircuitBreaker>`)
//! – 具体主题/事件总线(`ConcreteEventBus`)单例
//! – 12 个部门观察者(Observer 子类)订阅到主题
//! – 内存仓储单例
//! – 业务流程应用服务(调度器)
//!
//! 依赖方向严格单向:presentation → interface → application → domain → common,
//! 基础设施层向上提供实现,由容器完成组装。
use std::sync::Arc;
use std::time::Duration;
use crate::application::observer::concrete_event_bus::ConcreteEventBus;
use crate::application::observer::observers::business_sales::BusinessSalesObserver;
use crate::application::observer::observers::design::DesignObserver;
use crate::application::observer::observers::finance::FinanceObserver;
use crate::application::observer::observers::hr_admin::HrAdminObserver;
use crate::application::observer::observers::inspection::InspectionObserver;
use crate::application::observer::observers::it::ItObserver;
use crate::application::observer::observers::logistics::LogisticsObserver;
use crate::application::observer::observers::marketing::MarketingObserver;
use crate::application::observer::observers::packaging::PackagingObserver;
use crate::application::observer::observers::procurement::ProcurementObserver;
use crate::application::observer::observers::production::ProductionObserver;
use crate::application::observer::observers::training::TrainingObserver;
use crate::application::services::process_service::ProcessService;
use crate::common::logging::Logger;
use crate::common::resilience::retry_circuit_breaker::RetryCircuitBreaker;
use crate::domain::observer::observer::Observer;
use crate::domain::observer::subject::Subject;
use crate::infrastructure::logging::file_logger::FileLogger;
use crate::infrastructure::persistence::memory_process_repository::MemoryProcessRepository;
/// 依赖注入容器(组合根)
pub struct ServiceContainer {
/// 统一日志(单例)
logger: Arc<dyn Logger>,
/// 重试 + 熔断适配器(单例,预留给扩展组件复用)
#[allow(dead_code)]
resilience: Arc<RetryCircuitBreaker>,
/// 具体主题/事件总线(单例,由应用服务内部使用;此处持有以便装配与扩展)
#[allow(dead_code)]
topic: Arc<ConcreteEventBus>,
/// 内存仓储(单例,预留给扩展组件复用)
#[allow(dead_code)]
repository: Arc<MemoryProcessRepository>,
/// 业务流程应用服务(调度器)
service: Arc<ProcessService>,
}
impl ServiceContainer {
/// 构建依赖注入容器(组合根,统一装配主题、观察者与全部服务)
///
/// # 返回
/// 已装配完成的容器实例
pub fn new() -> Self {
// 1. 基础设施依赖(单例)
let logger: Arc<dyn Logger> = Arc::new(FileLogger::new("./Logs"));
// 重试 2 次、连续失败 3 次熔断、冷却 5 秒
let resilience = Arc::new(RetryCircuitBreaker::new(2, 3, Duration::from_secs(5)));
let repository = Arc::new(MemoryProcessRepository::new());
// 2. 创建具体主题/事件总线(注入统一日志 + 重试熔断适配器)
let topic = Arc::new(ConcreteEventBus::new(logger.clone(), resilience.clone()));
// 3. 创建 12 个部门观察者并订阅到主题(发布-订阅解耦)
let observers: Vec<Arc<dyn Observer>> = vec![
Arc::new(ProcurementObserver::new(logger.clone())),
Arc::new(DesignObserver::new(logger.clone())),
Arc::new(ProductionObserver::new(logger.clone())),
Arc::new(InspectionObserver::new(logger.clone())),
Arc::new(PackagingObserver::new(logger.clone())),
Arc::new(LogisticsObserver::new(logger.clone())),
Arc::new(FinanceObserver::new(logger.clone())),
Arc::new(MarketingObserver::new(logger.clone())),
Arc::new(BusinessSalesObserver::new(logger.clone())),
Arc::new(HrAdminObserver::new(logger.clone())),
Arc::new(ItObserver::new(logger.clone())),
Arc::new(TrainingObserver::new(logger.clone())),
];
// 每个观察者订阅到主题(构造器注入 + 订阅注册)
for observer in observers {
if let Err(err) = topic.attach(observer) {
logger.error(&format!("观察者订阅失败:{}", err));
}
}
// 4. 应用层服务(构造器注入)
let service = Arc::new(ProcessService::new(
topic.clone(),
repository.clone(),
logger.clone(),
));
Self {
logger,
resilience,
topic,
repository,
service,
}
}
/// 获取业务流程应用服务
///
/// # 返回
/// 应用服务(`Arc` 共享)
pub fn service(&self) -> Arc<ProcessService> {
self.service.clone()
}
/// 获取具体主题/事件总线
///
/// # 返回
/// 事件总线(`Arc` 共享)
#[allow(dead_code)]
pub fn topic(&self) -> Arc<ConcreteEventBus> {
self.topic.clone()
}
/// 获取统一日志对象
///
/// # 返回
/// 统一日志(`Arc<dyn Logger>`)
pub fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : file_logger.rs
//! 文件日志实现(按日期分文件夹、按日志等级分文件)
//!
//! 目录结构(示例,日期为当日):
//! ```text
//! Logs/
//! 2026-07-06/
//! app-info.log
//! app-error.log
//! app-debug.log
//! app-warn.log
//! ```
//!
//! 设计要点:
//! – **线程安全 / 高并发**:每个日志等级使用独立的 `Mutex<BufWriter<File>>`,
//! 同一等级写操作串行化,不同等级互不阻塞;可被 `Arc` 共享到多线程。
//! – **日期滚动**:每次写入检测日期目录,跨天自动切换到新的日期文件夹。
//! – **控制台与文件一致**:统一格式化 `[时间] [等级] 消息`,
//! 同时输出到控制台(stdout/stderr)与对应文件。
use std::fs::{self, File, OpenOptions};
use std::io::Write;
use std::path::PathBuf;
use std::sync::Mutex;
use crate::common::logging::{LogLevel, Logger};
/// 单日志等级的文件写入句柄(受互斥锁保护)
struct LevelWriter {
/// 当前打开的缓冲写入器
writer: Option<std::io::BufWriter<File>>,
/// 该句柄对应的日期文件夹(用于跨天滚动判断)
opened_date: String,
}
impl LevelWriter {
/// 创建空的等级写入器
fn new() -> Self {
Self {
writer: None,
opened_date: String::new(),
}
}
}
/// 文件日志实现(线程安全、支持高并发写入)
pub struct FileLogger {
/// 日志根目录(默认 ./Logs)
base_dir: PathBuf,
/// 调试日志写入器
debug_writer: Mutex<LevelWriter>,
/// 信息日志写入器
info_writer: Mutex<LevelWriter>,
/// 警告日志写入器
warn_writer: Mutex<LevelWriter>,
/// 错误日志写入器
error_writer: Mutex<LevelWriter>,
}
impl FileLogger {
/// 创建文件日志
///
/// # 参数
/// – `base_dir`:日志根目录(如 "./Logs")
///
/// # 返回
/// 文件日志实例
pub fn new(base_dir: &str) -> Self {
Self {
base_dir: PathBuf::from(base_dir),
debug_writer: Mutex::new(LevelWriter::new()),
info_writer: Mutex::new(LevelWriter::new()),
warn_writer: Mutex::new(LevelWriter::new()),
error_writer: Mutex::new(LevelWriter::new()),
}
}
/// 获取当前日期文件夹名(如 2026-07-06)
///
/// # 返回
/// 日期字符串
fn date_folder(&self) -> String {
chrono::Local::now().format("%Y-%m-%d").to_string()
}
/// 确保日期目录存在并返回目录路径
///
/// # 参数
/// – `date_folder`:日期文件夹名
///
/// # 返回
/// 日期目录路径
fn ensure_dir(&self, date_folder: &str) -> PathBuf {
let dir = self.base_dir.join(date_folder);
let _ = fs::create_dir_all(&dir);
dir
}
/// 以追加模式打开指定等级日志文件(返回缓冲写入器)
///
/// # 参数
/// – `level`:日志等级
///
/// # 返回
/// 缓冲写入器
fn open_writer(&self, level: LogLevel) -> std::io::BufWriter<File> {
let date_folder = self.date_folder();
let dir = self.ensure_dir(&date_folder);
let path = dir.join(level.file_name());
let file = OpenOptions::new()
.create(true)
.append(true)
.open(&path)
.unwrap_or_else(|e| panic!("无法打开日志文件 {}:{}", path.display(), e));
std::io::BufWriter::new(file)
}
/// 写入日志(统一格式;控制台与文件同时输出)
///
/// # 参数
/// – `level`:日志等级
/// – `message`:日志消息
fn write(&self, level: LogLevel, message: &str) {
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
let line = format!("[{}] [{}] {}", timestamp, level.tag(), message);
// ① 输出到控制台(错误走 stderr,其余走 stdout)
match level {
LogLevel::Error => eprintln!("{}", line),
_ => println!("{}", line),
}
// ② 输出到文件(按等级互斥锁串行化,保证线程安全)
let target = match level {
LogLevel::Debug => &self.debug_writer,
LogLevel::Info => &self.info_writer,
LogLevel::Warn => &self.warn_writer,
LogLevel::Error => &self.error_writer,
};
let mut guard = target.lock().unwrap();
let date_folder = self.date_folder();
// 跨天或未打开 → 重新打开文件(实现按日期滚动)
if guard.opened_date != date_folder || guard.writer.is_none() {
guard.opened_date = date_folder.clone();
guard.writer = Some(self.open_writer(level));
}
if let Some(writer) = guard.writer.as_mut() {
let _ = writeln!(writer, "{}", line);
let _ = writer.flush();
}
}
}
/// 实现统一日志接口(`Arc<dyn Logger>` 可注入各组件)
impl Logger for FileLogger {
/// 输出调试日志
fn debug(&self, message: &str) {
self.write(LogLevel::Debug, message);
}
/// 输出信息日志
fn info(&self, message: &str) {
self.write(LogLevel::Info, message);
}
/// 输出警告日志
fn warn(&self, message: &str) {
self.write(LogLevel::Warn, message);
}
/// 输出错误日志
fn error(&self, message: &str) {
self.write(LogLevel::Error, message);
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : memory_process_repository.rs
//! 内存仓储实现(线程安全)
//!
//! 以 `Mutex<HashMap>` 实现 `ProcessRepository` 接口,供业务执行记录
//! 的保存、查询与统计使用。演示场景使用内存存储;生产环境可替换为数据库实现。
use std::collections::HashMap;
use std::sync::Mutex;
use crate::common::error::ProcessError;
use crate::domain::repository::process_repository::{ProcessRecord, ProcessRepository};
/// 内存仓储实现
pub struct MemoryProcessRepository {
/// 内部存储(以流程实例编号为键,受互斥锁保护,保证并发安全)
store: Mutex<HashMap<String, ProcessRecord>>,
}
impl MemoryProcessRepository {
/// 创建内存仓储
///
/// # 返回
/// 内存仓储实例
pub fn new() -> Self {
Self {
store: Mutex::new(HashMap::new()),
}
}
}
impl ProcessRepository for MemoryProcessRepository {
/// 保存业务执行记录
///
/// # 参数
/// – `record`:执行记录
///
/// # 返回
/// – `Ok(())`:保存成功
/// – `Err(ProcessError)`:保存失败
fn save(&self, record: ProcessRecord) -> Result<(), ProcessError> {
let mut store = self.store.lock().unwrap();
store.insert(record.instance_id.clone(), record);
Ok(())
}
/// 查询全部执行记录
///
/// # 返回
/// 全部执行记录
fn find_all(&self) -> Vec<ProcessRecord> {
let store = self.store.lock().unwrap();
store.values().cloned().collect()
}
/// 统计成功/失败数量
///
/// # 返回
/// `(成功数量, 失败数量)` 元组
fn count(&self) -> (usize, usize) {
let store = self.store.lock().unwrap();
let total = store.values().len();
let success = store.values().filter(|r| r.outcome.success).count();
(success, total – success)
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : contracts.rs
//! 对外交互契约(Contracts)
//!
//! 定义外部调用方与系统交互的统一契约结构(业务信封),
//! 承载「事件标识 + 执行请求」,供表现层/外部系统装配。
use crate::domain::dtos::process_dtos::ProcessRequestDto;
/// 业务信封(外部发布一个业务事件的载体)
#[derive(Debug, Clone)]
pub struct BusinessEnvelope {
/// 事件对应的主部门标识(如 PROCUREMENT / TRAINING)
pub event_id: String,
/// 执行请求 DTO
pub request: ProcessRequestDto,
}
impl BusinessEnvelope {
/// 创建业务信封
///
/// # 参数
/// – `event_id`:事件对应的主部门标识
/// – `request`:执行请求
///
/// # 返回
/// 业务信封
pub fn new(event_id: &str, request: ProcessRequestDto) -> Self {
Self {
event_id: event_id.to_string(),
request,
}
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : ports.rs
//! 对外 API 端口契约(Ports)
//!
//! 定义表现层(presentation)与外部调用方可消费的应用端口,
//! 将「应用能力」与「具体实现」解耦;具体实现由表现层/应用层提供。
//!
//! 观察者模式语义:外部通过「发布事件」驱动观察者响应,而非直接调用部门。
use crate::common::error::ProcessError;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::repository::process_repository::ProcessRecord;
/// 对外应用 API 端口契约(线程安全)
///
/// 表现层实现该端口并向外部暴露;外部仅依赖本端口,不依赖具体实现。
pub trait BusinessApiPort: Send + Sync {
/// 发布业务事件驱动观察者执行(经主题广播)
///
/// # 参数
/// – `event_id`:事件对应的主部门标识(如 PROCUREMENT / TRAINING)
/// – `request`:执行请求 DTO
///
/// # 返回
/// – `Ok(ProcessResponseDto)`:主观察者执行响应
/// – `Err(ProcessError)`:发布/执行失败
fn publish(
&self,
event_id: &str,
request: ProcessRequestDto,
) -> Result<ProcessResponseDto, ProcessError>;
/// 获取业务执行统计(成功数量,失败数量)
///
/// # 返回
/// `(成功数量, 失败数量)` 元组
fn statistics(&self) -> (usize, usize);
/// 获取全部业务执行记录(用于追溯/汇总展示)
///
/// # 返回
/// 全部执行记录
fn records(&self) -> Vec<ProcessRecord>;
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : controller.rs
//! 应用控制器(表现层,控制台入口)
//!
//! 职责:
//! – 从组合根(DI 容器)获取应用服务与统一日志
//! – 实现 `interface::ports::BusinessApiPort` 端口契约(对外 API)
//! – 创建贯穿全流程的珠宝实体,驱动主题顺序广播与并发广播演示
//! – 输出业务执行统计与记录汇总
//!
//! 依赖方向:presentation → interface → application → domain → common,
//! 符合严格分层(六层结构)。
use std::sync::Arc;
use crate::common::error::ProcessError;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::entities::jewelry::Jewelry;
use crate::domain::repository::process_repository::ProcessRecord;
use crate::infrastructure::di::container::ServiceContainer;
use crate::interface::contracts::BusinessEnvelope;
use crate::interface::ports::BusinessApiPort;
/// 应用控制器(控制台表现层,实现对外端口契约)
pub struct ApplicationController {
/// 依赖注入容器(组合根)
container: Arc<ServiceContainer>,
/// 统一日志对象
logger: Arc<dyn Logger>,
}
impl ApplicationController {
/// 创建应用控制器
///
/// # 参数
/// – `container`:依赖注入容器
///
/// # 返回
/// 应用控制器实例
pub fn new(container: Arc<ServiceContainer>) -> Self {
let logger = container.logger();
Self { container, logger }
}
/// 启动珠宝行业全程业务流程(观察者模式)演示
///
/// 流程:
/// ① 打印标题与配置
/// ② 创建珠宝实体
/// ③ 主题广播「流程启动」事件(一对多通知全部观察者)+ 顺序广播核心事件
/// ④ 输出执行统计与记录明细
/// ⑤ 主题并发广播全部核心事件(高并发演示)
/// ⑥ 通过端口契约发布单个事件
pub fn run(&self) {
// ① 标题与运行说明
self.logger.info("================================================================");
self.logger.info(" 观察者模式 Observer Pattern");
self.logger.info(" 珠宝行业企业级全程业务流程(DDD 六层分层)");
self.logger.info(" 业务:原料采购核验 · 设计制图 · 加工生产 · 质检 · 包装 · 物流");
self.logger.info(" · 财务 · 营销推广 · 业务销售 · 人事行政 · IT · 培训");
self.logger.info(" 日志:Logs/<日期>/app-{info,error,debug,warn}.log(按日期/等级分文件)");
self.logger.info("================================================================");
// ② 创建贯穿全流程的珠宝实体
let jewelry = Jewelry::new("六福传承金镯", "黄金", 35.68, 26800.0);
self.logger.info(&format!(
"创建珠宝实体:{},材质={},重量={} 克,零售价={} 元",
jewelry.name, jewelry.material, jewelry.weight_grams, jewelry.price
));
// ③ 主题顺序广播:流程启动(一对多)+ 12 个核心完成事件
let request = ProcessRequestDto::new("ALL", jewelry.clone(), "调度中心", "Observer");
self.container.service().run_sequential(request);
self.logger.info("================================================================");
// ④ 输出执行统计(读取内存仓储)
self.print_summary();
// ⑤ 主题并发广播全部核心事件(高并发演示)
self.logger.info("【高并发演示】主题并发广播全部核心事件……");
let concurrent_request = ProcessRequestDto::new("ALL", jewelry.clone(), "调度中心", "Concurrent");
self.container.service().run_concurrent(concurrent_request);
self.print_summary();
// ⑥ 通过端口契约发布单个事件(BusinessEnvelope + publish)
let envelope = BusinessEnvelope::new(
"TRAINING",
ProcessRequestDto::new("TRAINING", jewelry, "培训部", "PortTest"),
);
match self.publish(&envelope.event_id, envelope.request) {
Ok(resp) => self.logger.info(&format!(
"端口契约发布事件成功:{} / {}",
resp.process_name, resp.message
)),
Err(err) => self.logger.warn(&format!("端口契约发布事件失败:{}", err)),
}
// ⑦ 输出已订阅观察者清单
let observers = self.container.service().observers();
self.logger
.info(&format!("已订阅观察者(部门)数:{}", observers.len()));
for observer in observers {
self.logger.info(&format!(
" – [{}] {} / {}",
observer.observer_id(),
observer.department(),
observer.observer_name()
));
}
self.logger.info("================================================================");
}
/// 输出执行统计与记录明细(基于仓储数据)
fn print_summary(&self) {
let (success, failure) = self.statistics();
self.logger.info(&format!(
"业务调度汇总:成功 {} 项,失败 {} 项(详见当日日志目录)",
success, failure
));
let records = self.records();
self.logger.info(&format!("执行记录明细(共 {} 条):", records.len()));
for record in records {
let flag = if record.outcome.success { "成功" } else { "失败" };
self.logger.info(&format!(
" – {} | {} | 状态:{} | 时间:{}",
record.instance_id, record.process_name, flag, record.executed_at
));
}
}
}
/// 实现对外 API 端口契约(interface 层定义)
impl BusinessApiPort for ApplicationController {
/// 发布业务事件驱动观察者执行(经主题广播)
fn publish(
&self,
event_id: &str,
request: ProcessRequestDto,
) -> Result<ProcessResponseDto, ProcessError> {
self.container.service().publish_single(event_id, request)
}
/// 获取业务执行统计(成功数量,失败数量)
fn statistics(&self) -> (usize, usize) {
self.container.service().statistics()
}
/// 获取全部业务执行记录(用于追溯/汇总展示)
fn records(&self) -> Vec<ProcessRecord> {
self.container.service().records()
}
}

//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : business_sales.rs
//! 业务销售部观察者(业务销售)
//!
//! 订阅事件:`ProcessStarted`、`SalesCompleted`
//! 主业务:业务销售(门店销售、订单履约、会员服务)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 业务销售部观察者
pub struct BusinessSalesObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl BusinessSalesObserver {
/// 创建业务销售部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 业务销售部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for BusinessSalesObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"SALES"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"业务销售部"
}
/// 获取所属部门
fn department(&self) -> &str {
"业务销售部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::SalesCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:业务销售
BusinessEvent::SalesCompleted => {
self.logger.info(&format!(
"【销售】开始业务销售:{}",
request.jewelry.name
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = "业务销售完成,门店成交 + 订单履约 + 会员服务";
self.logger.info(&format!("【销售】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【销售】收到流程启动通知,等待销售任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待销售任务",
)
}
_ => {
self.logger
.warn(&format!("【销售】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : design.rs
//! 设计部观察者(设计制图)
//!
//! 订阅事件:`ProcessStarted`、`DesignCompleted`
//! 主业务:设计制图(3D 起版、款式设计、工艺标注)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 设计部观察者
pub struct DesignObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl DesignObserver {
/// 创建设计部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 设计部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for DesignObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"DESIGN"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"设计部"
}
/// 获取所属部门
fn department(&self) -> &str {
"设计研发部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::DesignCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:设计制图
BusinessEvent::DesignCompleted => {
self.logger.info(&format!(
"【设计】开始设计制图:{}(材质:{})",
request.jewelry.name, request.jewelry.material
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = format!(
"设计制图完成,3D 起版 + 工艺标注,设计稿已归档",
);
self.logger.info(&format!("【设计】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, &message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【设计】收到流程启动通知,等待设计任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待设计任务",
)
}
_ => {
self.logger
.warn(&format!("【设计】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : finance.rs
//! 财务部观察者(财务核算)
//!
//! 订阅事件:`ProcessStarted`、`FinanceCompleted`
//! 主业务:财务核算(成本核算、开票、资金结算)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 财务部观察者
pub struct FinanceObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl FinanceObserver {
/// 创建财务部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 财务部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for FinanceObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"FINANCE"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"财务部"
}
/// 获取所属部门
fn department(&self) -> &str {
"财务管理部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::FinanceCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:财务核算
BusinessEvent::FinanceCompleted => {
self.logger.info(&format!(
"【财务】开始财务核算:{}(零售价:{} 元)",
request.jewelry.name, request.jewelry.price
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = format!(
"财务核算完成,成本入账 + 开具发票 + 资金结算(售价 {} 元)",
request.jewelry.price
);
self.logger.info(&format!("【财务】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, &message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【财务】收到流程启动通知,等待财务任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待财务任务",
)
}
_ => {
self.logger
.warn(&format!("【财务】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : hr_admin.rs
//! 人事行政部观察者(人事行政)
//!
//! 订阅事件:`ProcessStarted`、`HrAdminCompleted`
//! 主业务:人事行政(员工考勤、薪酬核算、行政保障)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 人事行政部观察者
pub struct HrAdminObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl HrAdminObserver {
/// 创建人事行政部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 人事行政部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for HrAdminObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"HR_ADMIN"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"人事行政部"
}
/// 获取所属部门
fn department(&self) -> &str {
"人事行政部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::HrAdminCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:人事行政
BusinessEvent::HrAdminCompleted => {
self.logger.info(&format!(
"【人事行政】开始人事行政保障:{}",
request.jewelry.name
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = "人事行政完成,员工考勤 + 薪酬核算 + 行政保障";
self.logger.info(&format!("【人事行政】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【人事行政】收到流程启动通知,等待任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待任务",
)
}
_ => {
self.logger
.warn(&format!("【人事行政】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : inspection.rs
//! 质检部观察者(质量检测)
//!
//! 订阅事件:`ProcessStarted`、`InspectionCompleted`
//! 主业务:质检(成色/重量复核、工艺抽检、鉴定证书)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 质检部观察者
pub struct InspectionObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl InspectionObserver {
/// 创建质检部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 质检部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for InspectionObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"INSPECTION"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"质检部"
}
/// 获取所属部门
fn department(&self) -> &str {
"质量检测部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::InspectionCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:质检
BusinessEvent::InspectionCompleted => {
self.logger.info(&format!(
"【质检】开始质检:{}(重量:{} 克)",
request.jewelry.name, request.jewelry.weight_grams
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = "质检完成,成色/重量复核 + 工艺抽检合格,出具鉴定证书";
self.logger.info(&format!("【质检】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【质检】收到流程启动通知,等待质检任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待质检任务",
)
}
_ => {
self.logger
.warn(&format!("【质检】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : it.rs
//! IT 部观察者(信息系统运维)
//!
//! 订阅事件:`ProcessStarted`、`ItCompleted`
//! 主业务:IT 运维(ERP 系统、数据安全、网络保障)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// IT 部观察者
pub struct ItObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl ItObserver {
/// 创建 IT 部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// IT 部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for ItObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"IT"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"IT部"
}
/// 获取所属部门
fn department(&self) -> &str {
"IT 信息部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::ItCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:IT 运维
BusinessEvent::ItCompleted => {
self.logger.info(&format!(
"【IT】开始系统运维保障:{}",
request.jewelry.name
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = "IT 运维完成,ERP 系统 + 数据安全 + 网络保障";
self.logger.info(&format!("【IT】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【IT】收到流程启动通知,等待运维任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待运维任务",
)
}
_ => {
self.logger
.warn(&format!("【IT】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : logistics.rs
//! 物流部观察者(仓储物流配送)
//!
//! 订阅事件:`ProcessStarted`、`LogisticsCompleted`
//! 主业务:物流配送(保价发货、在途跟踪、签收确认)。
//!
//! 重试熔断演示:通过静态计数模拟前两次「外部物流系统瞬时不可用」,
//! 触发「重试 + 熔断」适配器重试,第 3 次调用成功(warn 记录前两次失败)。
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use crate::common::error::ProcessError;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 外部物流系统调用计数器(静态、跨调用累加,用于演示瞬时失败后恢复)
static LOGISTICS_CALL_COUNT: AtomicU32 = AtomicU32::new(0);
/// 物流部观察者
pub struct LogisticsObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl LogisticsObserver {
/// 创建物流部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 物流部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
/// 模拟调用外部物流系统(前两次返回瞬时失败,第三次成功)
///
/// # 参数
/// – `request`:业务流程执行请求
///
/// # 返回
/// – `Ok(String)`:物流成功消息
/// – `Err(ProcessError)`:外部系统瞬时不可用
fn call_external_logistics(&self, request: &ProcessRequestDto) -> Result<String, ProcessError> {
let count = LOGISTICS_CALL_COUNT.fetch_add(1, Ordering::SeqCst) + 1;
if count <= 2 {
// 前两次模拟外部物流系统暂时不可用,触发重试
self.logger.warn(&format!(
"【物流】外部物流系统暂时不可用(第 {} 次尝试)",
count
));
return Err(ProcessError::new(
"EXTERNAL_LOGISTICS_UNAVAILABLE",
"外部物流系统暂时不可用,请重试",
));
}
// 第三次调用成功
Ok(format!(
"物流配送完成,{} 保价发货 + 在途跟踪 + 签收确认",
request.jewelry.name
))
}
}
impl Observer for LogisticsObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"LOGISTICS"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"物流部"
}
/// 获取所属部门
fn department(&self) -> &str {
"仓储物流部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::LogisticsCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:物流配送(经重试熔断保护)
BusinessEvent::LogisticsCompleted => {
self.logger.info(&format!(
"【物流】开始物流配送:{}",
request.jewelry.name
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = match self.call_external_logistics(request) {
Ok(msg) => msg,
Err(err) => err.message.clone(),
};
self.logger.info(&format!("【物流】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, &message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【物流】收到流程启动通知,等待物流任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待物流任务",
)
}
_ => {
self.logger
.warn(&format!("【物流】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : marketing.rs
//! 营销部观察者(营销推广)
//!
//! 订阅事件:`ProcessStarted`、`MarketingCompleted`
//! 主业务:营销推广(广告投放、渠道推广、品牌种草)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 营销部观察者
pub struct MarketingObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl MarketingObserver {
/// 创建营销部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 营销部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for MarketingObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"MARKETING"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"营销部"
}
/// 获取所属部门
fn department(&self) -> &str {
"营销推广部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::MarketingCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:营销推广
BusinessEvent::MarketingCompleted => {
self.logger.info(&format!(
"【营销】开始营销推广:{}",
request.jewelry.name
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = "营销推广完成,广告投放 + 渠道推广 + 品牌种草";
self.logger.info(&format!("【营销】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【营销】收到流程启动通知,等待营销任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待营销任务",
)
}
_ => {
self.logger
.warn(&format!("【营销】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : packaging.rs
//! 包装部观察者(成品包装)
//!
//! 订阅事件:`ProcessStarted`、`PackagingCompleted`
//! 主业务:成品包装(礼盒装配、防伪标签、出库单)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 包装部观察者
pub struct PackagingObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl PackagingObserver {
/// 创建包装部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 包装部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for PackagingObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"PACKAGING"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"包装部"
}
/// 获取所属部门
fn department(&self) -> &str {
"成品包装部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::PackagingCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:成品包装
BusinessEvent::PackagingCompleted => {
self.logger.info(&format!(
"【包装】开始成品包装:{}",
request.jewelry.name
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = "包装完成,礼盒装配 + 防伪标签 + 出库单已生成";
self.logger.info(&format!("【包装】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【包装】收到流程启动通知,等待包装任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待包装任务",
)
}
_ => {
self.logger
.warn(&format!("【包装】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : procurement.rs
//! 采购部观察者(原料采购核验)
//!
//! 订阅事件:`ProcessStarted`(流程启动确认)、`ProcurementCompleted`(执行采购主业务)
//! 主业务:原料采购核验(黄金/钻石成色、供应商资质、到货验收)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 采购部观察者
pub struct ProcurementObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl ProcurementObserver {
/// 创建采购部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 采购部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for ProcurementObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"PROCUREMENT"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"采购部"
}
/// 获取所属部门
fn department(&self) -> &str {
"原料采购部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::ProcurementCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:原料采购核验
BusinessEvent::ProcurementCompleted => {
self.logger.info(&format!(
"【采购】开始原料采购核验:{}({})",
request.jewelry.name, request.jewelry.material
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = format!(
"原料采购完成,核验成色/重量 {} 克/供应商资质,验收入库",
request.jewelry.weight_grams
);
self.logger.info(&format!("【采购】{}", message));
ProcessResponseDto::new(
&instance_id,
self.observer_name(),
true,
&message,
)
}
// 流程启动确认(一对多广播通知)
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【采购】收到流程启动通知,等待原料采购任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!("{}-{:06}", self.observer_id(), crate::domain::entities::jewelry::next_sequence()),
self.observer_name(),
true,
"已确认流程启动,等待采购任务",
)
}
// 理论不会触发(interests 已过滤),防御性处理
_ => {
self.logger
.warn(&format!("【采购】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!("{}-{:06}", self.observer_id(), crate::domain::entities::jewelry::next_sequence()),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : production.rs
//! 生产部观察者(加工生产)
//!
//! 订阅事件:`ProcessStarted`、`ProductionCompleted`
//! 主业务:加工生产(CNC 数控、执模、镶嵌、抛光)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 生产部观察者
pub struct ProductionObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl ProductionObserver {
/// 创建生产部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 生产部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for ProductionObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"PRODUCTION"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"生产部"
}
/// 获取所属部门
fn department(&self) -> &str {
"加工生产部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::ProductionCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:加工生产
BusinessEvent::ProductionCompleted => {
self.logger.info(&format!(
"【生产】开始加工生产:{}(重量:{} 克)",
request.jewelry.name, request.jewelry.weight_grams
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = "加工生产完成,CNC 执模 + 镶嵌 + 抛光,成品下线";
self.logger.info(&format!("【生产】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【生产】收到流程启动通知,等待生产任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待生产任务",
)
}
_ => {
self.logger
.warn(&format!("【生产】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : training.rs
//! 培训部观察者(人才培训)
//!
//! 订阅事件:`ProcessStarted`、`TrainingCompleted`
//! 主业务:人才培训(技能培训、考核评估、档案归档)。
use std::sync::Arc;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
/// 培训部观察者
pub struct TrainingObserver {
/// 统一日志对象(DI 注入)
logger: Arc<dyn Logger>,
}
impl TrainingObserver {
/// 创建培训部观察者
///
/// # 参数
/// – `logger`:统一日志
///
/// # 返回
/// 培训部观察者实例
pub fn new(logger: Arc<dyn Logger>) -> Self {
Self { logger }
}
}
impl Observer for TrainingObserver {
/// 获取观察者标识
fn observer_id(&self) -> &str {
"TRAINING"
}
/// 获取观察者名称
fn observer_name(&self) -> &str {
"培训部"
}
/// 获取所属部门
fn department(&self) -> &str {
"人才培训部"
}
/// 声明订阅的事件集合
fn interests(&self) -> Vec<BusinessEvent> {
vec![BusinessEvent::ProcessStarted, BusinessEvent::TrainingCompleted]
}
/// 收到事件通知后的响应
fn on_event(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> ProcessResponseDto {
match event {
// 主业务:人才培训
BusinessEvent::TrainingCompleted => {
self.logger.info(&format!(
"【培训】开始人才培训:{}",
request.jewelry.name
));
let instance_id = format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
);
let message = "培训完成,技能培训 + 考核评估 + 档案归档";
self.logger.info(&format!("【培训】{}", message));
ProcessResponseDto::new(&instance_id, self.observer_name(), true, message)
}
// 流程启动确认
BusinessEvent::ProcessStarted => {
self.logger.debug(&format!(
"【培训】收到流程启动通知,等待培训任务(珠宝:{})",
request.jewelry.name
));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"已确认流程启动,等待培训任务",
)
}
_ => {
self.logger
.warn(&format!("【培训】忽略不相关事件:{}", event.tag()));
ProcessResponseDto::new(
&format!(
"{}-{:06}",
self.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
self.observer_name(),
true,
"忽略不相关事件",
)
}
}
}
/// 获取统一日志对象
fn logger(&self) -> Arc<dyn Logger> {
self.logger.clone()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//! 具体主题(Concrete Subject)— 事件总线
//!
//! 实现领域层 `Subject` trait:维护观察者注册表,广播业务事件。
//! 特性:
//! – **线程安全**:观察者注册表以 `Mutex` 保护,可 `Arc` 共享到多线程。
//! – **同步广播** `notify`:遍历所有订阅该事件的观察者,逐个经「重试 + 熔断」
//! 执行响应。
//! – **并发广播** `notify_concurrent`:对每个订阅者独立线程并发执行(高并发演示)。
//! – 广播前根据观察者 `interests()` 匹配,实现「一对多」的订阅-发布解耦。
use std::sync::{Arc, Mutex};
use crate::common::error::ProcessError;
use crate::common::logging::Logger;
use crate::common::resilience::retry_circuit_breaker::RetryCircuitBreaker;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
use crate::domain::observer::subject::Subject;
/// 具体主题(事件总线),线程安全、可共享
pub struct ConcreteEventBus {
/// 观察者注册表(受互斥锁保护,高并发订阅/退订安全)
observers: Mutex<Vec<Arc<dyn Observer>>>,
/// 统一日志(依赖注入)
logger: Arc<dyn Logger>,
/// 重试 + 熔断适配器(依赖注入,保护观察者响应执行)
resilience: Arc<RetryCircuitBreaker>,
}
impl ConcreteEventBus {
/// 创建具体主题(事件总线)
///
/// # 参数
/// – `logger`:统一日志
/// – `resilience`:重试 + 熔断适配器
///
/// # 返回
/// 事件总线实例
pub fn new(logger: Arc<dyn Logger>, resilience: Arc<RetryCircuitBreaker>) -> Self {
Self {
observers: Mutex::new(Vec::new()),
logger,
resilience,
}
}
/// 判断指定观察者是否订阅了某事件
///
/// # 参数
/// – `observer`:观察者
/// – `event`:业务事件
///
/// # 返回
/// – `true`:订阅了该事件
/// – `false`:未订阅
fn is_subscribed(observer: &Arc<dyn Observer>, event: &BusinessEvent) -> bool {
observer.interests().contains(event)
}
/// 获取观察者注册表快照(避免持锁调用观察者造成死锁)
///
/// # 返回
/// 观察者集合快照
fn snapshot(&self) -> Vec<Arc<dyn Observer>> {
self.observers.lock().unwrap().clone()
}
/// 并发广播事件(高并发演示:每个订阅者一个线程执行响应)
///
/// # 参数
/// – `event`:业务事件
/// – `request`:业务流程执行请求 DTO
///
/// # 返回
/// 各订阅者执行响应集合(顺序与订阅顺序一致)
pub fn notify_concurrent(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> Vec<ProcessResponseDto> {
let snapshot = self.snapshot();
let mut handles = Vec::new();
for observer in snapshot {
// 仅对订阅了该事件的观察者并发执行(一对多广播)
if !Self::is_subscribed(&observer, event) {
continue;
}
self.logger.debug(&format!(
"主题广播事件【{}】→ 观察者 {}(并发线程)",
event.tag(),
observer.observer_id()
));
let event_clone = *event;
let request_clone = request.clone();
let observer_clone = observer.clone();
let resilience_clone = self.resilience.clone();
// 为每个观察者开辟独立线程,模拟高并发广播
handles.push(std::thread::spawn(move || {
resilience_clone
.execute(|| {
Ok::<_, ProcessError>(observer_clone.on_event(&event_clone, &request_clone))
})
.unwrap_or_else(|err| {
ProcessResponseDto::new(
&format!(
"{}-{:06}",
observer_clone.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
observer_clone.observer_name(),
false,
&err.to_string(),
)
})
}));
}
// 等待全部并发线程完成,按顺序收集响应
handles
.into_iter()
.map(|h| {
h.join()
.unwrap_or_else(|_| ProcessResponseDto::new("", "未知", false, "线程异常"))
})
.collect()
}
}
/// 实现主题抽象接口
impl Subject for ConcreteEventBus {
/// 订阅:注册观察者到主题
fn attach(&self, observer: Arc<dyn Observer>) -> Result<(), ProcessError> {
let mut observers = self.observers.lock().unwrap();
// 防重复订阅
if observers
.iter()
.any(|o| o.observer_id() == observer.observer_id())
{
return Err(ProcessError::new(
"DUPLICATE_SUBSCRIBER",
&format!("观察者 {} 已订阅,禁止重复订阅", observer.observer_id()),
));
}
// 经观察者自身的统一日志对象输出订阅确认(体现日志注入)
observer
.logger()
.debug(&format!("观察者 {} 已订阅到主题(事件总线)", observer.observer_id()));
observers.push(observer);
self.logger.debug("观察者订阅流程完成");
Ok(())
}
/// 退订:从主题移除观察者
fn detach(&self, observer_id: &str) -> Result<(), ProcessError> {
let mut observers = self.observers.lock().unwrap();
let before = observers.len();
observers.retain(|o| o.observer_id() != observer_id);
if observers.len() == before {
return Err(ProcessError::new(
"NOT_FOUND",
&format!("未找到观察者:{}", observer_id),
));
}
self.logger
.debug(&format!("观察者 {} 已退订", observer_id));
Ok(())
}
/// 获取全部已订阅观察者
fn observers(&self) -> Vec<Arc<dyn Observer>> {
self.snapshot()
}
/// 同步广播事件:通知所有订阅该事件的观察者
fn notify(
&self,
event: &BusinessEvent,
request: &ProcessRequestDto,
) -> Vec<ProcessResponseDto> {
let snapshot = self.snapshot();
let mut responses = Vec::new();
for observer in snapshot {
// 仅通知订阅了该事件的观察者
if !Self::is_subscribed(&observer, event) {
continue;
}
self.logger.debug(&format!(
"主题广播事件【{}】→ 观察者 {}",
event.tag(),
observer.observer_id()
));
let observer_clone = observer.clone();
let event_clone = *event;
let request_clone = request.clone();
// 经「重试 + 熔断」执行观察者响应
let response = self
.resilience
.execute(|| {
Ok::<_, ProcessError>(observer_clone.on_event(&event_clone, &request_clone))
})
.unwrap_or_else(|err| {
ProcessResponseDto::new(
&format!(
"{}-{:06}",
observer_clone.observer_id(),
crate::domain::entities::jewelry::next_sequence()
),
observer_clone.observer_name(),
false,
&err.to_string(),
)
});
responses.push(response);
}
responses
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : process_service.rs
//!
//! 业务流程应用服务(调度器)
//!
//! 职责:
//! – 持有具体主题(`Arc<ConcreteEventBus>`)与仓储(构造器注入)
//! – 驱动主题按供应链顺序 / 并发方式广播业务事件(观察者模式调度)
//! – 调用仓储保存执行记录
//! – 提供统计、记录查询、观察者清单能力
//!
//! 全部日志通过统一日志对象(`Arc<dyn Logger>`)输出,控制台与文件一致。
use std::sync::Arc;
use crate::application::observer::concrete_event_bus::ConcreteEventBus;
use crate::common::error::ProcessError;
use crate::common::logging::Logger;
use crate::domain::dtos::process_dtos::{ProcessRequestDto, ProcessResponseDto};
use crate::domain::entities::jewelry::ProcessOutcome;
use crate::domain::observer::business_event::BusinessEvent;
use crate::domain::observer::observer::Observer;
use crate::domain::observer::subject::Subject;
use crate::domain::repository::process_repository::{ProcessRecord, ProcessRepository};
/// 业务流程应用服务(观察者模式调度器)
pub struct ProcessService {
/// 具体主题(事件总线,依赖注入)
topic: Arc<ConcreteEventBus>,
/// 流程仓储(依赖注入)
repository: Arc<dyn ProcessRepository>,
/// 统一日志(依赖注入)
logger: Arc<dyn Logger>,
}
impl ProcessService {
/// 创建业务流程应用服务
///
/// # 参数
/// – `topic`:具体主题(事件总线)
/// – `repository`:流程仓储
/// – `logger`:统一日志
///
/// # 返回
/// 应用服务实例
pub fn new(
topic: Arc<ConcreteEventBus>,
repository: Arc<dyn ProcessRepository>,
logger: Arc<dyn Logger>,
) -> Self {
Self {
topic,
repository,
logger,
}
}
/// 顺序调度:先广播「流程启动」事件(一对多通知全部观察者),
/// 再按供应链顺序逐一广播各核心事件并保存执行记录。
///
/// # 参数
/// – `request`:执行请求 DTO
///
/// # 返回
/// 各核心事件主观察者执行响应集合
pub fn run_sequential(&self, request: ProcessRequestDto) -> Vec<ProcessResponseDto> {
// ① 广播流程启动事件:主题通知所有订阅者(一对多广播)
self.logger.info("========== 主题广播【流程启动】事件(通知全部观察者) ==========");
let start_responses = self
.topic
.notify(&BusinessEvent::ProcessStarted, &request);
self.logger
.info(&format!("流程启动事件已广播,收到通知的观察者数:{}", start_responses.len()));
// ② 按供应链顺序广播各核心完成事件
self.logger.info("========== 观察者顺序调度:按供应链广播核心事件 ==========");
let mut recorded = Vec::new();
for event in BusinessEvent::all_core_events() {
let responses = self.topic.notify(&event, &request);
// 每个核心事件由对应主观察者执行,取全部响应保存
recorded.extend(responses);
}
self.save_responses(&recorded);
recorded
}
/// 并发调度:对每个核心完成事件开独立线程广播(高并发演示),并保存执行记录。
///
/// # 参数
/// – `request`:执行请求 DTO
///
/// # 返回
/// 各核心事件主观察者执行响应集合
pub fn run_concurrent(&self, request: ProcessRequestDto) -> Vec<ProcessResponseDto> {
self.logger
.info("========== 观察者并发调度:多线程高并发广播核心事件 ==========");
let mut handles = Vec::new();
for event in BusinessEvent::all_core_events() {
let topic_clone = self.topic.clone();
let request_clone = request.clone();
// 每个核心事件一个线程,高并发广播
handles.push(std::thread::spawn(move || {
topic_clone.notify_concurrent(&event, &request_clone)
}));
}
// 收集全部并发结果
let mut recorded = Vec::new();
for handle in handles {
if let Ok(responses) = handle.join() {
recorded.extend(responses);
}
}
self.save_responses(&recorded);
recorded
}
/// 发布单个核心事件(供端口契约使用;经主题广播)
///
/// # 参数
/// – `event_id`:事件对应的主部门标识(如 PROCUREMENT / TRAINING)
/// – `request`:执行请求 DTO
///
/// # 返回
/// – `Ok(ProcessResponseDto)`:主观察者执行响应
/// – `Err(ProcessError)`:未知事件标识或广播失败
pub fn publish_single(
&self,
event_id: &str,
request: ProcessRequestDto,
) -> Result<ProcessResponseDto, ProcessError> {
let event = BusinessEvent::from_id(event_id).ok_or_else(|| {
ProcessError::new("NOT_FOUND", &format!("未知事件标识:{}", event_id))
})?;
let responses = self.topic.notify(&event, &request);
let response = responses
.into_iter()
.find(|r| r.instance_id.starts_with(event.id()))
.ok_or_else(|| {
ProcessError::new(
"NOT_SUBSCRIBER",
&format!("事件【{}】没有对应主观察者", event.tag()),
)
})?;
self.save_responses(&[response.clone()]);
Ok(response)
}
/// 保存一批执行记录(内部辅助)
///
/// # 参数
/// – `responses`:执行响应集合
fn save_responses(&self, responses: &[ProcessResponseDto]) {
for resp in responses {
let outcome = if resp.success {
ProcessOutcome::success(&resp.instance_id, &resp.message)
} else {
ProcessOutcome::failure(&resp.instance_id, &resp.message)
};
let record = ProcessRecord {
instance_id: resp.instance_id.clone(),
process_name: resp.process_name.clone(),
outcome,
executed_at: chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(),
};
if let Err(err) = self.repository.save(record) {
self.logger.error(&format!("保存业务执行记录失败:{}", err));
}
}
}
/// 获取全部已订阅观察者清单(经主题)
///
/// # 返回
/// 全部观察者实例
pub fn observers(&self) -> Vec<Arc<dyn Observer>> {
self.topic.observers()
}
/// 获取业务执行统计(成功数量,失败数量)
///
/// # 返回
/// `(成功数量, 失败数量)` 元组
pub fn statistics(&self) -> (usize, usize) {
self.repository.count()
}
/// 获取全部业务执行记录(用于追溯/汇总展示)
///
/// # 返回
/// 全部执行记录
pub fn records(&self) -> Vec<ProcessRecord> {
self.repository.find_all()
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : retry_circuit_breaker.rs
//! 重试 + 熔断适配器(Resilience Adapter)
//!
//! 作用:在中介者协调同事执行依赖外部系统(如质检系统、物流接口、财务网关)时,
//! 提供「自动重试 + 熔断保护」:
//! – **重试**:瞬时失败时按指数退避重试,直至达到最大重试次数。
//! – **熔断**:连续失败达到阈值后打开熔断器,快速失败(不再重试),
//! 经冷却时间后进入半开状态,试探恢复。
//!
//! 线程安全:内部状态使用 `Mutex` 保护,可被 `Arc` 共享到多个线程高并发使用。
use std::sync::Mutex;
use std::time::{Duration, Instant};
use crate::common::error::ProcessError;
/// 熔断器打开错误码
const ERROR_CIRCUIT_OPEN: &str = "CIRCUIT_OPEN";
/// 熔断器状态
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CircuitState {
/// 关闭(正常运行,允许调用)
Closed,
/// 打开(熔断,快速失败)
Open,
/// 半开(冷却结束,试探性放行一次)
HalfOpen,
}
/// 熔断器内部状态(受互斥锁保护)
struct CircuitInner {
/// 当前熔断状态
state: CircuitState,
/// 连续失败次数
consecutive_failures: u32,
/// 熔断打开时刻(用于计算冷却时间)
opened_at: Option<Instant>,
}
/// 重试 + 熔断适配器(线程安全、可共享)
pub struct RetryCircuitBreaker {
/// 最大重试次数(成功之前最多额外尝试的次数)
max_retries: u32,
/// 熔断失败阈值(连续失败达到该次数即打开熔断器)
failure_threshold: u32,
/// 熔断冷却时间(打开后等待该时长才允许半开试探)
cooldown: Duration,
/// 内部熔断状态
inner: Mutex<CircuitInner>,
}
impl RetryCircuitBreaker {
/// 创建重试 + 熔断适配器
///
/// # 参数
/// – `max_retries`:最大重试次数
/// – `failure_threshold`:熔断失败阈值
/// – `cooldown`:熔断冷却时长
///
/// # 返回
/// 适配器实例
pub fn new(max_retries: u32, failure_threshold: u32, cooldown: Duration) -> Self {
Self {
max_retries,
failure_threshold,
cooldown,
inner: Mutex::new(CircuitInner {
state: CircuitState::Closed,
consecutive_failures: 0,
opened_at: None,
}),
}
}
/// 获取当前熔断状态(用于日志输出)
///
/// # 返回
/// 当前 `CircuitState`
#[allow(dead_code)]
pub fn state(&self) -> CircuitState {
self.inner
.lock()
.map(|g| g.state)
.unwrap_or(CircuitState::Closed)
}
/// 执行受保护的操作:带「重试 + 熔断」
///
/// # 泛型参数
/// – `F`:操作闭包类型
/// – `O`:成功返回值类型
///
/// # 参数
/// – `operation`:返回 `Result<O, ProcessError>` 的操作闭包
///
/// # 返回
/// – `Ok(O)`:操作最终成功
/// – `Err(ProcessError)`:重试耗尽或熔断快速失败
pub fn execute<F, O>(&self, operation: F) -> Result<O, ProcessError>
where
F: Fn() -> Result<O, ProcessError>,
{
// 步骤一:熔断前置检查(快速失败)
{
let mut guard = self.inner.lock().unwrap();
if guard.state == CircuitState::Open {
if let Some(opened_at) = guard.opened_at {
// 冷却时间未过 → 直接快速失败
if opened_at.elapsed() < self.cooldown {
return Err(ProcessError::new(
ERROR_CIRCUIT_OPEN,
"熔断器已打开,请求快速失败,请稍后重试",
));
}
}
// 冷却时间已过 → 转为半开状态,允许一次试探
guard.state = CircuitState::HalfOpen;
}
}
// 步骤二:带重试地执行操作
let mut attempt = 0u32;
loop {
match operation() {
Ok(value) => {
// 成功:重置失败计数,恢复关闭状态
let mut guard = self.inner.lock().unwrap();
guard.consecutive_failures = 0;
guard.state = CircuitState::Closed;
guard.opened_at = None;
return Ok(value);
}
Err(err) => {
attempt += 1;
{
let mut guard = self.inner.lock().unwrap();
guard.consecutive_failures += 1;
// 连续失败达到阈值 → 打开熔断器
if guard.consecutive_failures >= self.failure_threshold {
guard.state = CircuitState::Open;
guard.opened_at = Some(Instant::now());
return Err(err);
}
}
// 未熔断但重试次数已耗尽 → 返回错误
if attempt > self.max_retries {
return Err(err);
}
// 指数退避等待后重试
std::thread::sleep(Duration::from_millis(100 * attempt as u64));
}
}
}
}
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : error.rs
//! 统一错误类型定义
//!
//! 全项目统一使用 `ProcessError` 作为业务错误载体,携带错误码与消息,
//! 便于上层(应用层/接口层/表现层)统一捕获与日志输出。
/// 业务流程错误(统一错误载体)
#[derive(Debug, Clone)]
pub struct ProcessError {
/// 错误码(如 EXECUTION_FAILED / CIRCUIT_OPEN 等)
pub code: String,
/// 错误消息(中文,可直接输出到日志与界面)
pub message: String,
}
impl ProcessError {
/// 创建业务流程错误
///
/// # 参数
/// – `code`:错误码
/// – `message`:错误消息
///
/// # 返回
/// 构造好的 `ProcessError` 实例
pub fn new(code: &str, message: &str) -> Self {
Self {
code: code.to_string(),
message: message.to_string(),
}
}
}
/// 格式化输出(支持 `{}` 直接打印)
impl std::fmt::Display for ProcessError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}] {}", self.code, self.message)
}
}
/// 实现标准 Error trait,可向上转换为 `Box<dyn Error>`
impl std::error::Error for ProcessError {}
/// 预留的标准错误码字典(供上层业务模块调用,作为统一错误码契约预留给扩展)
#[allow(dead_code)]
pub mod error_code {
/// 前置校验失败
pub const VALIDATE_FAILED: &str = "VALIDATE_FAILED";
/// 业务执行失败
pub const EXECUTION_FAILED: &str = "EXECUTION_FAILED";
/// 熔断器打开(快速失败)
pub const CIRCUIT_OPEN: &str = "CIRCUIT_OPEN";
/// 资源未找到
pub const NOT_FOUND: &str = "NOT_FOUND";
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : logging.rs
//! 统一日志抽象接口(对应 C# 中的 `ILogger<T>`)
//!
//! 所有组件(调度器、中介者、同事、入口)仅依赖该接口输出日志,
//! 具体实现(文件日志)由基础设施层通过 DI 注入。
//! 保证控制台输出与日志文件输出格式完全一致。
//!
//! 日志文件规约:
//! ```text
//! Logs/
//! 2026-07-06/
//! app-info.log
//! app-error.log
//! app-debug.log
//! app-warn.log
//! ```
/// 日志等级
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogLevel {
/// 调试(用于输出详细执行过程)
Debug,
/// 信息(用于输出常规流程状态)
Info,
/// 警告(用于输出可恢复异常)
Warn,
/// 错误(用于输出失败/异常)
Error,
}
impl LogLevel {
/// 获取日志等级标签(用于日志前缀,控制台与文件一致)
///
/// # 返回
/// 等级标签字符串
pub fn tag(&self) -> &'static str {
match self {
LogLevel::Debug => "DEBUG",
LogLevel::Info => "INFO",
LogLevel::Warn => "WARN",
LogLevel::Error => "ERROR",
}
}
/// 获取日志等级对应的文件名(按等级分文件)
///
/// # 返回
/// 文件名(如 `app-info.log`)
pub fn file_name(&self) -> &'static str {
match self {
LogLevel::Debug => "app-debug.log",
LogLevel::Info => "app-info.log",
LogLevel::Warn => "app-warn.log",
LogLevel::Error => "app-error.log",
}
}
}
/// 统一日志接口(线程安全、可对象化注入使用)
///
/// 设计要点:
/// – `Send + Sync` 保证可在多线程/高并发环境下共享(`Arc<dyn Logger>`)
/// – 方法非泛型,保持对象安全(object-safe),可向上转型为 trait 对象注入
pub trait Logger: Send + Sync {
/// 输出调试日志
///
/// # 参数
/// – `message`:日志消息
fn debug(&self, message: &str);
/// 输出信息日志
///
/// # 参数
/// – `message`:日志消息
fn info(&self, message: &str);
/// 输出警告日志
///
/// # 参数
/// – `message`:日志消息
fn warn(&self, message: &str);
/// 输出错误日志
///
/// # 参数
/// – `message`:日志消息
fn error(&self, message: &str);
}
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : result.rs
//! 统一结果返回类型
//!
//! 用于表现层/接口层向调用方返回统一结构的操作结果,保证输出格式一致。
/// 通用操作结果(泛型,表现层返回载体)
///
/// 预留给需要结构化返回(成功/失败 + 业务数据)的调用方使用;
/// 当前控制台演示直接输出日志,未构造该结果,属预留 API。
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ApiResult<T> {
/// 是否成功
pub success: bool,
/// 结果消息
pub message: String,
/// 业务数据(可选)
pub data: Option<T>,
}
impl<T> ApiResult<T> {
/// 创建成功结果
///
/// # 参数
/// – `data`:业务数据
///
/// # 返回
/// 成功结果
#[allow(dead_code)]
pub fn ok(data: T) -> Self {
Self {
success: true,
message: "操作成功".to_string(),
data: Some(data),
}
}
/// 创建失败结果
///
/// # 参数
/// – `message`:失败消息
///
/// # 返回
/// 失败结果
#[allow(dead_code)]
pub fn err(message: &str) -> Self {
Self {
success: false,
message: message.to_string(),
data: None,
}
}
}
调用:
//!# encoding: utf-8
//!# 版权所有 2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:观察者模式Observer Pattern 行为模式 Behavioral Patterns
//!# Author : geovindu,Geovin Du 涂聚文.
//!# IDE : RustRover 2025.1.1 Rust rustc 1.98.1
//!# os : windows 10
//!# database : mysql 9.0 sql server 2025, postgreSQL 18.0 Oracle 21c Neo4j
//!# Datetime : 2026/10/21 21:42
//!# User : geovindu
//!# Product : RustRover
//!# Project : ObserverPattern
//!# File : main.rs
//! 观察者模式(Observer Pattern)— 珠宝行业企业级全程业务流程
//!
//! 业务范围:原料采购核验、设计制图、加工生产、质检、包装、物流、财务、
//! 营销推广、业务销售、人事行政、IT、培训。
//!
//! 观察者模式核心思想:
//! – **Subject(主题)**:维护观察者注册表,状态变化时广播(notify)事件,
//! 主题不关心有哪些订阅者、订阅者是谁。
//! – **Observer(观察者)**:订阅主题感兴趣的事件,收到通知后自行响应
//! (推模型);新增观察者无需改动主题,完全可扩展。
//! – 通过主题广播,12 个部门作为观察者解耦协作:发布「流程启动」事件时
//! 所有部门同时收到通知(一对多);发布各部门完成事件时,对应部门执行
//! 核心业务(物流经重试熔断演示瞬时失败恢复)。
//!
//! 工程化特性:
//! – 日志按日期分文件夹、按日志等级分文件(Logs/2026-07-06/app-*.log)
//! – 注入统一日志对象 `Arc<dyn Logger>`(对应 C# 的 `ILogger<T>`)
//! – DTO 业务传输对象、适配器「重试 + 熔断」
//! – 兼容依赖注入(DI)、线程安全、高并发写入
//! – 调度器 / 观察者 / 入口全部使用统一标准日志,控制台与文件输出完全一致
//!
//! DDD 严格分层(依赖方向:presentation → interface → application → domain → common;
//! infrastructure 实现 domain/interface 定义的接口):
//! – domain 领域层(实体、DTO、观察者/主题抽象、业务事件、仓储接口)
//! – common 通用层(错误、结果、日志接口、重试熔断)
//! – application 应用层(具体主题、12 个观察者、应用服务调度器)
//! – infrastructure 基础设施层(文件日志、DI 容器、内存仓储)
//! – interface 接口层(对外端口契约、业务信封契约)
//! – presentation 表现层(控制台入口 / 组合根装配 / 端口实现)
// 声明顶层模块(对应六个文件夹)
mod application;
mod common;
mod domain;
mod infrastructure;
mod interface;
mod presentation;
use std::sync::Arc;
use infrastructure::di::container::ServiceContainer;
use presentation::console::controller::ApplicationController;
/// 程序入口(组合根:装配依赖注入容器 → 创建应用控制器 → 启动观察者广播演示)
fn main() {
// 1. 构建依赖注入容器(组合根,统一装配主题、观察者与全部服务)
let container = Arc::new(ServiceContainer::new());
// 2. 创建应用控制器(表现层,实现 interface 定义的对外端口契约)
let controller = ApplicationController::new(container);
// 3. 启动珠宝行业全程业务流程(观察者模式)演示
controller.run();
}
输出:





