Csharp:Visitor Pattern

项目结构:

54d4db73-5cb5-40ec-8754-b96bf79c3883

 

/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : BusinessElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:业务销售节点
    /// </summary>
    public class BusinessElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "业务";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-009";

        /// <summary>客户编号(敏感字段)</summary>
        public string CustomerNo { get; set; } = string.Empty;
        /// <summary>订单编号</summary>
        public string OrderNo { get; set; } = string.Empty;
        /// <summary>客户身份证号(敏感字段)</summary>
        public string CustomerIdCard { get; set; } = string.Empty;

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitBusiness(this);
        }
    }
}

/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : DesignDraftElement.cs
 */
using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:设计制图节点
    /// </summary>
    public class DesignDraftElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "设计制图";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-002";

        /// <summary>珠宝款式编号</summary>
        public string StyleNo { get; set; } = string.Empty;
        /// <summary>图纸版本号</summary>
        public string DraftVersion { get; set; } = string.Empty;
        /// <summary>设计师工号(敏感字段)</summary>
        public string DesignerEmpNo { get; set; } = string.Empty;

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitDesignDraft(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : FinanceElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:财务节点
    /// </summary>
    public class FinanceElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "财务";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-007";

        /// <summary>财务单据编号</summary>
        public string BillNo { get; set; } = string.Empty;
        /// <summary>交易金额</summary>
        public decimal Amount { get; set; }
        /// <summary>收款账户(敏感字段)</summary>
        public string BankAccount { get; set; } = string.Empty;

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitFinance(this);
        }
    }
}

/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : HrAdminElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:人事行政节点
    /// </summary>
    public class HrAdminElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "人事行政";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-010";

        /// <summary>员工编号(敏感字段)</summary>
        public string EmployeeNo { get; set; } = string.Empty;
        /// <summary>所属部门名称</summary>
        public string Department { get; set; } = string.Empty;

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitHrAdmin(this);
        }
    }
}

/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ITElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:IT运维节点
    /// </summary>
    public class ITElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "IT";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-011";

        /// <summary>系统名称</summary>
        public string SystemName { get; set; } = string.Empty;
        /// <summary>运维工单编号</summary>
        public string TicketNo { get; set; } = string.Empty;

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitIT(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogisticsElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:物流节点
    /// </summary>
    public class LogisticsElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "物流";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-006";

        /// <summary>快递物流单号</summary>
        public string ExpressNo { get; set; } = string.Empty;
        /// <summary>收货目的地</summary>
        public string Destination { get; set; } = string.Empty;
        /// <summary>收件人手机号(敏感字段)</summary>
        public string ReceiverPhone { get; set; } = string.Empty;

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitLogistics(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ManufactureElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:加工生产节点
    /// </summary>
    public class ManufactureElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "加工生产";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-003";

        /// <summary>生产工单编号</summary>
        public string WorkOrderNo { get; set; } = string.Empty;
        /// <summary>计划产出数量</summary>
        public int PlanQty { get; set; }

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitManufacture(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : MarketingElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:营销推广节点
    /// </summary>
    public class MarketingElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "营销推广";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-008";

        /// <summary>营销活动名称</summary>
        public string CampaignName { get; set; } = string.Empty;
        /// <summary>活动预算金额</summary>
        public decimal Budget { get; set; }

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitMarketing(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : PackagingElement.cs
 */
using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:包装节点
    /// </summary>
    public class PackagingElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "包装";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-005";

        /// <summary>包装盒类型名称</summary>
        public string PackageType { get; set; } = string.Empty;
        /// <summary>本次包装件数</summary>
        public int PackageCount { get; set; }

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitPackaging(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : QualityInspectElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:质检节点
    /// </summary>
    public class QualityInspectElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "质检";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-004";

        /// <summary>质检批次号</summary>
        public string BatchNo { get; set; } = string.Empty;
        /// <summary>合格产品数量</summary>
        public int PassQty { get; set; }
        /// <summary>不合格产品数量</summary>
        public int FailQty { get; set; }
        /// <summary>质检员工号(敏感字段)</summary>
        public string InspectorEmpNo { get; set; } = string.Empty;

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitQualityInspect(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : RawMaterialCheckElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:原料采购核验节点
    /// </summary>
    public class RawMaterialCheckElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "原料采购核验";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-001";

        /// <summary>原料材质名称</summary>
        public string MaterialType { get; set; } = string.Empty;
        /// <summary>原料重量,单位克</summary>
        public decimal Weight { get; set; }
        /// <summary>核验结果 true=通过 false=不通过</summary>
        public bool CheckResult { get; set; }
        /// <summary>供应商编号(敏感字段,日志脱敏)</summary>
        public string SupplierNo { get; set; } = string.Empty;

        /// <summary>接受访问者双分派</summary>
        /// <param name="visitor">领域访问者</param>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitRawMaterialCheck(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : TrainingElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Domain.Entities.ProcessElements
{
    /// <summary>
    /// 领域实体:培训节点
    /// </summary>
    public class TrainingElement : IJeweleryProcessElement
    {
        /// <summary>节点中文名称</summary>
        public string ProcessName => "培训";
        /// <summary>节点业务编码</summary>
        public string ProcessCode => "JWL-012";

        /// <summary>培训主题名称</summary>
        public string TrainingTopic { get; set; } = string.Empty;
        /// <summary>参训人数</summary>
        public int ParticipantCount { get; set; }

        /// <summary>接受访问者双分派</summary>
        public void Accept(IJeweleryProcessVisitor visitor)
        {
            visitor.VisitTraining(this);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : IJeweleryProcessElement.cs
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace VisitorPattern.Domain.Entities
{
    /// <summary>
    /// 领域层:珠宝业务流程元素接口,访问者模式 Element
    /// 所有业务节点领域实体实现该接口,用于接受访问者的领域操作
    /// </summary>
    public interface IJeweleryProcessElement
    {
        /// <summary>
        /// 接受访问者访问,双分派核心方法
        /// </summary>
        /// <param name="visitor">珠宝业务领域访问者</param>
        void Accept(Domain.Interfaces.IJeweleryProcessVisitor visitor);

        /// <summary>
        /// 业务节点中文名称
        /// </summary>
        string ProcessName { get; }

        /// <summary>
        /// 业务节点唯一编码
        /// </summary>
        string ProcessCode { get; }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : IJeweleryProcessVisitor.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Entities.ProcessElements;

namespace VisitorPattern.Domain.Interfaces
{
    /// <summary>
    /// 领域层:珠宝业务访问者接口 Visitor
    /// 定义每个业务节点对应的访问操作方法,新增操作不修改领域实体
    /// </summary>
    public interface IJeweleryProcessVisitor
    {
        /// <summary>原料采购核验节点访问</summary>
        void VisitRawMaterialCheck(RawMaterialCheckElement element);
        /// <summary>设计制图节点访问</summary>
        void VisitDesignDraft(DesignDraftElement element);
        /// <summary>加工生产节点访问</summary>
        void VisitManufacture(ManufactureElement element);
        /// <summary>质检节点访问</summary>
        void VisitQualityInspect(QualityInspectElement element);
        /// <summary>包装节点访问</summary>
        void VisitPackaging(PackagingElement element);
        /// <summary>物流节点访问</summary>
        void VisitLogistics(LogisticsElement element);
        /// <summary>财务节点访问</summary>
        void VisitFinance(FinanceElement element);
        /// <summary>营销推广节点访问</summary>
        void VisitMarketing(MarketingElement element);
        /// <summary>业务节点访问</summary>
        void VisitBusiness(BusinessElement element);
        /// <summary>人事行政节点访问</summary>
        void VisitHrAdmin(HrAdminElement element);
        /// <summary>IT节点访问</summary>
        void VisitIT(ITElement element);
        /// <summary>培训节点访问</summary>
        void VisitTraining(TrainingElement element);
    }
}

  

/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ICircuitBreakerAdapter.cs
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace VisitorPattern.Application.Abstractions
{
    /// <summary>
    /// 应用层抽象:熔断重试适配器接口
    /// 用于外部服务调用容错,依赖倒置,基础设施层实现
    /// </summary>
    public interface ICircuitBreakerAdapter
    {
        /// <summary>
        /// 执行带重试+熔断保护的异步业务操作
        /// </summary>
        /// <typeparam name="T">返回结果类型</typeparam>
        /// <param name="operation">待执行业务委托</param>
        /// <param name="maxRetry">最大重试次数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>业务执行结果</returns>
        Task<T> ExecuteWithRetryAndCircuitBreaker<T>(Func<Task<T>> operation, int maxRetry, CancellationToken cancellationToken);
    }
}


/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JeweleryBusinessDto.cs
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace VisitorPattern.Application.Dtos
{
    /// <summary>
    /// 应用层DTO:珠宝业务单据传输对象
    /// 用于跨层传递业务结果数据
    /// </summary>
    public class JeweleryBusinessDto
    {
        /// <summary>业务唯一单号</summary>
        public string BusinessNo { get; set; } = string.Empty;
        /// <summary>珠宝产品名称</summary>
        public string ProductName { get; set; } = string.Empty;
        /// <summary>产品总数量</summary>
        public int TotalQty { get; set; }
        /// <summary>单据总金额</summary>
        public decimal TotalAmount { get; set; }
        /// <summary>单据创建时间</summary>
        public DateTime CreateTime { get; set; }
        /// <summary>客户手机号(敏感字段)</summary>
        public string CustomerPhone { get; set; } = string.Empty;
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JeweleryProcessElementManager.cs
 */

using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Entities;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Application.Services
{
    /// <summary>
    /// 应用服务:珠宝流程元素管理器
    /// 维护全流程领域元素集合,线程安全读写,批量驱动访问者遍历所有节点
    /// </summary>
    public class JeweleryProcessElementManager
    {
        /// <summary>内部元素集合</summary>
        private readonly List<IJeweleryProcessElement> _elementList = new();
        /// <summary>多线程读写锁对象</summary>
        private readonly object _lockObj = new();

        /// <summary>只读元素集合,线程安全读取副本</summary>
        public IReadOnlyList<IJeweleryProcessElement> Elements
        {
            get
            {
                lock (_lockObj)
                {
                    return _elementList.ToList().AsReadOnly();
                }
            }
        }

        /// <summary>添加业务流程节点元素,线程安全</summary>
        /// <param name="element">领域流程节点实体</param>
        /// <exception cref="ArgumentNullException">元素为空抛出异常</exception>
        public void AddElement(IJeweleryProcessElement element)
        {
            if (element == null) throw new ArgumentNullException(nameof(element));
            lock (_lockObj)
            {
                _elementList.Add(element);
            }
        }

        /// <summary>清空全部流程节点,线程安全</summary>
        public void ClearElements()
        {
            lock (_lockObj)
            {
                _elementList.Clear();
            }
        }

        /// <summary>遍历全部节点,执行访问者Accept操作</summary>
        /// <param name="visitor">领域访问者实例</param>
        /// <exception cref="ArgumentNullException">访问者为空抛出异常</exception>
        public void AcceptAll(IJeweleryProcessVisitor visitor)
        {
            if (visitor == null) throw new ArgumentNullException(nameof(visitor));
            var items = Elements;
            foreach (var item in items)
            {
                item.Accept(visitor);
            }
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JeweleryWorkflowScheduler.cs
 */

using Microsoft.Extensions.Logging;
using OpenTelemetry.Trace;
using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Application.Abstractions;
using VisitorPattern.Application.Dtos;
using VisitorPattern.Application.Visitors;
using VisitorPattern.Domain.Entities.ProcessElements;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Application.Services
{
    /// <summary>
    /// 应用服务:珠宝工作流调度器
    /// 组装全流程领域节点,使用访问者模式驱动业务执行,集成OTel链路追踪,统一日志输出
    /// </summary>
    public class JeweleryWorkflowScheduler
    {
        private readonly ILogger<JeweleryWorkflowScheduler> _logger;
        private readonly JeweleryProcessElementManager _elementManager;
        private readonly ICircuitBreakerAdapter _circuitBreakerAdapter;
        private readonly IJeweleryProcessVisitor _logAuditVisitor;
        private readonly IJeweleryProcessVisitor _statVisitor;
        private readonly Tracer _tracer;

        /// <summary>构造函数,依赖注入全部服务</summary>
        /// <param name="logger">日志实例</param>
        /// <param name="elementManager">流程节点管理器</param>
        /// <param name="circuitBreakerAdapter">熔断重试适配器</param>
        /// <param name="logAuditVisitor">日志审计访问者</param>
        /// <param name="statVisitor">业务统计访问者</param>
        /// <param name="tracer">OTel追踪实例</param>
        public JeweleryWorkflowScheduler(
            ILogger<JeweleryWorkflowScheduler> logger,
            JeweleryProcessElementManager elementManager,
            ICircuitBreakerAdapter circuitBreakerAdapter,
            IJeweleryProcessVisitor logAuditVisitor,
            IJeweleryProcessVisitor statVisitor,
            Tracer tracer)
        {
            _logger = logger;
            _elementManager = elementManager;
            _circuitBreakerAdapter = circuitBreakerAdapter;
            _logAuditVisitor = logAuditVisitor;
            _statVisitor = statVisitor;
            _tracer = tracer;
        }

        /// <summary>
        /// 异步运行珠宝完整业务流程
        /// </summary>
        /// <returns>业务单据DTO</returns>
        public async Task<JeweleryBusinessDto> RunFullJeweleryWorkflowAsync()
        {
            // 创建顶层链路追踪Span
            using var rootSpan = _tracer.StartActiveSpan("JeweleryWorkflow.RunFullJeweleryWorkflowAsync");
            rootSpan.SetAttribute("workflow.type", "FullJeweleryBusiness");
            _logger.LogInformation("=====启动珠宝全业务流程调度=====");
            _elementManager.ClearElements();

            // 填充全流程领域节点实体,包含敏感字段用于脱敏演示
            _elementManager.AddElement(new RawMaterialCheckElement
            {
                MaterialType = "18K金",
                Weight = 120.50m,
                CheckResult = true,
                SupplierNo = "SUP20260912001"
            });
            _elementManager.AddElement(new DesignDraftElement
            {
                StyleNo = "JWL-2026-001",
                DraftVersion = "V1.2",
                DesignerEmpNo = "EMP0101"
            });
            _elementManager.AddElement(new ManufactureElement
            {
                WorkOrderNo = "WO-20260912001",
                PlanQty = 50
            });
            _elementManager.AddElement(new QualityInspectElement
            {
                BatchNo = "B2026091201",
                PassQty = 48,
                FailQty = 2,
                InspectorEmpNo = "EMP0202"
            });
            _elementManager.AddElement(new PackagingElement
            {
                PackageType = "精品礼盒",
                PackageCount = 48
            });
            _elementManager.AddElement(new LogisticsElement
            {
                ExpressNo = "SF1234567890",
                Destination = "深圳门店",
                ReceiverPhone = "13800138000"
            });
            _elementManager.AddElement(new FinanceElement
            {
                BillNo = "FIN20260912001",
                Amount = 286000.00m,
                BankAccount = "6222021202012345678"
            });
            _elementManager.AddElement(new MarketingElement
            {
                CampaignName = "中秋珠宝促销",
                Budget = 35000.00m
            });
            _elementManager.AddElement(new BusinessElement
            {
                CustomerNo = "CUST0088",
                OrderNo = "ORD20260912001",
                CustomerIdCard = "440306198801011234"
            });
            _elementManager.AddElement(new HrAdminElement
            {
                EmployeeNo = "EMP0125",
                Department = "生产部"
            });
            _elementManager.AddElement(new ITElement
            {
                SystemName = "珠宝ERP",
                TicketNo = "IT-TK-20260912"
            });
            _elementManager.AddElement(new TrainingElement
            {
                TrainingTopic = "珠宝质检标准培训",
                ParticipantCount = 32
            });

            // 使用熔断重试适配器包裹整个业务流程,OTel链路追踪自动记录异常
            var dto = await _circuitBreakerAdapter.ExecuteWithRetryAndCircuitBreaker(async () =>
            {
                using var spanAudit = _tracer.StartActiveSpan("Visitor.LogAudit");
                _logger.LogDebug("开始执行访问者:日志审计访问");
                _elementManager.AcceptAll(_logAuditVisitor);
                spanAudit.End();

                using var spanStat = _tracer.StartActiveSpan("Visitor.BusinessStat");
                _logger.LogDebug("开始执行访问者:业务统计访问");
                _elementManager.AcceptAll(_statVisitor);
                spanStat.End();

                var stat = _statVisitor as BusinessStatisticsVisitor;
                stat?.PrintSummary();

                return new JeweleryBusinessDto
                {
                    BusinessNo = "BUS20260912001",
                    ProductName = "18K金钻石项链",
                    TotalQty = 48,
                    TotalAmount = 286000.00m,
                    CreateTime = DateTime.Now,
                    CustomerPhone = "13900139000"
                };
            }, maxRetry: 2, CancellationToken.None);

            _logger.LogInformation("流程执行完成,业务单据号:{BusinessNo},产品:{Product}", dto.BusinessNo, dto.ProductName);
            _logger.LogInformation("=====珠宝全业务流程调度结束=====");
            rootSpan.SetAttribute("business.businessNo", dto.BusinessNo);
            return dto;
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : BusinessStatisticsVisitor.cs
 */

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Entities.ProcessElements;
using VisitorPattern.Domain.Interfaces;

namespace VisitorPattern.Application.Visitors
{
    /// <summary>
    /// 应用访问者:业务统计访问者
    /// 收集珠宝全流程指标数据,用于业务汇总统计,不修改领域实体
    /// </summary>
    public class BusinessStatisticsVisitor : IJeweleryProcessVisitor
    {
        private readonly ILogger<BusinessStatisticsVisitor> _logger;

        /// <summary>总流程节点计数</summary>
        public int TotalProcessCount { get; private set; }
        /// <summary>原料总重量,单位克</summary>
        public decimal TotalRawWeight { get; private set; }
        /// <summary>累计财务交易总金额</summary>
        public decimal TotalFinanceAmount { get; private set; }

        /// <summary>构造注入日志实例</summary>
        /// <param name="logger">日志对象</param>
        public BusinessStatisticsVisitor(ILogger<BusinessStatisticsVisitor> logger)
        {
            _logger = logger;
        }

        /// <summary>访问原料采购核验节点,累加原料重量</summary>
        public void VisitRawMaterialCheck(RawMaterialCheckElement element)
        {
            TotalProcessCount++;
            TotalRawWeight += element.Weight;
            _logger.LogDebug("统计节点[{0}]累计原料重量:{1}", element.ProcessName, TotalRawWeight);
        }

        /// <summary>访问设计制图节点,计数+1</summary>
        public void VisitDesignDraft(DesignDraftElement element) => TotalProcessCount++;
        /// <summary>访问加工生产节点,计数+1</summary>
        public void VisitManufacture(ManufactureElement element) => TotalProcessCount++;
        /// <summary>访问质检节点,计数+1</summary>
        public void VisitQualityInspect(QualityInspectElement element) => TotalProcessCount++;
        /// <summary>访问包装节点,计数+1</summary>
        public void VisitPackaging(PackagingElement element) => TotalProcessCount++;
        /// <summary>访问物流节点,计数+1</summary>
        public void VisitLogistics(LogisticsElement element) => TotalProcessCount++;

        /// <summary>访问财务节点,累加金额</summary>
        public void VisitFinance(FinanceElement element)
        {
            TotalProcessCount++;
            TotalFinanceAmount += element.Amount;
            _logger.LogDebug("统计节点[{0}]累计财务金额:{1:C}", element.ProcessName, TotalFinanceAmount);
        }

        /// <summary>访问营销推广节点,计数+1</summary>
        public void VisitMarketing(MarketingElement element) => TotalProcessCount++;
        /// <summary>访问业务销售节点,计数+1</summary>
        public void VisitBusiness(BusinessElement element) => TotalProcessCount++;
        /// <summary>访问人事行政节点,计数+1</summary>
        public void VisitHrAdmin(HrAdminElement element) => TotalProcessCount++;
        /// <summary>访问IT运维节点,计数+1</summary>
        public void VisitIT(ITElement element) => TotalProcessCount++;
        /// <summary>访问培训节点,计数+1</summary>
        public void VisitTraining(TrainingElement element) => TotalProcessCount++;

        /// <summary>输出汇总统计结果到日志</summary>
        public void PrintSummary()
        {
            _logger.LogWarning("====业务统计汇总====");
            _logger.LogWarning("总流程节点数:{Count}", TotalProcessCount);
            _logger.LogWarning("原料总重量:{Weight}g", TotalRawWeight);
            _logger.LogWarning("累计财务金额:{Amount:C}", TotalFinanceAmount);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogAuditProcessVisitor.cs
 */

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Domain.Entities.ProcessElements;
using VisitorPattern.Domain.Interfaces;
using VisitorPattern.Infrastructure.Logging;

namespace VisitorPattern.Application.Visitors
{
    /// <summary>
    /// 应用访问者:日志审计访问者
    /// 遍历领域节点,输出脱敏后的业务审计日志,注入ILogger
    /// </summary>
    public class LogAuditProcessVisitor : IJeweleryProcessVisitor
    {

        private readonly ILogger<LogAuditProcessVisitor> _logger;
        /// <summary>构造函数注入日志(脱敏工具为静态无状态类,直接调用)</summary>
        /// <param name="logger">日志实例</param>
        public LogAuditProcessVisitor(ILogger<LogAuditProcessVisitor> logger)
        {
            _logger = logger;
        }

        /// <summary>访问原料采购核验节点</summary>
        /// <param name="element">原料采购核验领域实体</param>
        public void VisitRawMaterialCheck(RawMaterialCheckElement element)
        {
            string supplierNoMasked = SensitiveDataMasker.MaskSupplierNo(element.SupplierNo);
            _logger.LogInformation("【{ProcessName}】编码:{Code},材质:{Material},重量:{Weight}g,核验结果:{Result},供应商编号:{SupplierNo}",
                element.ProcessName, element.ProcessCode, element.MaterialType, element.Weight, element.CheckResult, supplierNoMasked);
        }

        /// <summary>访问设计制图节点</summary>
        /// <param name="element">设计制图领域实体</param>
        public void VisitDesignDraft(DesignDraftElement element)
        {
            string empNoMasked = SensitiveDataMasker.MaskEmployeeNo(element.DesignerEmpNo);
            _logger.LogInformation("【{ProcessName}】编码:{Code},款式:{Style},版本:{Ver},设计师工号:{EmpNo}",
                element.ProcessName, element.ProcessCode, element.StyleNo, element.DraftVersion, empNoMasked);
        }

        /// <summary>访问加工生产节点</summary>
        /// <param name="element">加工生产领域实体</param>
        public void VisitManufacture(ManufactureElement element)
        {
            _logger.LogInformation("【{ProcessName}】编码:{Code},工单:{WorkNo},计划数量:{Qty}",
                element.ProcessName, element.ProcessCode, element.WorkOrderNo, element.PlanQty);
        }

        /// <summary>访问质检节点</summary>
        /// <param name="element">质检领域实体</param>
        public void VisitQualityInspect(QualityInspectElement element)
        {
            string inspectorMasked = SensitiveDataMasker.MaskEmployeeNo(element.InspectorEmpNo);
            _logger.LogInformation("【{ProcessName}】编码:{Code},批次:{Batch},合格:{Pass},不合格:{Fail},质检员工号:{Inspector}",
                element.ProcessName, element.ProcessCode, element.BatchNo, element.PassQty, element.FailQty, inspectorMasked);
        }

        /// <summary>访问包装节点</summary>
        /// <param name="element">包装领域实体</param>
        public void VisitPackaging(PackagingElement element)
        {
            _logger.LogInformation("【{ProcessName}】编码:{Code},包装类型:{PkgType},件数:{Count}",
                element.ProcessName, element.ProcessCode, element.PackageType, element.PackageCount);
        }

        /// <summary>访问物流节点</summary>
        /// <param name="element">物流领域实体</param>
        public void VisitLogistics(LogisticsElement element)
        {
            string phoneMasked = SensitiveDataMasker.MaskPhone(element.ReceiverPhone);
            _logger.LogInformation("【{ProcessName}】编码:{Code},快递单号:{Express},目的地:{Dest},收件手机:{Phone}",
                element.ProcessName, element.ProcessCode, element.ExpressNo, element.Destination, phoneMasked);
        }

        /// <summary>访问财务节点</summary>
        /// <param name="element">财务领域实体</param>
        public void VisitFinance(FinanceElement element)
        {
            string bankMasked = SensitiveDataMasker.MaskBankAccount(element.BankAccount);
            _logger.LogInformation("【{ProcessName}】编码:{Code},单据:{BillNo},金额:{Amount:C},收款账户:{BankAccount}",
                element.ProcessName, element.ProcessCode, element.BillNo, element.Amount, bankMasked);
        }

        /// <summary>访问营销推广节点</summary>
        /// <param name="element">营销推广领域实体</param>
        public void VisitMarketing(MarketingElement element)
        {
            _logger.LogInformation("【{ProcessName}】编码:{Code},活动:{Campaign},预算:{Budget:C}",
                element.ProcessName, element.ProcessCode, element.CampaignName, element.Budget);
        }

        /// <summary>访问业务销售节点</summary>
        /// <param name="element">业务领域实体</param>
        public void VisitBusiness(BusinessElement element)
        {
            string custNoMasked = SensitiveDataMasker.MaskCustomerNo(element.CustomerNo);
            string idCardMasked = SensitiveDataMasker.MaskIdCard(element.CustomerIdCard);
            _logger.LogInformation("【{ProcessName}】编码:{Code},客户:{CustNo},订单:{OrderNo},身份证:{IdCard}",
                element.ProcessName, element.ProcessCode, custNoMasked, element.OrderNo, idCardMasked);
        }

        /// <summary>访问人事行政节点</summary>
        /// <param name="element">人事行政领域实体</param>
        public void VisitHrAdmin(HrAdminElement element)
        {
            string empNoMasked = SensitiveDataMasker.MaskEmployeeNo(element.EmployeeNo);
            _logger.LogInformation("【{ProcessName}】编码:{Code},员工:{EmpNo},部门:{Dept}",
                element.ProcessName, element.ProcessCode, empNoMasked, element.Department);
        }

        /// <summary>访问IT运维节点</summary>
        /// <param name="element">IT领域实体</param>
        public void VisitIT(ITElement element)
        {
            _logger.LogInformation("【{ProcessName}】编码:{Code},系统:{Sys},运维工单:{Ticket}",
                element.ProcessName, element.ProcessCode, element.SystemName, element.TicketNo);
        }

        /// <summary>访问培训节点</summary>
        /// <param name="element">培训领域实体</param>
        public void VisitTraining(TrainingElement element)
        {
            _logger.LogInformation("【{ProcessName}】编码:{Code},培训主题:{Topic},参训人数:{People}",
                element.ProcessName, element.ProcessCode, element.TrainingTopic, element.ParticipantCount);
        }
    }
}

  

/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogCleaner.cs
 */

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;

namespace VisitorPattern.Infrastructure.Logging
{
    /// <summary>
    /// 基础设施:日志自动清理服务
    /// 双策略:过期天数删除 + 磁盘占用阈值删除;后台定时执行,线程安全
    /// </summary>
    public class LogCleaner
    {
        private readonly ILogger<LogCleaner> _logger;
        private readonly object _cleanLock = new();

        /// <summary>日志根目录</summary>
        private readonly string _logBasePath;
        /// <summary>日志保留最大天数</summary>
        private readonly int _retentionDays;
        /// <summary>磁盘阈值,单位MB,超过该值自动清理最早日志文件夹</summary>
        private readonly long _diskThresholdMb;

        /// <summary>构造函数</summary>
        /// <param name="logger">日志实例</param>
        /// <param name="logBasePath">日志根目录路径</param>
        /// <param name="retentionDays">日志保留天数</param>
        /// <param name="diskThresholdMb">磁盘占用阈值 MB</param>
        public LogCleaner(ILogger<LogCleaner> logger, string logBasePath, int retentionDays, long diskThresholdMb)
        {
            _logger = logger;
            _logBasePath = logBasePath;
            _retentionDays = retentionDays;
            _diskThresholdMb = diskThresholdMb;
        }

        /// <summary>
        /// 执行日志清理入口方法,线程安全锁保护
        /// </summary>
        /// <returns>异步任务</returns>
        public async Task CleanAsync()
        {
            // 防止多线程同时执行清理
            lock (_cleanLock)
            {
                if (!Directory.Exists(_logBasePath))
                {
                    _logger.LogDebug("日志目录不存在,无需清理:{Path}", _logBasePath);
                    return;
                }
            }

            await Task.Run(() =>
            {
                lock (_cleanLock)
                {
                    // 获取所有日期子文件夹,按文件夹名称(日期)升序排列(旧文件夹在前)
                    var dirs = Directory.GetDirectories(_logBasePath)
                        .Select(d => new
                        {
                            FullPath = d,
                            FolderName = Path.GetFileName(d),
                            ParseSuccess = DateTime.TryParseExact(Path.GetFileName(d), "yyyy-MM-dd", null, System.Globalization.DateTimeStyles.None, out var folderDate),
                            FolderDate = folderDate
                        })
                        .Where(x => x.ParseSuccess)
                        .OrderBy(x => x.FolderDate)
                        .ToList();

                    // 策略1:删除超过保留天数的日志文件夹
                    DateTime expireTime = DateTime.Now.AddDays(-1 * _retentionDays);
                    foreach (var dirItem in dirs.Where(x => x.FolderDate < expireTime))
                    {
                        try
                        {
                            Directory.Delete(dirItem.FullPath, true);
                            _logger.LogInformation("日志过期删除:{Folder}", dirItem.FolderName);
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "删除过期日志文件夹失败 {Folder}", dirItem.FullPath);
                        }
                    }

                    // 重新读取目录,策略2:检查磁盘总大小,超过阈值继续删除最早文件夹
                    var remainDirs = Directory.GetDirectories(_logBasePath)
                        .Select(d => new
                        {
                            FullPath = d,
                            FolderName = Path.GetFileName(d),
                            ParseSuccess = DateTime.TryParseExact(Path.GetFileName(d), "yyyy-MM-dd", null, System.Globalization.DateTimeStyles.None, out var folderDate),
                            FolderDate = folderDate
                        })
                        .Where(x => x.ParseSuccess)
                        .OrderBy(x => x.FolderDate)
                        .ToList();

                    long totalSizeMb = GetTotalLogSizeMb(_logBasePath);
                    _logger.LogInformation("当前日志总大小:{TotalSize} MB,阈值:{Threshold} MB", totalSizeMb, _diskThresholdMb);

                    long currentSize = totalSizeMb;
                    foreach (var dirItem in remainDirs)
                    {
                        if (currentSize < _diskThresholdMb) break;
                        try
                        {
                            long folderSize = GetDirectorySizeMb(dirItem.FullPath);
                            Directory.Delete(dirItem.FullPath, true);
                            currentSize -= folderSize;
                            _logger.LogWarning("日志磁盘超出阈值,强制删除旧日志文件夹:{Folder}", dirItem.FolderName);
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "磁盘阈值清理删除文件夹失败 {Folder}", dirItem.FullPath);
                        }
                    }
                }
            });
        }

        /// <summary>获取目录总大小 MB</summary>
        /// <param name="path">目录路径</param>
        /// <returns>大小MB</returns>
        private long GetTotalLogSizeMb(string path)
        {
            return GetDirectorySizeMb(path);
        }

        /// <summary>计算文件夹占用大小 MB</summary>
        /// <param name="path">文件夹路径</param>
        /// <returns>MB</returns>
        private long GetDirectorySizeMb(string path)
        {
            if (!Directory.Exists(path)) return 0;
            long bytes = 0;
            var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                try
                {
                    var fi = new FileInfo(file);
                    bytes += fi.Length;
                }
                catch
                {
                    // 读取文件异常跳过
                }
            }
            return bytes / 1024 / 1024;
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : SensitiveDataMasker.cs
 */
using System;
using System.Collections.Generic;
using System.Text;

namespace VisitorPattern.Infrastructure.Logging
{
    /// <summary>
    /// 基础设施:敏感数据脱敏工具类
    /// 用于日志输出前,对手机号、身份证、客户编号、银行账号、员工编号等敏感信息脱敏
    /// 线程安全,静态无状态方法
    /// </summary>
    public static class SensitiveDataMasker
    {
        /// <summary>手机号脱敏,保留前3后4</summary>
        /// <param name="phone">原始手机号</param>
        /// <returns>脱敏后手机号</returns>
        public static string MaskPhone(string phone)
        {
            if (string.IsNullOrWhiteSpace(phone) || phone.Length < 7) return phone;
            return $"{phone[..3]}****{phone.Substring(phone.Length - 4)}";
        }

        /// <summary>身份证脱敏,保留前6后4</summary>
        /// <param name="idCard">身份证号码</param>
        /// <returns>脱敏身份证</returns>
        public static string MaskIdCard(string idCard)
        {
            if (string.IsNullOrWhiteSpace(idCard) || idCard.Length < 10) return idCard;
            return $"{idCard[..6]}********{idCard.Substring(idCard.Length - 4)}";
        }

        /// <summary>客户编号脱敏,只显示前2位</summary>
        /// <param name="custNo">客户编号</param>
        /// <returns>脱敏客户编号</returns>
        public static string MaskCustomerNo(string custNo)
        {
            if (string.IsNullOrWhiteSpace(custNo) || custNo.Length < 3) return custNo;
            return $"{custNo[..2]}******";
        }

        /// <summary>员工编号脱敏,只显示前2位</summary>
        /// <param name="empNo">员工编号</param>
        /// <returns>脱敏员工编号</returns>
        public static string MaskEmployeeNo(string empNo)
        {
            if (string.IsNullOrWhiteSpace(empNo) || empNo.Length < 3) return empNo;
            return $"{empNo[..2]}****";
        }

        /// <summary>供应商编号脱敏</summary>
        /// <param name="supplierNo">供应商编号</param>
        /// <returns>脱敏供应商编号</returns>
        public static string MaskSupplierNo(string supplierNo)
        {
            if (string.IsNullOrWhiteSpace(supplierNo) || supplierNo.Length < 4) return supplierNo;
            return $"{supplierNo[..3]}********";
        }

        /// <summary>银行卡号脱敏,保留前6后4</summary>
        /// <param name="bankAccount">银行卡账号</param>
        /// <returns>脱敏账号</returns>
        public static string MaskBankAccount(string bankAccount)
        {
            if (string.IsNullOrWhiteSpace(bankAccount) || bankAccount.Length < 10) return bankAccount;
            return $"{bankAccount[..6]}********{bankAccount.Substring(bankAccount.Length - 4)}";
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : CircuitBreakerRetryAdapter.cs
 */

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Application.Abstractions;

namespace VisitorPattern.Infrastructure.Resilience
{
    /// <summary>
    /// 基础设施:熔断重试适配器实现
    /// 线程安全,熔断器状态机,失败计数、熔断打开、半开恢复,重试策略
    /// </summary>
    public class CircuitBreakerRetryAdapter : ICircuitBreakerAdapter
    {
        private readonly ILogger<CircuitBreakerRetryAdapter> _logger;
        /// <summary>熔断器锁对象</summary>
        private readonly object _circuitLock = new();
        /// <summary>连续失败次数</summary>
        private int _failCount;
        /// <summary>熔断阈值,连续失败达到该数值打开熔断器</summary>
        private const int CircuitThreshold = 3;
        /// <summary>熔断器是否处于打开状态</summary>
        private bool _circuitOpen;
        /// <summary>熔断器重置时间点(UTC)</summary>
        private DateTime _circuitResetTime;

        /// <summary>构造注入日志</summary>
        /// <param name="logger">日志实例</param>
        public CircuitBreakerRetryAdapter(ILogger<CircuitBreakerRetryAdapter> logger)
        {
            _logger = logger;
        }

        /// <summary>执行带熔断+重试保护的异步操作</summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="operation">待执行业务委托</param>
        /// <param name="maxRetry">最大重试次数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>业务结果</returns>
        public async Task<T> ExecuteWithRetryAndCircuitBreaker<T>(Func<Task<T>> operation, int maxRetry, CancellationToken cancellationToken)
        {
            // 检查熔断器状态
            lock (_circuitLock)
            {
                if (_circuitOpen)
                {
                    if (DateTime.UtcNow > _circuitResetTime)
                    {
                        // 半开状态,重置熔断器,允许尝试一次调用
                        _logger.LogInformation("熔断时间到期,关闭熔断器,尝试恢复");
                        _circuitOpen = false;
                        _failCount = 0;
                    }
                    else
                    {
                        _logger.LogError("熔断器已打开,拒绝执行操作");
                        throw new InvalidOperationException("服务熔断,暂时无法调用");
                    }
                }
            }

            Exception? lastException = null;
            // 循环重试
            for (int retry = 0; retry <= maxRetry; retry++)
            {
                try
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    var result = await operation.Invoke();
                    // 调用成功,清空失败计数器
                    lock (_circuitLock)
                    {
                        _failCount = 0;
                    }
                    if (retry > 0)
                    {
                        _logger.LogInformation("操作重试成功,当前重试次数:{Retry}", retry);
                    }
                    return result;
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    _logger.LogWarning("操作执行失败,重试次数:{Retry}, 异常:{Msg}", retry, ex.Message);
                    lock (_circuitLock)
                    {
                        _failCount++;
                        if (_failCount >= CircuitThreshold)
                        {
                            _circuitOpen = true;
                            _circuitResetTime = DateTime.UtcNow.AddSeconds(10);
                            _logger.LogError("达到熔断阈值{Threshold},熔断器开启,10秒后重置", CircuitThreshold);
                        }
                    }
                    if (retry >= maxRetry) break;
                    await Task.Delay(200 * (retry + 1), cancellationToken);
                }
            }
            throw new AggregateException("重试全部失败", lastException!);
        }
    }
}
/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : OpenTelemetrySetup.cs
 */

using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Collections.Generic;
using System.Text;

namespace VisitorPattern.Infrastructure.Telemetry
{
    /// <summary>
    /// 基础设施:OpenTelemetry 链路追踪配置扩展类
    /// 提供DI注册扩展方法,自动关联日志与TraceId
    /// </summary>
    public static class OpenTelemetrySetup
    {
        /// <summary>
        /// 注册OpenTelemetry追踪服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddJeweleryOpenTelemetryTracing(this IServiceCollection services)
        {
            services.AddOpenTelemetry()
                .WithTracing(tracerBuilder =>
                {
                    tracerBuilder
                        .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("JeweleryVisitorDDD"))
                        .AddSource("JeweleryVisitorDDD")
                        .AddConsoleExporter();
                });
            return services;
        }
    }
}

  

调用:

/*
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:访问者模式 Visitor 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/08/29 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : VisitorBll.cs
 */
using System;
using System.Collections.Generic;
using System.Text;
using VisitorPattern.Application.Abstractions;
using VisitorPattern.Application.Services;
using VisitorPattern.Application.Visitors;
using VisitorPattern.Domain.Interfaces;
using VisitorPattern.Infrastructure.Logging;
using VisitorPattern.Infrastructure.Resilience;
using VisitorPattern.Infrastructure.Telemetry;
using Karambolo.Extensions.Logging.File;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Trace;


namespace BLL
{

    public class VisitorBll
    {
        public async Task Demo()
        {
            string logBasePath = Path.Combine(Directory.GetCurrentDirectory(), "Logs");
            // 日志清理配置:保留7天,磁盘阈值200MB
            int logRetentionDays = 7;
            long logDiskThresholdMb = 200;

            var host = Host.CreateDefaultBuilder()
                .ConfigureLogging((context, loggingBuilder) =>
                {
                    loggingBuilder.ClearProviders();
                    loggingBuilder.AddConsole();

                    // Karambolo v4 文件日志配置:按日期文件夹、按等级拆分日志文件
                    loggingBuilder.AddFile(options =>
                    {
                        options.RootPath = logBasePath;
                        options.Files = new[]
                        {
                            new LogFileOptions
                            {
                                Path = "<date:yyyy-MM-dd>/app-info.log",
                                MinLevel = new Dictionary<string, LogLevel> { ["Default"] = LogLevel.Information }
                            },
                            new LogFileOptions
                            {
                                Path = "<date:yyyy-MM-dd>/app-debug.log",
                                MinLevel = new Dictionary<string, LogLevel> { ["Default"] = LogLevel.Debug }
                            },
                            new LogFileOptions
                            {
                                Path = "<date:yyyy-MM-dd>/app-warn.log",
                                MinLevel = new Dictionary<string, LogLevel> { ["Default"] = LogLevel.Warning }
                            },
                            new LogFileOptions
                            {
                                Path = "<date:yyyy-MM-dd>/app-error.log",
                                MinLevel = new Dictionary<string, LogLevel> { ["Default"] = LogLevel.Error }
                            }
                        };
                    });
                    loggingBuilder.SetMinimumLevel(LogLevel.Debug);
                })
                .ConfigureServices((context, services) =>
                {
                    // 基础设施层
                    services.AddSingleton<LogCleaner>(sp =>
                    {
                        var logger = sp.GetRequiredService<ILogger<LogCleaner>>();
                        return new LogCleaner(logger, logBasePath, logRetentionDays, logDiskThresholdMb);
                    });
                    services.AddSingleton<ICircuitBreakerAdapter, CircuitBreakerRetryAdapter>();

                    // OTel链路追踪
                    services.AddJeweleryOpenTelemetryTracing();
                    services.AddSingleton<Tracer>(sp => TracerProvider.Default.GetTracer("JeweleryVisitorDDD"));

                    // 应用层
                    services.AddSingleton<JeweleryProcessElementManager>();
                    services.AddScoped<IJeweleryProcessVisitor, LogAuditProcessVisitor>();
                    services.AddScoped<IJeweleryProcessVisitor, BusinessStatisticsVisitor>();
                    services.AddScoped<JeweleryWorkflowScheduler>();
                })
                .Build();

            // 执行日志清理任务
            var logCleaner = host.Services.GetRequiredService<LogCleaner>();
            await logCleaner.CleanAsync();

            // 获取调度器并执行珠宝业务流程
            var scheduler = host.Services.GetRequiredService<JeweleryWorkflowScheduler>();
            var resultDto = await scheduler.RunFullJeweleryWorkflowAsync();

            Console.WriteLine("珠宝全业务流程执行完成,按任意键退出");
            Console.ReadKey();
            await host.StopAsync();
        }
    }
}

  

输出:

20016b98-85c3-4cc1-8624-5587f564de34

 

posted @ 2026-09-13 17:10  ®Geovin Du Dream Park™  阅读(5)  评论(0)    收藏  举报