Csharp:Visitor Pattern
项目结构:

/*
# 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();
}
}
}
输出:

哲学管理(学)人生, 文学艺术生活, 自动(计算机学)物理(学)工作, 生物(学)化学逆境, 历史(学)测绘(学)时间, 经济(学)数学金钱(理财), 心理(学)医学情绪, 诗词美容情感, 美学建筑(学)家园, 解构建构(分析)整合学习, 智商情商(IQ、EQ)运筹(学)生存.---Geovin Du(涂聚文)
浙公网安备 33010602011771号