CSharp: Observer Pattern

前言

在珠宝业务系统中,从原料采购、设计加工到质检、物流、财务、营销乃至人事培训,一条完整业务链路往往横跨多个部门。传统做法是各部门在流程节点上轮询或硬编码调用,导致模块之间高度耦合、扩展困难。观察者模式(Observer Pattern)通过「主题发布、观察者订阅」的方式,让业务阶段变更事件能够按需精准通知到对应部门,既降低了耦合,又提升了系统的可维护性与并发能力。本文以 C# .NET 10 为例,结合领域事件、依赖注入与重试熔断机制,完整演示观察者模式在珠宝全流程业务中的落地实践。

一、观察者模式核心概念

观察者模式属于行为型设计模式,核心思想是定义对象间一对多的依赖关系:当一个对象(主题 Subject)的状态发生变化时,所有依赖它的对象(观察者 Observer)都会收到通知并自动更新。在珠宝业务场景中,业务流程聚合根作为主题,各业务部门观察者订阅自己关心的阶段,从而实现业务链路的解耦与并行处理。

1.1 模式角色划分

  • 主题(Subject) :维护观察者列表,提供注册、注销与通知方法,对应代码中的 IJewelBusinessSubjectJewelBusinessSubject
  • 观察者(Observer) :定义接收通知的更新接口,对应 IJewelObserver 及各业务部门观察者实现。
  • 具体主题(ConcreteSubject) :维护业务状态,状态变化时触发通知,对应 JewelBusinessFlow 聚合根。
  • 具体观察者(ConcreteObserver):实现具体的业务响应逻辑,对应采购部、设计部、质检部等观察者。

1.2 领域事件与观察者模式的结合

领域事件(Domain Event)是观察者模式在领域驱动设计(DDD)中的典型应用。当业务流程阶段发生变更时,聚合根产生一个 JewelStageChangedEvent 领域事件,主题将其发布给订阅了对应阶段的观察者。这种方式让业务规则与通知逻辑解耦,各观察者只需关心自己订阅的阶段,无需了解其他部门的处理细节。

二、珠宝业务观察者模式实战

本节基于 C# .NET 10 与 Visual Studio 2026,从领域模型、主题实现、观察者注册到高并发调度,逐步搭建完整的珠宝业务观察者模式示例。

2.1 领域模型与业务流程聚合根

首先定义珠宝原料、成品等实体,以及业务流程聚合根。聚合根维护全流程阶段顺序与状态机,通过 AdvanceToNextStage 方法推进业务阶段,并在阶段变更时产生领域事件。

2.2 主题与观察者接口设计

主题接口 IJewelBusinessSubject 负责订阅管理与事件发布;观察者接口 IJewelObserver 声明关心的阶段集合与事件处理方法。主题实现采用 ConcurrentDictionary 按阶段隔离订阅集合,锁粒度最小,保证高并发安全。

2.3 观察者注册与依赖注入

通过 JewelObserverRegistrar 统一注册全部业务部门观察者,并在 DI 容器中按需解析。各观察者声明自己关心的阶段,主题发布时按阶段精准分发,避免无关部门收到无效通知。

2.4 高并发调度与重试熔断

调度器 JewelFlowScheduler 并行运行多条业务流程,模拟高并发写入场景。结合重试熔断机制(ResilienceAdapter),当业务执行失败时自动重试,达到阈值则打开熔断,保护下游系统稳定。

三、运行效果与日志输出

运行示例程序后,调度器并行执行 8 条珠宝业务流程,各阶段变更事件按订阅关系精准通知对应部门观察者。日志按日期、按等级分类写入程序目录 Logs 文件夹,便于追踪每条流程的完整业务链路与执行结果。

3.1 项目结构说明

示例项目采用分层架构,包含领域层(Domain)、应用层(Application)、基础设施层(Infrastructure)与表现层(BLL),各层职责清晰,便于扩展与维护。

3.2 关键代码解读

主题实现中,ConcurrentDictionary<JewelStage, ConcurrentDictionary<IJewelObserver, byte>> 按阶段隔离订阅集合,发布时使用 Parallel 并行通知观察者,观察者经 ILogger 写日志,保证线程安全与高效分发。

总结

本文以珠宝全流程业务为背景,完整演示了观察者模式在 C# .NET 10 中的落地实践。通过领域事件解耦业务阶段与部门响应,结合依赖注入、并行调度与重试熔断机制,构建了一个高并发、易扩展、可维护的业务链路系统。观察者模式不仅适用于珠宝行业,在电商订单流转、审批流、消息推送等场景同样具有广泛的参考价值。

参考资料

  • GoF 设计模式:可复用面向对象软件的基础(Erich Gamma 等)
  • 领域驱动设计:软件核心复杂性应对之道(Eric Evans)
  • Microsoft 官方文档:.NET 依赖注入与通用主机
  • Microsoft 官方文档:ConcurrentDictionary 与并行编程
  • Karambolo.Extensions.Logging.File:文件日志组件文档

项目结构:

cs 复制代码
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelBusinessFlow.cs
*/
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern.Domain.Entities
{
/// <summary>
/// 珠宝业务流程聚合根,维护业务流转顺序与状态机
/// </summary>
public sealed class JewelBusinessFlow
{
/// <summary>
/// 全流程固定阶段顺序(保证业务链闭环)
/// </summary>
private static readonly IReadOnlyList<JewelStage> StageSequence = new[]
{
JewelStage.RawMaterialVerify,
JewelStage.DesignDrawing,
JewelStage.Processing,
JewelStage.QualityInspection,
JewelStage.Packaging,
JewelStage.Logistics,
JewelStage.Finance,
JewelStage.Marketing,
JewelStage.SalesBusiness,
JewelStage.HrAdmin,
JewelStage.ItOps,
JewelStage.Training
};
    /// &lt;summary&gt;
    /// 业务流程实例 ID
    /// &lt;/summary&gt;
    public string FlowId { get; }

    /// &lt;summary&gt;
    /// 关联原料
    /// &lt;/summary&gt;
    public JewelRawMaterial RawMaterial { get; }

    /// &lt;summary&gt;
    /// 关联成品
    /// &lt;/summary&gt;
    public JewelProduct Product { get; }

    /// &lt;summary&gt;
    /// 当前所处阶段
    /// &lt;/summary&gt;
    public JewelStage CurrentStage { get; private set; }

    /// &lt;summary&gt;
    /// 流程状态:Running 运行中 / Completed 已完成 / Error 异常
    /// &lt;/summary&gt;
    public string FlowStatus { get; private set; }

    /// &lt;summary&gt;
    /// 全流程只读阶段顺序(对外暴露)
    /// &lt;/summary&gt;
    public IReadOnlyList&lt;JewelStage&gt; AllStages =&gt; StageSequence;

    /// &lt;summary&gt;
    /// 构造业务流程聚合根,初始状态为第一阶段的运行中
    /// &lt;/summary&gt;
    /// &lt;param name="flowId"&gt;流程 ID&lt;/param&gt;
    /// &lt;param name="rawMaterial"&gt;原料&lt;/param&gt;
    /// &lt;param name="product"&gt;成品&lt;/param&gt;
    public JewelBusinessFlow(string flowId, JewelRawMaterial rawMaterial, JewelProduct product)
    {
        FlowId = flowId;
        RawMaterial = rawMaterial;
        Product = product;
        CurrentStage = StageSequence[0];
        FlowStatus = "Running";
    }

    /// &lt;summary&gt;
    /// 推进到下一阶段,返回新阶段;已是最后阶段则置为已完成并返回 null
    /// &lt;/summary&gt;
    /// &lt;returns&gt;推进后的阶段,流程结束时返回 null&lt;/returns&gt;
    public JewelStage? AdvanceToNextStage()
    {
        // 找到当前阶段在顺序表中的索引
        int currentIndex = Array.IndexOf([.. StageSequence], CurrentStage);
        int nextIndex = currentIndex + 1;

        // 已是最后一个阶段,标记完成
        if (nextIndex &gt;= StageSequence.Count)
        {
            FlowStatus = "Completed";
            return null;
        }

        // 更新为下一阶段
        CurrentStage = StageSequence[nextIndex];
        return CurrentStage;
    }
}
}
/*
encoding: utf-8
版权所有  2026 ©涂聚文有限公司™ ®
许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
Author    : geovindu,Geovin Du 涂聚文.
IDE       : vs2026 c# .net 10
os        : windows 10
database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
Datetime  : 2026/07/04 22:16
User      :  geovindu
Product   : Visual Studio 2026
Project   : CSharpDesignPattern
File      : JewelProduct.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern.Domain.Entities
{
/// <summary>
/// 珠宝成品实体(领域模型)
/// </summary>
public sealed class JewelProduct
{
/// <summary>
/// 成品唯一编号
/// </summary>
public string ProductCode { get; }
    /// &lt;summary&gt;
    /// 成品名称(如"钻石吊坠")
    /// &lt;/summary&gt;
    public string ProductName { get; }

    /// &lt;summary&gt;
    /// 零售定价(元)
    /// &lt;/summary&gt;
    public decimal RetailPrice { get; }

    /// &lt;summary&gt;
    /// 构造成品实体
    /// &lt;/summary&gt;
    /// &lt;param name="productCode"&gt;成品编号&lt;/param&gt;
    /// &lt;param name="productName"&gt;成品名称&lt;/param&gt;
    /// &lt;param name="retailPrice"&gt;零售定价&lt;/param&gt;
    public JewelProduct(string productCode, string productName, decimal retailPrice)
    {
        ProductCode = productCode;
        ProductName = productName;
        RetailPrice = retailPrice;
    }
}
}
/*
encoding: utf-8
版权所有  2026 ©涂聚文有限公司™ ®
许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
Author    : geovindu,Geovin Du 涂聚文.
IDE       : vs2026 c# .net 10
os        : windows 10
database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
Datetime  : 2026/07/04 22:16
User      :  geovindu
Product   : Visual Studio 2026
Project   : CSharpDesignPattern
File      : JewelRawMaterial.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern.Domain.Entities
{
/// <summary>
/// 珠宝原料实体(领域模型)
/// </summary>
public sealed class JewelRawMaterial
{
/// <summary>
/// 原料唯一编号
/// </summary>
public string RawMaterialId { get; }
    /// &lt;summary&gt;
    /// 原料类型:黄金/铂金/钻石/宝石
    /// &lt;/summary&gt;
    public string MaterialType { get; }

    /// &lt;summary&gt;
    /// 原料重量
    /// &lt;/summary&gt;
    public decimal Weight { get; }

    /// &lt;summary&gt;
    /// 供应商名称
    /// &lt;/summary&gt;
    public string SupplierName { get; }

    /// &lt;summary&gt;
    /// 采购核验是否通过
    /// &lt;/summary&gt;
    public bool IsVerifyPass { get; }

    /// &lt;summary&gt;
    /// 构造原料实体
    /// &lt;/summary&gt;
    /// &lt;param name="rawMaterialId"&gt;原料编号&lt;/param&gt;
    /// &lt;param name="materialType"&gt;原料类型&lt;/param&gt;
    /// &lt;param name="weight"&gt;原料重量&lt;/param&gt;
    /// &lt;param name="supplierName"&gt;供应商名称&lt;/param&gt;
    /// &lt;param name="isVerifyPass"&gt;核验结果&lt;/param&gt;
    public JewelRawMaterial(
        string rawMaterialId,
        string materialType,
        decimal weight,
        string supplierName,
        bool isVerifyPass)
    {
        RawMaterialId = rawMaterialId;
        MaterialType = materialType;
        Weight = weight;
        SupplierName = supplierName;
        IsVerifyPass = isVerifyPass;
    }
}
}
/*
encoding: utf-8
版权所有  2026 ©涂聚文有限公司™ ®
许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
Author    : geovindu,Geovin Du 涂聚文.
IDE       : vs2026 c# .net 10
os        : windows 10
database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
Datetime  : 2026/07/04 22:16
User      :  geovindu
Product   : Visual Studio 2026
Project   : CSharpDesignPattern
File      : DomainEventBase.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern.Domain.Events
{
/// <summary>
/// 领域事件基类,所有领域事件继承该类
/// </summary>
public abstract class DomainEventBase
{
/// <summary>
/// 事件唯一标识
/// </summary>
public Guid EventId { get; }
    /// &lt;summary&gt;
    /// 事件发生时间戳(UTC)
    /// &lt;/summary&gt;
    public DateTime OccurTimeUtc { get; }

    /// &lt;summary&gt;
    /// 构造领域事件基类,初始化唯一标识与时间戳
    /// &lt;/summary&gt;
    protected DomainEventBase()
    {
        EventId = Guid.NewGuid();
        OccurTimeUtc = DateTime.UtcNow;
    }
}
}
/*
encoding: utf-8
版权所有  2026 ©涂聚文有限公司™ ®
许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
Author    : geovindu,Geovin Du 涂聚文.
IDE       : vs2026 c# .net 10
os        : windows 10
database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
Datetime  : 2026/07/04 22:16
User      :  geovindu
Product   : Visual Studio 2026
Project   : CSharpDesignPattern
File      : JewelStageChangedEvent.cs
*/
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern.Domain.Events
{
/// <summary>
/// 珠宝业务流程阶段变更领域事件,由主题发布、观察者消费
/// </summary>
public sealed class JewelStageChangedEvent : DomainEventBase
{
/// <summary>
/// 业务流程实例 ID
/// </summary>
public string FlowId { get; }
    /// &lt;summary&gt;
    /// 当前所处业务阶段
    /// &lt;/summary&gt;
    public JewelStage Stage { get; }

    /// &lt;summary&gt;
    /// 成品编号
    /// &lt;/summary&gt;
    public string ProductCode { get; }

    /// &lt;summary&gt;
    /// 原料编号
    /// &lt;/summary&gt;
    public string RawMaterialId { get; }

    /// &lt;summary&gt;
    /// 原料类型(黄金/铂金/钻石/宝石)
    /// &lt;/summary&gt;
    public string MaterialType { get; }

    /// &lt;summary&gt;
    /// 原料重量(克/克拉)
    /// &lt;/summary&gt;
    public decimal Weight { get; }

    /// &lt;summary&gt;
    /// 供应商名称
    /// &lt;/summary&gt;
    public string SupplierName { get; }

    /// &lt;summary&gt;
    /// 构造阶段变更事件
    /// &lt;/summary&gt;
    /// &lt;param name="flowId"&gt;业务流程 ID&lt;/param&gt;
    /// &lt;param name="stage"&gt;当前阶段&lt;/param&gt;
    /// &lt;param name="productCode"&gt;成品编号&lt;/param&gt;
    /// &lt;param name="rawMaterialId"&gt;原料编号&lt;/param&gt;
    /// &lt;param name="materialType"&gt;原料类型&lt;/param&gt;
    /// &lt;param name="weight"&gt;原料重量&lt;/param&gt;
    /// &lt;param name="supplierName"&gt;供应商名称&lt;/param&gt;
    public JewelStageChangedEvent(
        string flowId,
        JewelStage stage,
        string productCode,
        string rawMaterialId,
        string materialType,
        decimal weight,
        string supplierName)
    {
        FlowId = flowId;
        Stage = stage;
        ProductCode = productCode;
        RawMaterialId = rawMaterialId;
        MaterialType = materialType;
        Weight = weight;
        SupplierName = supplierName;
    }
}
}
/*
encoding: utf-8
版权所有  2026 ©涂聚文有限公司™ ®
许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
Author    : geovindu,Geovin Du 涂聚文.
IDE       : vs2026 c# .net 10
os        : windows 10
database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
Datetime  : 2026/07/04 22:16
User      :  geovindu
Product   : Visual Studio 2026
Project   : CSharpDesignPattern
File      : IJewelBusinessSubject.cs
*/
using ObserverPattern.Domain.Events;
using System;
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern.Domain.Interfaces
{
/// <summary>
/// 业务主题(发布者)接口,负责订阅管理与事件发布
/// </summary>
public interface IJewelBusinessSubject
{
/// <summary>
/// 注册(订阅)观察者
/// </summary>
/// <param name="observer">观察者实例</param>
void Attach(IJewelObserver observer);
    /// &lt;summary&gt;
    /// 注销(退订)观察者
    /// &lt;/summary&gt;
    /// &lt;param name="observer"&gt;观察者实例&lt;/param&gt;
    void Detach(IJewelObserver observer);

    /// &lt;summary&gt;
    /// 发布业务阶段变更事件,通知对应阶段的全部观察者
    /// &lt;/summary&gt;
    /// &lt;param name="evt"&gt;阶段变更事件&lt;/param&gt;
    void Notify(JewelStageChangedEvent evt);
}
}
/*
encoding: utf-8
版权所有  2026 ©涂聚文有限公司™ ®
许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
Author    : geovindu,Geovin Du 涂聚文.
IDE       : vs2026 c# .net 10
os        : windows 10
database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
Datetime  : 2026/07/04 22:16
User      :  geovindu
Product   : Visual Studio 2026
Project   : CSharpDesignPattern
File      : IJewelObserver.cs
*/
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern.Domain.Interfaces
{
/// <summary>
/// 观察者接口:所有业务部门观察者实现该接口,接收领域事件通知
/// </summary>
public interface IJewelObserver
{
/// <summary>
/// 本观察者关心的业务阶段集合(用于主题按阶段精准分发,降低耦合)
/// </summary>
IReadOnlyCollection<JewelStage> SubscribeStages { get; }
    /// &lt;summary&gt;
    /// 处理业务阶段变更事件
    /// &lt;/summary&gt;
    /// &lt;param name="evt"&gt;阶段变更领域事件&lt;/param&gt;
    void OnStageChanged(JewelStageChangedEvent evt);
}
}
/*
encoding: utf-8
版权所有  2026 ©涂聚文有限公司™ ®
许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
Author    : geovindu,Geovin Du 涂聚文.
IDE       : vs2026 c# .net 10
os        : windows 10
database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
Datetime  : 2026/07/04 22:16
User      :  geovindu
Product   : Visual Studio 2026
Project   : CSharpDesignPattern
File      : JewelBusinessSubject.cs
*/
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Domain.Interfaces;
using ObserverPattern.Shared;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern.Domain.Services
{
/// <summary>
/// 业务主题实现(发布者 Subject)
/// 采用 ConcurrentDictionary 按阶段隔离订阅集合,锁粒度最小,高并发安全
/// 发布时用 Parallel 并行通知观察者,观察者经 ILogger 写日志(线程安全)
/// </summary>
public class JewelBusinessSubject : IJewelBusinessSubject
{
/// <summary>
/// 日志注入
/// </summary>
private readonly ILogger<JewelBusinessSubject> _logger;
    /// &lt;summary&gt;
    /// 阶段 -&gt; 观察者集合的映射表(线程安全)
    /// 内层值使用 ConcurrentDictionary&lt;IJewelObserver, byte&gt; 当集合用,key 即观察者,保证去重
    /// &lt;/summary&gt;
    private readonly ConcurrentDictionary&lt;JewelStage, ConcurrentDictionary&lt;IJewelObserver, byte&gt;&gt; _observerMap;

    /// &lt;summary&gt;
    /// 构造主题,初始化映射表
    /// &lt;/summary&gt;
    /// &lt;param name="logger"&gt;日志实例&lt;/param&gt;
    public JewelBusinessSubject(ILogger&lt;JewelBusinessSubject&gt; logger)
    {
        _logger = logger;
        _observerMap = new ConcurrentDictionary&lt;JewelStage, ConcurrentDictionary&lt;IJewelObserver, byte&gt;&gt;();
    }

    /// &lt;summary&gt;
    /// 注册观察者:按观察者声明的关注阶段分别加入对应集合
    /// &lt;/summary&gt;
    /// &lt;param name="observer"&gt;观察者实例&lt;/param&gt;
    public void Attach(IJewelObserver observer)
    {
        // 遍历观察者关心的每个阶段
        foreach (JewelStage stage in observer.SubscribeStages)
        {
            // 获取或新建该阶段的观察者集合
            ConcurrentDictionary&lt;IJewelObserver, byte&gt; stageObservers =
                _observerMap.GetOrAdd(stage, _ =&gt; new ConcurrentDictionary&lt;IJewelObserver, byte&gt;());

            // 尝试加入,若已存在则忽略(原子操作,线程安全)
            if (stageObservers.TryAdd(observer, 0))
            {
                _logger.LogDebug(
                    "观察者 {ObserverName} 订阅阶段 {Stage} 成功",
                    observer.GetType().Name, stage);
            }
        }
    }

    /// &lt;summary&gt;
    /// 注销观察者:从其关注的各阶段集合中移除
    /// &lt;/summary&gt;
    /// &lt;param name="observer"&gt;观察者实例&lt;/param&gt;
    public void Detach(IJewelObserver observer)
    {
        // 遍历观察者关心的每个阶段
        foreach (JewelStage stage in observer.SubscribeStages)
        {
            // 若该阶段集合存在则尝试移除
            if (_observerMap.TryGetValue(stage, out ConcurrentDictionary&lt;IJewelObserver, byte&gt;? stageObservers)
                &amp;&amp; stageObservers != null
                &amp;&amp; stageObservers.TryRemove(observer, out _))
            {
                _logger.LogDebug(
                    "观察者 {ObserverName} 取消订阅阶段 {Stage}",
                    observer.GetType().Name, stage);
            }
        }
    }

    /// &lt;summary&gt;
    /// 发布阶段变更事件:并行通知该阶段全部观察者,单个观察者异常不阻断其他观察者
    /// &lt;/summary&gt;
    /// &lt;param name="evt"&gt;阶段变更事件&lt;/param&gt;
    public void Notify(JewelStageChangedEvent evt)
    {
        // 取出该阶段的观察者集合
        if (!_observerMap.TryGetValue(evt.Stage, out ConcurrentDictionary&lt;IJewelObserver, byte&gt;? stageObservers)
            || stageObservers == null || stageObservers.IsEmpty)
        {
            _logger.LogWarning("阶段 {Stage} 无任何观察者订阅,事件 FlowId:{FlowId} 被忽略",
                evt.Stage, evt.FlowId);
            return;
        }

        _logger.LogInformation(
            "发布阶段事件 FlowId:{FlowId} 阶段:{Stage} 产品:{ProductCode},通知观察者数:{Count}",
            evt.FlowId, evt.Stage, evt.ProductCode, stageObservers.Count);

        // 并行通知,观察者日志经 ILogger 线程安全写入,高并发安全
        Parallel.ForEach(stageObservers.Keys, observer =&gt;
        {
            try
            {
                observer.OnStageChanged(evt);
            }
            catch (Exception ex)
            {
                // 单个观察者异常不阻断整体通知,记录错误日志
                _logger.LogError(ex,
                    "通知观察者 {ObserverName} 处理阶段 {Stage} 事件时发生异常,FlowId:{FlowId}",
                    observer.GetType().Name, evt.Stage, evt.FlowId);
            }
        });
    }
}
}
cs 复制代码
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : IJewelFlowApplicationService.cs
 
 */
 
using ObserverPattern.Application.Dto;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Contracts
{
    /// <summary>
    /// 珠宝业务流程应用服务接口:定义完整业务用例
    /// </summary>
    public interface IJewelFlowApplicationService
    {
        /// <summary>
        /// 创建业务流程并推进到下一阶段(发布领域事件)
        /// </summary>
        /// <param name="inputDto">流程创建输入 DTO</param>
        /// <returns>流程当前 DTO</returns>
        Task<JewelBusinessFlowDto> CreateAndAdvanceFlowAsync(JewelBusinessFlowDto inputDto);
 
        /// <summary>
        /// 运行完整珠宝业务链路(从采购核验到培训),每阶段发布领域事件
        /// </summary>
        /// <param name="inputDto">流程创建输入 DTO</param>
        /// <returns>完成后的流程 DTO</returns>
        Task<JewelBusinessFlowDto> RunFullFlowAsync(JewelBusinessFlowDto inputDto);
    }
}
 
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelBusinessFlowDto.cs
 
 */
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Dto
{
    /// <summary>
    /// 业务流程创建/查询传输对象
    /// </summary>
    public sealed class JewelBusinessFlowDto
    {
        /// <summary>
        /// 业务流程实例 ID
        /// </summary>
        public string FlowId { get; set; } = string.Empty;
 
        /// <summary>
        /// 原料信息
        /// </summary>
        public JewelRawMaterialDto? RawMaterial { get; set; }
 
        /// <summary>
        /// 成品信息
        /// </summary>
        public JewelProductDto? Product { get; set; }
 
        /// <summary>
        /// 当前所处阶段
        /// </summary>
        public JewelStage CurrentStage { get; set; }
 
        /// <summary>
        /// 流程状态:Running/Completed/Error
        /// </summary>
        public string FlowStatus { get; set; } = "Running";
    }
}
 
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelProductDto.cs
 
 */
 
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Dto
{
    /// <summary>
    /// 珠宝成品数据传输对象
    /// </summary>
    public sealed class JewelProductDto
    {
        /// <summary>
        /// 成品唯一编号
        /// </summary>
        public string ProductCode { get; set; } = string.Empty;
 
        /// <summary>
        /// 成品名称
        /// </summary>
        public string ProductName { get; set; } = string.Empty;
 
        /// <summary>
        /// 零售定价(元)
        /// </summary>
        public decimal RetailPrice { get; set; }
    }
}
 
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelRawMaterialDto.cs
 
 */
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Dto
{
    /// <summary>
    /// 珠宝原料数据传输对象(应用层边界对象)
    /// </summary>
    public sealed class JewelRawMaterialDto
    {
        /// <summary>
        /// 原料唯一编号
        /// </summary>
        public string RawMaterialId { get; set; } = string.Empty;
 
        /// <summary>
        /// 原料类型:黄金/铂金/钻石/宝石
        /// </summary>
        public string MaterialType { get; set; } = string.Empty;
 
        /// <summary>
        /// 原料重量
        /// </summary>
        public decimal Weight { get; set; }
 
        /// <summary>
        /// 供应商名称
        /// </summary>
        public string SupplierName { get; set; } = string.Empty;
 
        /// <summary>
        /// 采购核验是否通过
        /// </summary>
        public bool IsVerifyPass { get; set; }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : DesignDepartmentObserver.cs
 
 */
 
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 设计制图部门观察者
    /// </summary>
    public class DesignDepartmentObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<DesignDepartmentObserver> _logger;
 
        /// <summary>
        /// 构造设计制图观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public DesignDepartmentObserver(ILogger<DesignDepartmentObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "设计制图部门";
 
        /// <summary>
        /// 关注阶段:设计制图
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.DesignDrawing };
 
        /// <summary>
        /// 设计制图业务处理:3D 建模、结构出图、工艺参数输出
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行设计制图:成品 {ProductCode} 3D 建模与工艺图纸输出", evt.ProductCode);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : FinanceObserver.cs
 
 */
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 财务部门观察者
    /// </summary>
    public class FinanceObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<FinanceObserver> _logger;
 
        /// <summary>
        /// 构造财务观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public FinanceObserver(ILogger<FinanceObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "财务部门";
 
        /// <summary>
        /// 关注阶段:财务
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.Finance };
 
        /// <summary>
        /// 财务业务处理:成本核算、费用归集、应收应付记账
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行财务:成品 {ProductCode} 成本核算与应收应付记账", evt.ProductCode);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : HrAdminObserver.cs
 
 */
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 人事行政部门观察者
    /// </summary>
    public class HrAdminObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<HrAdminObserver> _logger;
 
        /// <summary>
        /// 构造人事行政观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public HrAdminObserver(ILogger<HrAdminObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "人事行政部门";
 
        /// <summary>
        /// 关注阶段:人事行政
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.HrAdmin };
 
        /// <summary>
        /// 人事行政业务处理:人力评估、产能人力调度、后勤保障
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行人事行政:业务人力评估与后勤保障", evt.FlowId);
        }
    }
}
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ItDepartmentObserver.cs
 
 */
 
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// IT 运维部门观察者
    /// </summary>
    public class ItDepartmentObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<ItDepartmentObserver> _logger;
 
        /// <summary>
        /// 构造 IT 运维观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public ItDepartmentObserver(ILogger<ItDepartmentObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "IT运维部门";
 
        /// <summary>
        /// 关注阶段:IT 运维
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.ItOps };
 
        /// <summary>
        /// IT 运维业务处理:链路日志采集、系统监控、异常告警
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行 IT 运维:流程 {FlowId} 链路日志采集与系统监控", evt.FlowId);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogisticsObserver.cs
 
 */
 
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 物流部门观察者
    /// </summary>
    public class LogisticsObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<LogisticsObserver> _logger;
 
        /// <summary>
        /// 构造物流观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public LogisticsObserver(ILogger<LogisticsObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "物流部门";
 
        /// <summary>
        /// 关注阶段:物流
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.Logistics };
 
        /// <summary>
        /// 物流业务处理:高值保价出库、物流单号生成、在途跟踪
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行物流:成品 {ProductCode} 保价出库与在途跟踪", evt.ProductCode);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ObserverBll.cs
 
 */
 
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 营销推广部门观察者
    /// </summary>
    public class MarketingObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<MarketingObserver> _logger;
 
        /// <summary>
        /// 构造营销推广观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public MarketingObserver(ILogger<MarketingObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "营销推广部门";
 
        /// <summary>
        /// 关注阶段:营销推广
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.Marketing };
 
        /// <summary>
        /// 营销推广业务处理:新品素材、线上线下推广配置
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行营销推广:成品 {ProductCode} 新品推广素材与活动配置", evt.ProductCode);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : PackObserver.cs
 
 */
 
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 包装部门观察者
    /// </summary>
    public class PackObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<PackObserver> _logger;
 
        /// <summary>
        /// 构造包装观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public PackObserver(ILogger<PackObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "包装部门";
 
        /// <summary>
        /// 关注阶段:包装
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.Packaging };
 
        /// <summary>
        /// 包装业务处理:礼盒、证书、防伪标签封装
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行包装:成品 {ProductCode} 礼盒与证书封装", evt.ProductCode);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ProduceDepartmentObserver.cs
 
 */
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 加工生产部门观察者
    /// </summary>
    public class ProduceDepartmentObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<ProduceDepartmentObserver> _logger;
 
        /// <summary>
        /// 构造加工生产观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public ProduceDepartmentObserver(ILogger<ProduceDepartmentObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "加工生产部门";
 
        /// <summary>
        /// 关注阶段:加工生产
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.Processing };
 
        /// <summary>
        /// 加工生产业务处理:铸造、镶嵌、抛光、执模
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行加工生产:成品 {ProductCode} 铸造/镶嵌/抛光工序启动", evt.ProductCode);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : PurchaseDepartmentObserver.cs
 
 */
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 原料采购核验部门观察者
    /// </summary>
    public class PurchaseDepartmentObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<PurchaseDepartmentObserver> _logger;
 
        /// <summary>
        /// 构造采购核验观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public PurchaseDepartmentObserver(ILogger<PurchaseDepartmentObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "原料采购核验部门";
 
        /// <summary>
        /// 关注阶段:原料采购核验
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.RawMaterialVerify };
 
        /// <summary>
        /// 采购核验业务处理:核对供应商资质、验金验石、登记入库
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug(
                "执行原料采购核验:原料 {RawId},类型 {MatType},重量 {Weight},供应商 {Supplier}",
                evt.RawMaterialId, evt.MaterialType, evt.Weight, evt.SupplierName);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : QualityCheckObserver.cs
 
 */
 
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 质检部门观察者
    /// </summary>
    public class QualityCheckObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<QualityCheckObserver> _logger;
 
        /// <summary>
        /// 构造质检观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public QualityCheckObserver(ILogger<QualityCheckObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "质检部门";
 
        /// <summary>
        /// 关注阶段:质检
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.QualityInspection };
 
        /// <summary>
        /// 质检业务处理:贵金属纯度、宝石分级、外观瑕疵检验
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行质检:成品 {ProductCode} 纯度检测与外观瑕疵检验", evt.ProductCode);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : SalesBusinessObserver.cs
 
 */
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 业务销售部门观察者
    /// </summary>
    public class SalesBusinessObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<SalesBusinessObserver> _logger;
 
        /// <summary>
        /// 构造业务销售观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public SalesBusinessObserver(ILogger<SalesBusinessObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "业务销售部门";
 
        /// <summary>
        /// 关注阶段:业务销售
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.SalesBusiness };
 
        /// <summary>
        /// 业务销售处理:货品入库门店、库存同步、客户订单对接
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行业务销售:成品 {ProductCode} 入库门店与库存同步", evt.ProductCode);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : TrainingObserver.cs
 
 */
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers.Departments
{
    /// <summary>
    /// 员工培训部门观察者
    /// </summary>
    public class TrainingObserver : JewelDepartmentObserverBase
    {
        /// <summary>
        /// 具体类型日志
        /// </summary>
        private readonly ILogger<TrainingObserver> _logger;
 
        /// <summary>
        /// 构造员工培训观察者
        /// </summary>
        /// <param name="logger">日志实例</param>
        public TrainingObserver(ILogger<TrainingObserver> logger) : base(logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称
        /// </summary>
        public override string DepartmentName => "员工培训部门";
 
        /// <summary>
        /// 关注阶段:员工培训
        /// </summary>
        public override IReadOnlyCollection<JewelStage> SubscribeStages =>
            new[] { JewelStage.Training };
 
        /// <summary>
        /// 员工培训业务处理:按新流程更新课件、安排实操培训
        /// </summary>
        /// <param name="evt">阶段事件</param>
        protected override void HandleBusiness(JewelStageChangedEvent evt)
        {
            _logger.LogDebug("执行员工培训:根据流程 {FlowId} 更新岗位培训课件", evt.FlowId);
        }
    }
}
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelDepartmentObserverBase.cs
 
 */
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Events;
using ObserverPattern.Domain.Interfaces;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers
{
    /// <summary>
    /// 部门观察者抽象基类:统一日志模板输出与生命周期,子类只需声明关注阶段与业务处理
    /// 职责单一、完全可扩展------新增部门只需继承本类
    /// </summary>
    public abstract class JewelDepartmentObserverBase : IJewelObserver
    {
        /// <summary>
        /// 日志抽象(子类注入的具体泛型日志)
        /// </summary>
        private readonly ILogger _logger;
 
        /// <summary>
        /// 构造部门观察者基类
        /// </summary>
        /// <param name="logger">日志实例</param>
        protected JewelDepartmentObserverBase(ILogger logger)
        {
            _logger = logger;
        }
 
        /// <summary>
        /// 部门名称(用于日志标识)
        /// </summary>
        public abstract string DepartmentName { get; }
 
        /// <summary>
        /// 本部门关注的业务阶段集合
        /// </summary>
        public abstract IReadOnlyCollection<JewelStage> SubscribeStages { get; }
 
        /// <summary>
        /// 观察者入口:统一输出收到的阶段事件,再委托子类执行业务
        /// </summary>
        /// <param name="evt">阶段变更事件</param>
        public void OnStageChanged(JewelStageChangedEvent evt)
        {
            // 统一日志模板,保证控制台与文件输出一致
            _logger.LogInformation(
                "[{Department}] 收到阶段事件 FlowId:{FlowId} 阶段:{Stage} 产品:{ProductCode}",
                DepartmentName, evt.FlowId, evt.Stage, evt.ProductCode);
 
            // 调用子类具体业务处理
            HandleBusiness(evt);
        }
 
        /// <summary>
        /// 子类实现的部门具体业务处理逻辑
        /// </summary>
        /// <param name="evt">阶段变更事件</param>
        protected abstract void HandleBusiness(JewelStageChangedEvent evt);
    }
}
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelObserverRegistrar.cs
 
 */
 
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ObserverPattern.Domain.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Observers
{
    /// <summary>
    /// 观察者统一注册器:从 DI 容器取出全部部门观察者并订阅到主题
    /// 职责单一------负责订阅装配;新增部门只需注册到 DI,本类自动装配
    /// </summary>
    public class JewelObserverRegistrar
    {
        /// <summary>
        /// 业务主题
        /// </summary>
        private readonly IJewelBusinessSubject _subject;
 
        /// <summary>
        /// DI 服务提供器
        /// </summary>
        private readonly IServiceProvider _serviceProvider;
 
        /// <summary>
        /// 日志注入
        /// </summary>
        private readonly ILogger<JewelObserverRegistrar> _logger;
 
        /// <summary>
        /// 构造注册器
        /// </summary>
        /// <param name="subject">业务主题</param>
        /// <param name="serviceProvider">DI 容器</param>
        /// <param name="logger">日志实例</param>
        public JewelObserverRegistrar(
            IJewelBusinessSubject subject,
            IServiceProvider serviceProvider,
            ILogger<JewelObserverRegistrar> logger)
        {
            _subject = subject;
            _serviceProvider = serviceProvider;
            _logger = logger;
        }
 
        /// <summary>
        /// 注册全部观察者:解析所有 IJewelObserver 实现并订阅到主题
        /// </summary>
        public void RegisterAllObservers()
        {
            // 从 DI 解析全部观察者实例
            IEnumerable<IJewelObserver> observers = _serviceProvider.GetServices<IJewelObserver>();
 
            // 逐个订阅
            foreach (IJewelObserver observer in observers)
            {
                _subject.Attach(observer);
                _logger.LogDebug("已注册观察者 {ObserverName}", observer.GetType().Name);
            }
        }
    }
}
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelFlowApplicationService.cs
 
 */
using Microsoft.Extensions.Logging;
using ObserverPattern.Application.Contracts;
using ObserverPattern.Application.Dto;
using ObserverPattern.Domain.Entities;
using ObserverPattern.Domain.Events;
using ObserverPattern.Domain.Interfaces;
using ObserverPattern.Infrastructure.Resilience;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Application.Services
{
    /// <summary>
    /// 珠宝业务流程应用服务:负责用例编排、领域模型构建、事件发布
    /// 使用重试熔断适配器包装对外/对内关键调用,职责单一、可扩展
    /// </summary>
    public class JewelFlowApplicationService : IJewelFlowApplicationService
    {
        /// <summary>
        /// 业务主题(发布者)
        /// </summary>
        private readonly IJewelBusinessSubject _businessSubject;
 
        /// <summary>
        /// 重试熔断适配器
        /// </summary>
        private readonly IResilienceAdapter _resilienceAdapter;
 
        /// <summary>
        /// 日志注入
        /// </summary>
        private readonly ILogger<JewelFlowApplicationService> _logger;
 
        /// <summary>
        /// 构造应用服务,构造函数注入全部依赖(构造器注入)
        /// </summary>
        /// <param name="businessSubject">业务主题</param>
        /// <param name="resilienceAdapter">重试熔断适配器</param>
        /// <param name="logger">日志实例</param>
        public JewelFlowApplicationService(
            IJewelBusinessSubject businessSubject,
            IResilienceAdapter resilienceAdapter,
            ILogger<JewelFlowApplicationService> logger)
        {
            _businessSubject = businessSubject;
            _resilienceAdapter = resilienceAdapter;
            _logger = logger;
        }
 
        /// <summary>
        /// 创建业务流程并推进到下一阶段,发布领域事件
        /// </summary>
        /// <param name="inputDto">流程创建输入</param>
        /// <returns>流程当前状态 DTO</returns>
        public Task<JewelBusinessFlowDto> CreateAndAdvanceFlowAsync(JewelBusinessFlowDto inputDto)
        {
            // 从 DTO 构建领域实体(应用层 -> 领域层)
            JewelBusinessFlow flow = MapToEntity(inputDto);
 
            // 获取当前阶段并构建事件
            JewelStage currentStage = flow.CurrentStage;
            JewelStageChangedEvent evt = BuildEvent(flow, currentStage);
 
            // 通过重试熔断适配器发布事件,保证可靠投递
            return _resilienceAdapter.ExecuteAsync(async () =>
            {
                _businessSubject.Notify(evt);
                _logger.LogDebug("流程 {FlowId} 已发布阶段 {Stage} 事件", flow.FlowId, currentStage);
                await Task.CompletedTask;
 
                // 推进到下一阶段并返回当前状态
                return MapToDto(flow);
            });
        }
 
        /// <summary>
        /// 运行完整业务链路,逐阶段推进并发布事件,带重试熔断保护
        /// </summary>
        /// <param name="inputDto">流程创建输入</param>
        /// <returns>完成后的流程 DTO</returns>
        public async Task<JewelBusinessFlowDto> RunFullFlowAsync(JewelBusinessFlowDto inputDto)
        {
            // 构建领域聚合根
            JewelBusinessFlow flow = MapToEntity(inputDto);
 
            _logger.LogInformation("流程 {FlowId} 开始运行完整业务链路", flow.FlowId);
 
            // 每个阶段推进 + 发布事件(用重试熔断保护,防止偶发失败导致链路中断)
            return await _resilienceAdapter.ExecuteAsync(async () =>
            {
                // 先发布当前阶段事件
                _businessSubject.Notify(BuildEvent(flow, flow.CurrentStage));
 
                // 循环推进到最后一阶段
                JewelStage? nextStage;
                while ((nextStage = flow.AdvanceToNextStage()) != null)
                {
                    // 发布推进后阶段的领域事件
                    _businessSubject.Notify(BuildEvent(flow, nextStage.Value));
                }
 
                _logger.LogInformation("流程 {FlowId} 全部阶段执行完毕,状态:{Status}", flow.FlowId, flow.FlowStatus);
                await Task.CompletedTask;
                return MapToDto(flow);
            });
        }
 
        /// <summary>
        /// 根据聚合根与阶段构建领域事件
        /// </summary>
        /// <param name="flow">业务流程聚合根</param>
        /// <param name="stage">当前阶段</param>
        /// <returns>阶段变更事件</returns>
        private static JewelStageChangedEvent BuildEvent(JewelBusinessFlow flow, JewelStage stage)
        {
            return new JewelStageChangedEvent(
                flowId: flow.FlowId,
                stage: stage,
                productCode: flow.Product.ProductCode,
                rawMaterialId: flow.RawMaterial.RawMaterialId,
                materialType: flow.RawMaterial.MaterialType,
                weight: flow.RawMaterial.Weight,
                supplierName: flow.RawMaterial.SupplierName);
        }
 
        /// <summary>
        /// 将输入 DTO 映射为领域聚合根
        /// </summary>
        /// <param name="inputDto">输入 DTO</param>
        /// <returns>领域聚合根</returns>
        private static JewelBusinessFlow MapToEntity(JewelBusinessFlowDto inputDto)
        {
            // 参数校验:原料与成品不可为空
            ArgumentNullException.ThrowIfNull(inputDto.RawMaterial, nameof(inputDto.RawMaterial));
            ArgumentNullException.ThrowIfNull(inputDto.Product, nameof(inputDto.Product));
 
            // 映射原料实体
            JewelRawMaterial material = new(
                rawMaterialId: inputDto.RawMaterial.RawMaterialId,
                materialType: inputDto.RawMaterial.MaterialType,
                weight: inputDto.RawMaterial.Weight,
                supplierName: inputDto.RawMaterial.SupplierName,
                isVerifyPass: inputDto.RawMaterial.IsVerifyPass);
 
            // 映射成品实体
            JewelProduct product = new(
                productCode: inputDto.Product.ProductCode,
                productName: inputDto.Product.ProductName,
                retailPrice: inputDto.Product.RetailPrice);
 
            // 流程 ID 为空则生成新 ID
            string flowId = string.IsNullOrWhiteSpace(inputDto.FlowId)
                ? Guid.NewGuid().ToString("N")
                : inputDto.FlowId;
 
            return new JewelBusinessFlow(flowId, material, product);
        }
 
        /// <summary>
        /// 将领域聚合根映射为输出 DTO
        /// </summary>
        /// <param name="flow">领域聚合根</param>
        /// <returns>输出 DTO</returns>
        private static JewelBusinessFlowDto MapToDto(JewelBusinessFlow flow)
        {
            return new JewelBusinessFlowDto
            {
                FlowId = flow.FlowId,
                CurrentStage = flow.CurrentStage,
                FlowStatus = flow.FlowStatus,
                RawMaterial = new JewelRawMaterialDto
                {
                    RawMaterialId = flow.RawMaterial.RawMaterialId,
                    MaterialType = flow.RawMaterial.MaterialType,
                    Weight = flow.RawMaterial.Weight,
                    SupplierName = flow.RawMaterial.SupplierName,
                    IsVerifyPass = flow.RawMaterial.IsVerifyPass
                },
                Product = new JewelProductDto
                {
                    ProductCode = flow.Product.ProductCode,
                    ProductName = flow.Product.ProductName,
                    RetailPrice = flow.Product.RetailPrice
                }
            };
        }
    }
}
cs 复制代码
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LoggingConfigurator.cs
 
 */
 
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Infrastructure.Logging
{
    /// <summary>
    /// 日志统一配置器:控制台与文件日志共用同一套 ILogger 抽象,保证输出内容一致
    /// 文件日志由 Karambolo 实现按日期分文件夹、按等级分文件
    /// </summary>
    public static class LoggingConfigurator
    {
        /// <summary>
        /// 扩展方法:配置日志提供程序
        /// </summary>
        /// <param name="builder">日志构建器</param>
        /// <param name="configuration">应用配置</param>
        /// <returns>日志构建器(链式)</returns>
        public static ILoggingBuilder ConfigureEnterpriseLogging(
            this ILoggingBuilder builder,
            IConfiguration configuration)
        {
            // 清理默认提供程序,避免重复输出
            builder.ClearProviders();
 
            // 控制台日志
            builder.AddConsole();
 
            // Karambolo v4:配置绑定与提供程序注册分离
            builder.AddConfiguration(configuration.GetSection("Logging"));
            builder.AddFile();
 
            // 最低日志等级
            builder.SetMinimumLevel(LogLevel.Debug);
 
            return builder;
        }
    }
}
 
 
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : IResilienceAdapter.cs
 
 */
 
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Infrastructure.Resilience
{
    /// <summary>
    /// 重试熔断适配器接口:统一为业务调用提供同步/异步容错
    /// </summary>
    public interface IResilienceAdapter
    {
        /// <summary>
        /// 同步执行带重试熔断的业务委托
        /// </summary>
        /// <typeparam name="TResult">返回结果类型</typeparam>
        /// <param name="func">业务委托</param>
        /// <returns>业务结果</returns>
        TResult Execute<TResult>(Func<TResult> func);
 
        /// <summary>
        /// 异步执行带重试熔断的业务委托
        /// </summary>
        /// <typeparam name="TResult">返回结果类型</typeparam>
        /// <param name="func">异步业务委托</param>
        /// <returns>业务结果 Task</returns>
        Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> func);
    }
}
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ResilienceAdapter.cs
 
 */
 
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Infrastructure.Resilience
{
    /// <summary>
    /// 重试熔断适配器实现
    /// 用 lock 保护熔断状态计数与时间戳,保证多线程并发下安全
    /// </summary>
    public class ResilienceAdapter : IResilienceAdapter
    {
        /// <summary>
        /// 配置项
        /// </summary>
        private readonly ResilienceOptions _options;
 
        /// <summary>
        /// 日志注入
        /// </summary>
        private readonly ILogger<ResilienceAdapter> _logger;
 
        /// <summary>
        /// 当前连续失败计数
        /// </summary>
        private int _currentFailCount;
 
        /// <summary>
        /// 熔断打开时间戳(UTC 毫秒),0 表示关闭
        /// </summary>
        private long _circuitBreakOpenTimestamp;
 
        /// <summary>
        /// 熔断状态访问锁
        /// </summary>
        private readonly object _stateLock = new();
 
        /// <summary>
        /// 构造适配器
        /// </summary>
        /// <param name="options">配置项</param>
        /// <param name="logger">日志实例</param>
        public ResilienceAdapter(ResilienceOptions options, ILogger<ResilienceAdapter> logger)
        {
            _options = options;
            _logger = logger;
        }
 
        /// <summary>
        /// 判断是否处于熔断打开状态;若超过熔断时长则自动半开恢复
        /// </summary>
        /// <returns>true=熔断打开拒绝执行,false=可执行</returns>
        private bool IsCircuitBreakOpen()
        {
            lock (_stateLock)
            {
                // 未打开
                if (_circuitBreakOpenTimestamp <= 0)
                {
                    return false;
                }
 
                // 计算当前与打开时刻的间隔
                long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                if (now - _circuitBreakOpenTimestamp > _options.CircuitBreakerBreakMs)
                {
                    // 熔断窗口结束,进入半开状态并复位
                    _circuitBreakOpenTimestamp = 0;
                    _currentFailCount = 0;
                    _logger.LogInformation("熔断时间窗口结束,熔断器复位进入半开状态");
                    return false;
                }
                return true;
            }
        }
 
        /// <summary>
        /// 记录一次成功,复位失败计数器
        /// </summary>
        private void MarkSuccess()
        {
            lock (_stateLock)
            {
                _currentFailCount = 0;
            }
        }
 
        /// <summary>
        /// 记录一次失败,达阈值则打开熔断
        /// </summary>
        private void MarkFail()
        {
            lock (_stateLock)
            {
                _currentFailCount++;
                // 连续失败达到阈值,打开熔断
                if (_currentFailCount >= _options.CircuitBreakerErrorThreshold)
                {
                    _circuitBreakOpenTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                    _logger.LogWarning(
                        "连续失败达阈值 {Threshold},熔断器打开,熔断时长 {BreakMs}ms",
                        _options.CircuitBreakerErrorThreshold, _options.CircuitBreakerBreakMs);
                }
            }
        }
 
        /// <summary>
        /// 同步执行:失败重试,达到熔断阈值抛异常
        /// </summary>
        /// <typeparam name="TResult">返回类型</typeparam>
        /// <param name="func">业务委托</param>
        /// <returns>业务结果</returns>
        public TResult Execute<TResult>(Func<TResult> func)
        {
            // 熔断打开则直接拒绝
            if (IsCircuitBreakOpen())
            {
                throw new InvalidOperationException("熔断器已打开,拒绝执行业务操作");
            }
 
            Exception? lastException = null;
 
            // 重试循环
            for (int attempt = 0; attempt <= _options.MaxRetryCount; attempt++)
            {
                try
                {
                    TResult result = func.Invoke();
                    MarkSuccess();
                    return result;
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    MarkFail();
                    _logger.LogWarning(ex, "业务执行失败,第 {Attempt} 次重试", attempt);
 
                    // 非最后一次则等待后重试
                    if (attempt < _options.MaxRetryCount)
                    {
                        Thread.Sleep(_options.RetryDelayMs);
                    }
                }
            }
 
            throw lastException!;
        }
 
        /// <summary>
        /// 异步执行:失败重试,达到熔断阈值抛异常
        /// </summary>
        /// <typeparam name="TResult">返回类型</typeparam>
        /// <param name="func">异步业务委托</param>
        /// <returns>业务结果 Task</returns>
        public async Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> func)
        {
            // 熔断打开则直接拒绝
            if (IsCircuitBreakOpen())
            {
                throw new InvalidOperationException("熔断器已打开,拒绝执行业务操作");
            }
 
            Exception? lastException = null;
 
            // 重试循环
            for (int attempt = 0; attempt <= _options.MaxRetryCount; attempt++)
            {
                try
                {
                    TResult result = await func.Invoke();
                    MarkSuccess();
                    return result;
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    MarkFail();
                    _logger.LogWarning(ex, "异步业务执行失败,第 {Attempt} 次重试", attempt);
 
                    // 非最后一次则异步等待后重试
                    if (attempt < _options.MaxRetryCount)
                    {
                        await Task.Delay(_options.RetryDelayMs);
                    }
                }
            }
 
            throw lastException!;
        }
    }
}
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ResilienceOptions.cs
 
 */
 
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Infrastructure.Resilience
{
    /// <summary>
    /// 重试熔断策略配置项
    /// </summary>
    public sealed class ResilienceOptions
    {
        /// <summary>
        /// 最大重试次数
        /// </summary>
        public int MaxRetryCount { get; set; } = 3;
 
        /// <summary>
        /// 重试间隔毫秒
        /// </summary>
        public int RetryDelayMs { get; set; } = 500;
 
        /// <summary>
        /// 熔断触发阈值:连续失败多少次打开熔断
        /// </summary>
        public int CircuitBreakerErrorThreshold { get; set; } = 5;
 
        /// <summary>
        /// 熔断恢复等待毫秒
        /// </summary>
        public int CircuitBreakerBreakMs { get; set; } = 3000;
    }
}
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelFlowScheduler.cs
 
 */
 
using Microsoft.Extensions.Logging;
using ObserverPattern.Application.Contracts;
using ObserverPattern.Application.Dto;
using ObserverPattern.Infrastructure.Resilience;
using ObserverPattern.Shared;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Infrastructure.Scheduler
{
    /// <summary>
    /// 珠宝业务流程调度器:驱动完整业务链路,并模拟高并发(并行多个流程)
    /// </summary>
    public class JewelFlowScheduler
    {
        /// <summary>
        /// 业务流程应用服务
        /// </summary>
        private readonly IJewelFlowApplicationService _flowService;
 
        /// <summary>
        /// 重试熔断适配器
        /// </summary>
        private readonly IResilienceAdapter _resilienceAdapter;
 
        /// <summary>
        /// 日志注入
        /// </summary>
        private readonly ILogger<JewelFlowScheduler> _logger;
 
        /// <summary>
        /// 构造调度器
        /// </summary>
        /// <param name="flowService">业务流程应用服务</param>
        /// <param name="resilienceAdapter">重试熔断适配器</param>
        /// <param name="logger">日志实例</param>
        public JewelFlowScheduler(
            IJewelFlowApplicationService flowService,
            IResilienceAdapter resilienceAdapter,
            ILogger<JewelFlowScheduler> logger)
        {
            _flowService = flowService;
            _resilienceAdapter = resilienceAdapter;
            _logger = logger;
        }
 
        /// <summary>
        /// 运行高并发珠宝业务流程
        /// </summary>
        /// <param name="parallelCount">并行流程数量(模拟高并发)</param>
        /// <returns>异步任务</returns>
        public async Task RunAsync(int parallelCount)
        {
            _logger.LogInformation("===== 启动珠宝业务高并发调度,并行流程数:{ParallelCount} =====", parallelCount);
 
            // 并行创建并运行多个流程,模拟高并发写入场景
            Task[] tasks = Enumerable.Range(0, parallelCount)
                .Select(index => RunOneFlowAsync(index))
                .ToArray();
 
            // 等待全部流程完成
            await Task.WhenAll(tasks);
 
            _logger.LogInformation("===== 珠宝业务高并发调度完成,共执行 {ParallelCount} 条流程 =====", parallelCount);
        }
 
        /// <summary>
        /// 运行单条完整珠宝业务链路
        /// </summary>
        /// <param name="index">流程序号</param>
        /// <returns>异步任务</returns>
        private async Task RunOneFlowAsync(int index)
        {
            try
            {
                // 构建流程输入 DTO
                JewelBusinessFlowDto inputDto = BuildFlowInput(index);
 
                // 通过重试熔断适配器执行完整链路
                await _resilienceAdapter.ExecuteAsync(() => _flowService.RunFullFlowAsync(inputDto));
 
                _logger.LogInformation("流程 #{Index} 完整业务链路执行完成", index);
            }
            catch (Exception ex)
            {
                // 记录单条流程异常,不阻断其他流程
                _logger.LogError(ex, "流程 #{Index} 执行失败", index);
            }
        }
 
        /// <summary>
        /// 构建流程输入 DTO(含原料与成品)
        /// </summary>
        /// <param name="index">流程序号</param>
        /// <returns>流程输入 DTO</returns>
        private static JewelBusinessFlowDto BuildFlowInput(int index)
        {
            // 生成基于序号+时间的唯一编号
            string stamp = $"{DateTime.Now:yyyyMMddHHmmss}";
            string rawId = $"RM{index}_{stamp}";
            string productCode = $"JW{index}_{stamp}";
 
            return new JewelBusinessFlowDto
            {
                FlowId = Guid.NewGuid().ToString("N"),
                CurrentStage = JewelStage.RawMaterialVerify,
                FlowStatus = "Running",
                RawMaterial = new JewelRawMaterialDto
                {
                    RawMaterialId = rawId,
                    MaterialType = "钻石",
                    Weight = 1.28m,
                    SupplierName = "环球宝石供应商",
                    IsVerifyPass = true
                },
                Product = new JewelProductDto
                {
                    ProductCode = productCode,
                    ProductName = "璀璨钻石吊坠",
                    RetailPrice = 28888.00m
                }
            };
        }
    }
}
/*
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelStage.cs
 
 */
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ObserverPattern.Shared
{
    /// <summary>
    /// 珠宝全业务流程阶段枚举(共享常量,避免字符串魔法值)
    /// </summary>
    public enum JewelStage
    {
        /// <summary>
        /// 原料采购核验
        /// </summary>
        RawMaterialVerify = 0,
 
        /// <summary>
        /// 设计制图
        /// </summary>
        DesignDrawing = 1,
 
        /// <summary>
        /// 加工生产
        /// </summary>
        Processing = 2,
 
        /// <summary>
        /// 质检
        /// </summary>
        QualityInspection = 3,
 
        /// <summary>
        /// 包装
        /// </summary>
        Packaging = 4,
 
        /// <summary>
        /// 物流
        /// </summary>
        Logistics = 5,
 
        /// <summary>
        /// 财务
        /// </summary>
        Finance = 6,
 
        /// <summary>
        /// 营销推广
        /// </summary>
        Marketing = 7,
 
        /// <summary>
        /// 业务销售
        /// </summary>
        SalesBusiness = 8,
 
        /// <summary>
        /// 人事行政
        /// </summary>
        HrAdmin = 9,
 
        /// <summary>
        /// IT 运维
        /// </summary>
        ItOps = 10,
 
        /// <summary>
        /// 员工培训
        /// </summary>
        Training = 11
    }
}
 

调用:

cs 复制代码
/*\
 # encoding: utf-8
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:观察者模式 Observer Pattern 行为模式 Behavioral Patterns
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/07/04 22:16
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ObserverBll.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
using ObserverPattern.Application.Contracts;
using ObserverPattern.Application.Observers;
using ObserverPattern.Application.Observers.Departments;
using ObserverPattern.Application.Services;
using ObserverPattern.Domain.Interfaces;
using ObserverPattern.Domain.Services;
using ObserverPattern.Infrastructure.Logging;
using ObserverPattern.Infrastructure.Resilience;
using ObserverPattern.Infrastructure.Scheduler;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace BLL
{
/// &lt;summary&gt;
///  可以扩展: 数据库持久化仓储、或把调度器改成 `Channel` 背压队列 
/// &lt;/summary&gt;
public class ObserverBll
{
    public async Task Demo()
    {

        string[] args= { };
        // 1. 构建通用主机并完成 DI 装配
        using IHost host = BuildHost(args);

        // 2. 从 DI 容器获取订阅器并注册全部观察者
        using (IServiceScope scope = host.Services.CreateScope())
        {
            // 获取观察者注册器
            JewelObserverRegistrar registrar =
                scope.ServiceProvider.GetRequiredService&lt;JewelObserverRegistrar&gt;();

            // 统一订阅全部业务部门观察者
            registrar.RegisterAllObservers();

            // 3. 获取高并发调度器并运行
            JewelFlowScheduler scheduler =
                scope.ServiceProvider.GetRequiredService&lt;JewelFlowScheduler&gt;();

            // 并行运行 8 条流程,模拟高并发写入
            await scheduler.RunAsync(parallelCount: 8);
        }

        Console.WriteLine("珠宝业务调度执行完毕,请在程序目录 Logs 下查看按日期、按等级分类的日志文件。");
        Console.WriteLine("按回车键退出...");
        Console.ReadLine();
    }

    /// &lt;summary&gt;
    /// 构建通用主机:加载配置、注册 DI、配置日志(控制台+文件)
    /// &lt;/summary&gt;
    /// &lt;param name="args"&gt;命令行参数&lt;/param&gt;
    /// &lt;returns&gt;构建完成的通用主机&lt;/returns&gt;
    private static IHost BuildHost(string[] args)
    {
        return Host.CreateDefaultBuilder(args)
            // 加载仓库根目录 appsettings.json(ContentRoot 默认在 BLL 目录,默认配置读不到根目录文件)
            .ConfigureAppConfiguration((_, config) =&gt;
            {
                string? configDir = Directory.GetCurrentDirectory();
                while (configDir != null &amp;&amp; !File.Exists(Path.Combine(configDir, "appsettings.json")))
                {
                    configDir = Directory.GetParent(configDir)?.FullName;
                }
                if (configDir != null)
                {
                    config.AddJsonFile(Path.Combine(configDir, "appsettings.json"), optional: false, reloadOnChange: true);
                }
            })
            // 注册全部服务到 DI 容器
            .ConfigureServices((context, services) =&gt;
            {
                // ---- 领域层 ----
                // 主题(发布者)注册为单例,全应用共享
                services.AddSingleton&lt;IJewelBusinessSubject, JewelBusinessSubject&gt;();

                // ---- 应用层 ----
                // 业务流程应用服务
                services.AddScoped&lt;IJewelFlowApplicationService, JewelFlowApplicationService&gt;();
                // 观察者统一注册器
                services.AddScoped&lt;JewelObserverRegistrar&gt;();

                // 注册全部业务部门观察者(按需解析,装配时取出)
                services.AddTransient&lt;IJewelObserver, PurchaseDepartmentObserver&gt;();
                services.AddTransient&lt;IJewelObserver, DesignDepartmentObserver&gt;();
                services.AddTransient&lt;IJewelObserver, ProduceDepartmentObserver&gt;();
                services.AddTransient&lt;IJewelObserver, QualityCheckObserver&gt;();
                services.AddTransient&lt;IJewelObserver, PackObserver&gt;();
                services.AddTransient&lt;IJewelObserver, LogisticsObserver&gt;();
                services.AddTransient&lt;IJewelObserver, FinanceObserver&gt;();
                services.AddTransient&lt;IJewelObserver, MarketingObserver&gt;();
                services.AddTransient&lt;IJewelObserver, SalesBusinessObserver&gt;();
                services.AddTransient&lt;IJewelObserver, HrAdminObserver&gt;();
                services.AddTransient&lt;IJewelObserver, ItDepartmentObserver&gt;();
                services.AddTransient&lt;IJewelObserver, TrainingObserver&gt;();

                // ---- 基础设施层 ----
                // 重试熔断配置(从配置或默认值)
                services.AddSingleton(_ =&gt; new ResilienceOptions
                {
                    MaxRetryCount = 3,
                    RetryDelayMs = 600,
                    CircuitBreakerErrorThreshold = 4,
                    CircuitBreakerBreakMs = 5000
                });
                services.AddSingleton&lt;IResilienceAdapter, ResilienceAdapter&gt;();

                // 高并发业务调度器
                services.AddTransient&lt;JewelFlowScheduler&gt;();
            })
            // 配置日志:控制台 + Karambolo 文件日志,输出一致
            .ConfigureLogging((context, logging) =&gt;
            {
                logging.ConfigureEnterpriseLogging(context.Configuration);
            })
            .Build();
    }
}
}

输出:

相关推荐
Flynt1 小时前
把公司项目迁到 Spring Boot 4.0:编译通过只是开始
java·spring boot·后端
郝学胜-神的一滴2 小时前
C++11 工程级应用 09:告别无谓拷贝,解锁高性能移动语义
开发语言·数据结构·c++·vscode·软件工程·visual studio
IT_陈寒2 小时前
Redis误用keys命令把生产环境搞崩了,血的教训
前端·人工智能·后端
她的男孩2 小时前
多租户和数据权限怎么共存?扒完拦截器注册链路,我找到 4 个隐蔽的坑
java·后端·架构
用户8356290780512 小时前
使用 Python 设置 Excel 页眉和页脚
后端·python
步行cgn2 小时前
IoC 控制反转:从概念到 Spring 的实现
后端
MC皮蛋侠客2 小时前
OPC UA 系列(一):标准全景与 Python 最小闭环——让第一条设备数据流动起来
开发语言·python·opcua
爱勇宝3 小时前
没有 Fn 键关触控板?我做了一个双击即用的 Windows 小工具
前端·后端·程序员
SamChan903 小时前
PDF翻译后的格式完整性校验:用Python自动比对译文与原文档的表格与段落结构
开发语言·python·ai·pdf·机器翻译