moklgy's blog moklgy's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 后端文章

    • 技术题
  • .netcore

    • 《asp.netcore》笔记
    • 《设计模式》
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

moklgy docs

全栈初级开发工程师
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 后端文章

    • 技术题
  • .netcore

    • 《asp.netcore》笔记
    • 《设计模式》
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 对象之间的关系
  • SOLID原则
  • 创建型
  • 结构型
    • 结构型模式
      • 6. 适配器模式
      • 7. 桥接模式
      • 8. 组合模式
      • 9. 装饰模式
      • 10. 外观模式
      • 11. 享元模式
      • 12. 代理模式
  • 行为型一
  • 行为型二
  • 其他模式与组合使用
  • 《设计模式》
moklgydocs
2025-10-12
目录

结构型

# C#设计模式全面指南

# 结构型模式

# 6. 适配器模式

原理:
适配器模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。它通过创建一个包装类(适配器),将一个类的接口转换成客户端期望的另一个接口。

思路:

  1. 定义目标接口(客户端期望的接口)
  2. 创建适配器类实现目标接口
  3. 在适配器中包含被适配者(原有类)的实例
  4. 在适配器的方法中调用被适配者的相应方法

前辈经验:

  • 当需要使用现有类,但其接口与系统其他部分不兼容时,使用适配器模式
  • 适配器可以让原有代码与新系统一起工作,而无需修改原有代码
  • 适配器通常用于集成第三方库或遗留系统
  • 适配器有对象适配器(组合)和类适配器(继承)两种实现方式
  • 适配器模式符合"开闭原则",可以引入新的适配器而无需修改现有代码

业务场景:
系统需要集成多个第三方支付网关,但每个支付网关的API接口各不相同,需要统一接口以便系统使用。

简单实现:

// 目标接口 - 我们系统期望的统一支付接口
public interface IPaymentProcessor
{
    bool ProcessPayment(decimal amount, string currency, string cardNumber, string cardHolderName, string expiryDate, string cvv);
    bool RefundPayment(string transactionId, decimal amount);
    string GetPaymentStatus(string transactionId);
}

// 被适配者 - 第三方支付网关的原始接口
public class PayPalGateway
{
    public string Authenticate(string apiKey, string secretKey)
    {
        // 模拟身份验证
        Console.WriteLine("PayPal身份验证");
        return "PayPal-SessionToken";
    }
    
    public PayPalPaymentResponse MakePayment(PayPalPaymentRequest paymentRequest)
    {
        // 模拟支付处理
        Console.WriteLine($"PayPal处理支付: {paymentRequest.Amount} {paymentRequest.Currency}");
        
        return new PayPalPaymentResponse
        {
            Success = true,
            TransactionId = "PP-" + Guid.NewGuid().ToString().Substring(0, 8),
            Timestamp = DateTime.Now
        };
    }
    
    public PayPalRefundResponse IssueRefund(string transactionId, decimal refundAmount)
    {
        // 模拟退款处理
        Console.WriteLine($"PayPal处理退款: {transactionId}, 金额: {refundAmount}");
        
        return new PayPalRefundResponse
        {
            Success = true,
            RefundId = "PPR-" + Guid.NewGuid().ToString().Substring(0, 8),
            Timestamp = DateTime.Now
        };
    }
    
    public PayPalTransactionStatus CheckTransactionStatus(string transactionId)
    {
        // 模拟状态查询
        Console.WriteLine($"PayPal查询交易状态: {transactionId}");
        
        return new PayPalTransactionStatus
        {
            TransactionId = transactionId,
            Status = "Completed",
            Timestamp = DateTime.Now
        };
    }
}

// PayPal相关类
public class PayPalPaymentRequest
{
    public decimal Amount { get; set; }
    public string Currency { get; set; }
    public string CardNumber { get; set; }
    public string CardHolderName { get; set; }
    public string ExpiryDate { get; set; }
    public string Cvv { get; set; }
}

public class PayPalPaymentResponse
{
    public bool Success { get; set; }
    public string TransactionId { get; set; }
    public DateTime Timestamp { get; set; }
}

public class PayPalRefundResponse
{
    public bool Success { get; set; }
    public string RefundId { get; set; }
    public DateTime Timestamp { get; set; }
}

public class PayPalTransactionStatus
{
    public string TransactionId { get; set; }
    public string Status { get; set; }
    public DateTime Timestamp { get; set; }
}

// 适配器 - 将PayPal网关适配到IPaymentProcessor接口
public class PayPalAdapter : IPaymentProcessor
{
    private readonly PayPalGateway _payPalGateway;
    private readonly string _apiKey;
    private readonly string _secretKey;
    
    public PayPalAdapter(string apiKey, string secretKey)
    {
        _payPalGateway = new PayPalGateway();
        _apiKey = apiKey;
        _secretKey = secretKey;
    }
    
    public bool ProcessPayment(decimal amount, string currency, string cardNumber, string cardHolderName, string expiryDate, string cvv)
    {
        // 先进行身份验证
        string sessionToken = _payPalGateway.Authenticate(_apiKey, _secretKey);
        
        // 创建PayPal支付请求
        var paymentRequest = new PayPalPaymentRequest
        {
            Amount = amount,
            Currency = currency,
            CardNumber = cardNumber,
            CardHolderName = cardHolderName,
            ExpiryDate = expiryDate,
            Cvv = cvv
        };
        
        // 调用PayPal的支付方法
        var response = _payPalGateway.MakePayment(paymentRequest);
        
        // 返回处理结果
        return response.Success;
    }
    
    public bool RefundPayment(string transactionId, decimal amount)
    {
        // 先进行身份验证
        string sessionToken = _payPalGateway.Authenticate(_apiKey, _secretKey);
        
        // 调用PayPal的退款方法
        var response = _payPalGateway.IssueRefund(transactionId, amount);
        
        // 返回处理结果
        return response.Success;
    }
    
    public string GetPaymentStatus(string transactionId)
    {
        // 先进行身份验证
        string sessionToken = _payPalGateway.Authenticate(_apiKey, _secretKey);
        
        // 调用PayPal的状态查询方法
        var status = _payPalGateway.CheckTransactionStatus(transactionId);
        
        // 返回状态
        return status.Status;
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        // 创建PayPal适配器
        IPaymentProcessor paymentProcessor = new PayPalAdapter("your-api-key", "your-secret-key");
        
        // 使用统一接口处理支付
        bool paymentResult = paymentProcessor.ProcessPayment(
            100.00m,
            "USD",
            "4111111111111111",
            "John Doe",
            "12/25",
            "123");
            
        Console.WriteLine($"支付结果: {(paymentResult ? "成功" : "失败")}");
        
        // 查询支付状态
        string status = paymentProcessor.GetPaymentStatus("PP-12345678");
        Console.WriteLine($"支付状态: {status}");
        
        // 处理退款
        bool refundResult = paymentProcessor.RefundPayment("PP-12345678", 50.00m);
        Console.WriteLine($"退款结果: {(refundResult ? "成功" : "失败")}");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

复杂实现:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

// 目标接口 - 统一支付处理接口
public interface IPaymentProcessor
{
    Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request);
    Task<RefundResult> RefundPaymentAsync(RefundRequest request);
    Task<PaymentStatusResult> GetPaymentStatusAsync(string transactionId);
    Task<bool> ValidatePaymentDetailsAsync(PaymentRequest request);
    List<string> GetSupportedPaymentMethods();
    List<string> GetSupportedCurrencies();
}

// 统一的请求/响应模型
public class PaymentRequest
{
    public decimal Amount { get; set; }
    public string Currency { get; set; }
    public string PaymentMethod { get; set; }
    public CardDetails CardDetails { get; set; }
    public BillingAddress BillingAddress { get; set; }
    public Dictionary<string, string> AdditionalData { get; set; } = new Dictionary<string, string>();
}

public class CardDetails
{
    public string CardNumber { get; set; }
    public string CardHolderName { get; set; }
    public string ExpiryMonth { get; set; }
    public string ExpiryYear { get; set; }
    public string Cvv { get; set; }
}

public class BillingAddress
{
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
    public string Country { get; set; }
    public string PhoneNumber { get; set; }
}

public class PaymentResult
{
    public bool Success { get; set; }
    public string TransactionId { get; set; }
    public string Status { get; set; }
    public string Message { get; set; }
    public decimal AmountProcessed { get; set; }
    public string Currency { get; set; }
    public DateTime Timestamp { get; set; }
    public Dictionary<string, string> AdditionalData { get; set; } = new Dictionary<string, string>();
}

public class RefundRequest
{
    public string TransactionId { get; set; }
    public decimal Amount { get; set; }
    public string Reason { get; set; }
}

public class RefundResult
{
    public bool Success { get; set; }
    public string RefundId { get; set; }
    public string Status { get; set; }
    public string Message { get; set; }
    public decimal AmountRefunded { get; set; }
    public DateTime Timestamp { get; set; }
}

public class PaymentStatusResult
{
    public string TransactionId { get; set; }
    public string Status { get; set; }
    public decimal Amount { get; set; }
    public string Currency { get; set; }
    public DateTime Timestamp { get; set; }
    public List<string> StatusHistory { get; set; } = new List<string>();
}

// 被适配者 1 - PayPal网关
public class PayPalGateway
{
    private readonly string _apiKey;
    private readonly string _secretKey;
    private string _sessionToken;
    
    public PayPalGateway(string apiKey, string secretKey)
    {
        _apiKey = apiKey;
        _secretKey = secretKey;
    }
    
    private async Task<string> AuthenticateAsync()
    {
        await Task.Delay(100); // 模拟网络请求
        _sessionToken = "PayPal-SessionToken-" + Guid.NewGuid().ToString().Substring(0, 8);
        Console.WriteLine($"PayPal身份验证: {_sessionToken}");
        return _sessionToken;
    }
    
    public async Task<PayPalPaymentResponse> MakePaymentAsync(PayPalPaymentRequest request)
    {
        if (string.IsNullOrEmpty(_sessionToken))
        {
            await AuthenticateAsync();
        }
        
        await Task.Delay(200); // 模拟网络请求
        Console.WriteLine($"PayPal处理支付: {request.Amount} {request.Currency}");
        
        // 模拟处理逻辑
        bool success = !string.IsNullOrEmpty(request.CreditCard.Number) && 
                       !string.IsNullOrEmpty(request.CreditCard.Cvv) &&
                       request.Amount > 0;
                       
        return new PayPalPaymentResponse
        {
            Success = success,
            TransactionId = success ? "PP-" + Guid.NewGuid().ToString().Substring(0, 8) : null,
            Status = success ? "Completed" : "Failed",
            Timestamp = DateTime.Now,
            ErrorMessage = success ? null : "Invalid payment details"
        };
    }
    
    public async Task<PayPalRefundResponse> IssueRefundAsync(PayPalRefundRequest request)
    {
        if (string.IsNullOrEmpty(_sessionToken))
        {
            await AuthenticateAsync();
        }
        
        await Task.Delay(150); // 模拟网络请求
        Console.WriteLine($"PayPal处理退款: {request.TransactionId}, 金额: {request.Amount}");
        
        return new PayPalRefundResponse
        {
            Success = true,
            RefundId = "PPR-" + Guid.NewGuid().ToString().Substring(0, 8),
            Status = "Completed",
            Timestamp = DateTime.Now
        };
    }
    
    public async Task<PayPalTransactionStatus> CheckTransactionStatusAsync(string transactionId)
    {
        if (string.IsNullOrEmpty(_sessionToken))
        {
            await AuthenticateAsync();
        }
        
        await Task.Delay(100); // 模拟网络请求
        Console.WriteLine($"PayPal查询交易状态: {transactionId}");
        
        return new PayPalTransactionStatus
        {
            TransactionId = transactionId,
            Status = "Completed",
            Amount = 100.00m, // 模拟金额
            Currency = "USD",
            Timestamp = DateTime.Now,
            StatusHistory = new List<string> { "Pending", "Processing", "Completed" }
        };
    }
    
    public async Task<PayPalValidationResult> ValidatePaymentDetailsAsync(PayPalPaymentRequest request)
    {
        if (string.IsNullOrEmpty(_sessionToken))
        {
            await AuthenticateAsync();
        }
        
        await Task.Delay(50); // 模拟网络请求
        Console.WriteLine($"PayPal验证支付详情");
        
        bool isValid = !string.IsNullOrEmpty(request.CreditCard.Number) && 
                       request.CreditCard.Number.Length >= 13 && 
                       !string.IsNullOrEmpty(request.CreditCard.Cvv);
                       
        return new PayPalValidationResult
        {
            IsValid = isValid,
            Message = isValid ? "Validation successful" : "Invalid card details"
        };
    }
    
    public List<string> GetSupportedCurrencies()
    {
        return new List<string> { "USD", "EUR", "GBP", "CAD", "AUD", "JPY" };
    }
    
    public List<string> GetSupportedPaymentMethods()
    {
        return new List<string> { "visa", "mastercard", "amex", "discover" };
    }
}

// PayPal相关类
public class PayPalPaymentRequest
{
    public decimal Amount { get; set; }
    public string Currency { get; set; }
    public PayPalCreditCard CreditCard { get; set; }
    public PayPalPayer Payer { get; set; }
    public Dictionary<string, string> Metadata { get; set; } = new Dictionary<string, string>();
}

public class PayPalCreditCard
{
    public string Number { get; set; }
    public string Type { get; set; }
    public string ExpMonth { get; set; }
    public string ExpYear { get; set; }
    public string Cvv { get; set; }
    public string CardholderName { get; set; }
}

public class PayPalPayer
{
    public string Email { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public PayPalAddress BillingAddress { get; set; }
}

public class PayPalAddress
{
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
    public string CountryCode { get; set; }
    public string Phone { get; set; }
}

public class PayPalPaymentResponse
{
    public bool Success { get; set; }
    public string TransactionId { get; set; }
    public string Status { get; set; }
    public DateTime Timestamp { get; set; }
    public string ErrorMessage { get; set; }
}

public class PayPalRefundRequest
{
    public string TransactionId { get; set; }
    public decimal Amount { get; set; }
    public string Reason { get; set; }
}

public class PayPalRefundResponse
{
    public bool Success { get; set; }
    public string RefundId { get; set; }
    public string Status { get; set; }
    public DateTime Timestamp { get; set; }
    public string ErrorMessage { get; set; }
}

public class PayPalTransactionStatus
{
    public string TransactionId { get; set; }
    public string Status { get; set; }
    public decimal Amount { get; set; }
    public string Currency { get; set; }
    public DateTime Timestamp { get; set; }
    public List<string> StatusHistory { get; set; } = new List<string>();
}

public class PayPalValidationResult
{
    public bool IsValid { get; set; }
    public string Message { get; set; }
}

// 被适配者 2 - Stripe网关
public class StripeGateway
{
    private readonly string _apiKey;
    
    public StripeGateway(string apiKey)
    {
        _apiKey = apiKey;
    }
    
    public async Task<StripeChargeResponse> CreateChargeAsync(StripeChargeRequest request)
    {
        await Task.Delay(150); // 模拟网络请求
        Console.WriteLine($"Stripe创建支付: {request.Amount} {request.Currency}");
        
        bool success = !string.IsNullOrEmpty(request.Source.Token) && request.Amount > 0;
        
        return new StripeChargeResponse
        {
            Id = success ? "ch_" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 24) : null,
            Object = "charge",
            Amount = (long)(request.Amount * 100), // Stripe使用分为单位
            Currency = request.Currency,
            Status = success ? "succeeded" : "failed",
            Created = DateTimeOffset.Now.ToUnixTimeSeconds(),
            Paid = success,
            FailureCode = success ? null : "card_declined",
            FailureMessage = success ? null : "Your card was declined"
        };
    }
    
    public async Task<StripeRefundResponse> CreateRefundAsync(StripeRefundRequest request)
    {
        await Task.Delay(120); // 模拟网络请求
        Console.WriteLine($"Stripe创建退款: {request.ChargeId}");
        
        return new StripeRefundResponse
        {
            Id = "re_" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 24),
            Object = "refund",
            Amount = request.Amount != null ? (long)request.Amount : 0,
            ChargeId = request.ChargeId,
            Created = DateTimeOffset.Now.ToUnixTimeSeconds(),
            Currency = "usd", // 默认
            Status = "succeeded"
        };
    }
    
    public async Task<StripeChargeResponse> RetrieveChargeAsync(string chargeId)
    {
        await Task.Delay(80); // 模拟网络请求
        Console.WriteLine($"Stripe查询支付: {chargeId}");
        
        return new StripeChargeResponse
        {
            Id = chargeId,
            Object = "charge",
            Amount = 10000, // 模拟金额 $100.00
            Currency = "usd",
            Status = "succeeded",
            Created = DateTimeOffset.Now.AddMinutes(-10).ToUnixTimeSeconds(),
            Paid = true
        };
    }
    
    public async Task<TokenValidationResult> ValidateCardAsync(CardValidationRequest request)
    {
        await Task.Delay(50); // 模拟网络请求
        Console.WriteLine("Stripe验证卡信息");
        
        bool isValid = !string.IsNullOrEmpty(request.CardNumber) && 
                       !string.IsNullOrEmpty(request.Cvc) &&
                       !string.IsNullOrEmpty(request.ExpMonth) &&
                       !string.IsNullOrEmpty(request.ExpYear);
                       
        return new TokenValidationResult
        {
            IsValid = isValid,
            ErrorMessage = isValid ? null : "Invalid card information"
        };
    }
    
    public List<string> SupportedCurrencies()
    {
        return new List<string> { "USD", "EUR", "GBP", "AUD", "CAD", "CHF", "CNY", "JPY" };
    }
    
    public List<string> SupportedCardBrands()
    {
        return new List<string> { "visa", "mastercard", "amex", "discover", "jcb", "diners" };
    }
}

// Stripe相关类
public class StripeChargeRequest
{
    public long Amount { get; set; }
    public string Currency { get; set; }
    public StripeSource Source { get; set; }
    public string Description { get; set; }
    public Dictionary<string, string> Metadata { get; set; } = new Dictionary<string, string>();
}

public class StripeSource
{
    public string Token { get; set; } // 支付令牌
    public string Object { get; set; } // 如 "card"
}

public class StripeChargeResponse
{
    public string Id { get; set; }
    public string Object { get; set; }
    public long Amount { get; set; }
    public string Currency { get; set; }
    public string Status { get; set; }
    public long Created { get; set; }
    public bool Paid { get; set; }
    public string FailureCode { get; set; }
    public string FailureMessage { get; set; }
}

public class StripeRefundRequest
{
    public string ChargeId { get; set; }
    public long? Amount { get; set; }
    public string Reason { get; set; }
}

public class StripeRefundResponse
{
    public string Id { get; set; }
    public string Object { get; set; }
    public long Amount { get; set; }
    public string ChargeId { get; set; }
    public long Created { get; set; }
    public string Currency { get; set; }
    public string Status { get; set; }
}

public class CardValidationRequest
{
    public string CardNumber { get; set; }
    public string ExpMonth { get; set; }
    public string ExpYear { get; set; }
    public string Cvc { get; set; }
}

public class TokenValidationResult
{
    public bool IsValid { get; set; }
    public string ErrorMessage { get; set; }
}

// 适配器 - PayPal适配器
public class PayPalAdapter : IPaymentProcessor
{
    private readonly PayPalGateway _payPalGateway;
    
    public PayPalAdapter(string apiKey, string secretKey)
    {
        _payPalGateway = new PayPalGateway(apiKey, secretKey);
    }
    
    public async Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request)
    {
        // 将统一请求模型转换为PayPal请求模型
        var payPalRequest = new PayPalPaymentRequest
        {
            Amount = request.Amount,
            Currency = request.Currency,
            CreditCard = new PayPalCreditCard
            {
                Number = request.CardDetails.CardNumber,
                Type = MapCardType(request.CardDetails.CardNumber),
                ExpMonth = request.CardDetails.ExpiryMonth,
                ExpYear = request.CardDetails.ExpiryYear,
                Cvv = request.CardDetails.Cvv,
                CardholderName = request.CardDetails.CardHolderName
            },
            Payer = new PayPalPayer
            {
                Email = request.AdditionalData.ContainsKey("email") ? request.AdditionalData["email"] : null,
                FirstName = request.AdditionalData.ContainsKey("firstName") ? request.AdditionalData["firstName"] : null,
                LastName = request.AdditionalData.ContainsKey("lastName") ? request.AdditionalData["lastName"] : null,
                BillingAddress = request.BillingAddress != null ? new PayPalAddress
                {
                    Line1 = request.BillingAddress.Line1,
                    Line2 = request.BillingAddress.Line2,
                    City = request.BillingAddress.City,
                    State = request.BillingAddress.State,
                    PostalCode = request.BillingAddress.PostalCode,
                    CountryCode = request.BillingAddress.Country,
                    Phone = request.BillingAddress.PhoneNumber
                } : null
            }
        };
        
        // 调用PayPal网关
        var payPalResponse = await _payPalGateway.MakePaymentAsync(payPalRequest);
        
        // 将PayPal响应转换为统一响应模型
        return new PaymentResult
        {
            Success = payPalResponse.Success,
            TransactionId = payPalResponse.TransactionId,
            Status = payPalResponse.Status,
            Message = payPalResponse.ErrorMessage,
            AmountProcessed = request.Amount,
            Currency = request.Currency,
            Timestamp = payPalResponse.Timestamp,
            AdditionalData = new Dictionary<string, string>
            {
                { "provider", "PayPal" }
            }
        };
    }
    
    public async Task<RefundResult> RefundPaymentAsync(RefundRequest request)
    {
        // 将统一请求模型转换为PayPal请求模型
        var payPalRequest = new PayPalRefundRequest
        {
            TransactionId = request.TransactionId,
            Amount = request.Amount,
            Reason = request.Reason
        };
        
        // 调用PayPal网关
        var payPalResponse = await _payPalGateway.IssueRefundAsync(payPalRequest);
        
        // 将PayPal响应转换为统一响应模型
        return new RefundResult
        {
            Success = payPalResponse.Success,
            RefundId = payPalResponse.RefundId,
            Status = payPalResponse.Status,
            Message = payPalResponse.ErrorMessage,
            AmountRefunded = request.Amount,
            Timestamp = payPalResponse.Timestamp
        };
    }
    
    public async Task<PaymentStatusResult> GetPaymentStatusAsync(string transactionId)
    {
        // 调用PayPal网关
        var payPalStatus = await _payPalGateway.CheckTransactionStatusAsync(transactionId);
        
        // 将PayPal响应转换为统一响应模型
        return new PaymentStatusResult
        {
            TransactionId = payPalStatus.TransactionId,
            Status = MapStatus(payPalStatus.Status),
            Amount = payPalStatus.Amount,
            Currency = payPalStatus.Currency,
            Timestamp = payPalStatus.Timestamp,
            StatusHistory = payPalStatus.StatusHistory
        };
    }
    
    public async Task<bool> ValidatePaymentDetailsAsync(PaymentRequest request)
    {
        // 将统一请求模型转换为PayPal请求模型
        var payPalRequest = new PayPalPaymentRequest
        {
            Amount = request.Amount,
            Currency = request.Currency,
            CreditCard = new PayPalCreditCard
            {
                Number = request.CardDetails.CardNumber,
                Type = MapCardType(request.CardDetails.CardNumber),
                ExpMonth = request.CardDetails.ExpiryMonth,
                ExpYear = request.CardDetails.ExpiryYear,
                Cvv = request.CardDetails.Cvv,
                CardholderName = request.CardDetails.CardHolderName
            }
        };
        
        // 调用PayPal网关
        var validationResult = await _payPalGateway.ValidatePaymentDetailsAsync(payPalRequest);
        
        return validationResult.IsValid;
    }
    
    public List<string> GetSupportedPaymentMethods()
    {
        return _payPalGateway.GetSupportedPaymentMethods();
    }
    
    public List<string> GetSupportedCurrencies()
    {
        return _payPalGateway.GetSupportedCurrencies();
    }
    
    // 辅助方法 - 映射卡类型
    private string MapCardType(string cardNumber)
    {
        if (string.IsNullOrEmpty(cardNumber))
            return "unknown";
            
        if (cardNumber.StartsWith("4"))
            return "visa";
        if (cardNumber.StartsWith("5"))
            return "mastercard";
        if (cardNumber.StartsWith("34") || cardNumber.StartsWith("37"))
            return "amex";
        if (cardNumber.StartsWith("6"))
            return "discover";
            
        return "unknown";
    }
    
    // 辅助方法 - 映射状态
    private string MapStatus(string payPalStatus)
    {
        switch (payPalStatus.ToLower())
        {
            case "completed":
                return "Completed";
            case "pending":
                return "Pending";
            case "refunded":
                return "Refunded";
            case "failed":
                return "Failed";
            default:
                return payPalStatus;
        }
    }
}

// 适配器 - Stripe适配器
public class StripeAdapter : IPaymentProcessor
{
    private readonly StripeGateway _stripeGateway;
    
    public StripeAdapter(string apiKey)
    {
        _stripeGateway = new StripeGateway(apiKey);
    }
    
    public async Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request)
    {
        // 首先验证卡信息并获取令牌(实际Stripe使用中应该由前端获取令牌)
        var cardValidation = new CardValidationRequest
        {
            CardNumber = request.CardDetails.CardNumber,
            ExpMonth = request.CardDetails.ExpiryMonth,
            ExpYear = request.CardDetails.ExpiryYear,
            Cvc = request.CardDetails.Cvv
        };
        
        var validationResult = await _stripeGateway.ValidateCardAsync(cardValidation);
        if (!validationResult.IsValid)
        {
            return new PaymentResult
            {
                Success = false,
                Message = validationResult.ErrorMessage,
                Timestamp = DateTime.Now
            };
        }
        
        // 模拟令牌
        string token = "tok_" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 24);
        
        // 将统一请求模型转换为Stripe请求模型
        var stripeRequest = new StripeChargeRequest
        {
            Amount = request.Amount,
            Currency = request.Currency.ToLower(),
            Source = new StripeSource
            {
                Token = token,
                Object = "card"
            },
            Description = request.AdditionalData.ContainsKey("description") ? request.AdditionalData["description"] : null,
            Metadata = new Dictionary<string, string>
            {
                { "customer_name", request.CardDetails.CardHolderName }
            }
        };
        
        // 添加额外数据
        foreach (var item in request.AdditionalData)
        {
            if (!stripeRequest.Metadata.ContainsKey(item.Key))
            {
                stripeRequest.Metadata.Add(item.Key, item.Value);
            }
        }
        
        // 调用Stripe网关
        var stripeResponse = await _stripeGateway.CreateChargeAsync(stripeRequest);
        
        // 将Stripe响应转换为统一响应模型
        return new PaymentResult
        {
            Success = stripeResponse.Paid,
            TransactionId = stripeResponse.Id,
            Status = MapStatus(stripeResponse.Status),
            Message = stripeResponse.FailureMessage,
            AmountProcessed = stripeResponse.Amount / 100m, // 从分转换为元
            Currency = stripeResponse.Currency,
            Timestamp = DateTimeOffset.FromUnixTimeSeconds(stripeResponse.Created).DateTime,
            AdditionalData = new Dictionary<string, string>
            {
                { "provider", "Stripe" },
                { "paid", stripeResponse.Paid.ToString() }
            }
        };
    }
    
    public async Task<RefundResult> RefundPaymentAsync(RefundRequest request)
    {
        // 将统一请求模型转换为Stripe请求模型
        var stripeRequest = new StripeRefundRequest
        {
            ChargeId = request.TransactionId,
            Amount = (long)(request.Amount * 100), // 转换为分
            Reason = MapRefundReason(request.Reason)
        };
        
        // 调用Stripe网关
        var stripeResponse = await _stripeGateway.CreateRefundAsync(stripeRequest);
        
        // 将Stripe响应转换为统一响应模型
        return new RefundResult
        {
            Success = stripeResponse.Status == "succeeded",
            RefundId = stripeResponse.Id,
            Status = MapStatus(stripeResponse.Status),
            AmountRefunded = stripeResponse.Amount / 100m, // 从分转换为元
            Timestamp = DateTimeOffset.FromUnixTimeSeconds(stripeResponse.Created).DateTime
        };
    }
    
    public async Task<PaymentStatusResult> GetPaymentStatusAsync(string transactionId)
    {
        // 调用Stripe网关
        var stripeCharge = await _stripeGateway.RetrieveChargeAsync(transactionId);
        
        // 将Stripe响应转换为统一响应模型
        return new PaymentStatusResult
        {
            TransactionId = stripeCharge.Id,
            Status = MapStatus(stripeCharge.Status),
            Amount = stripeCharge.Amount / 100m, // 从分转换为元
            Currency = stripeCharge.Currency,
            Timestamp = DateTimeOffset.FromUnixTimeSeconds(stripeCharge.Created).DateTime,
            StatusHistory = new List<string> { stripeCharge.Status } // Stripe不提供历史状态
        };
    }
    
    public async Task<bool> ValidatePaymentDetailsAsync(PaymentRequest request)
    {
        var cardValidation = new CardValidationRequest
        {
            CardNumber = request.CardDetails.CardNumber,
            ExpMonth = request.CardDetails.ExpiryMonth,
            ExpYear = request.CardDetails.ExpiryYear,
            Cvc = request.CardDetails.Cvv
        };
        
        var validationResult = await _stripeGateway.ValidateCardAsync(cardValidation);
        return validationResult.IsValid;
    }
    
    public List<string> GetSupportedPaymentMethods()
    {
        return _stripeGateway.SupportedCardBrands();
    }
    
    public List<string> GetSupportedCurrencies()
    {
        return _stripeGateway.SupportedCurrencies();
    }
    
    // 辅助方法 - 映射状态
    private string MapStatus(string stripeStatus)
    {
        switch (stripeStatus.ToLower())
        {
            case "succeeded":
                return "Completed";
            case "pending":
                return "Pending";
            case "failed":
                return "Failed";
            default:
                return stripeStatus;
        }
    }
    
    // 辅助方法 - 映射退款原因
    private string MapRefundReason(string reason)
    {
        if (string.IsNullOrEmpty(reason))
            return null;
            
        if (reason.Contains("requested_by_customer", StringComparison.OrdinalIgnoreCase))
            return "requested_by_customer";
        if (reason.Contains("duplicate", StringComparison.OrdinalIgnoreCase))
            return "duplicate";
        if (reason.Contains("fraudulent", StringComparison.OrdinalIgnoreCase))
            return "fraudulent";
            
        return null;
    }
}

// 支付处理工厂
public class PaymentProcessorFactory
{
    private readonly Dictionary<string, IPaymentProcessor> _processors = new Dictionary<string, IPaymentProcessor>();
    
    public void RegisterProcessor(string name, IPaymentProcessor processor)
    {
        if (!_processors.ContainsKey(name.ToLower()))
        {
            _processors.Add(name.ToLower(), processor);
        }
    }
    
    public IPaymentProcessor GetProcessor(string name)
    {
        if (_processors.TryGetValue(name.ToLower(), out var processor))
        {
            return processor;
        }
        
        throw new ArgumentException($"Payment processor '{name}' is not registered.");
    }
    
    public List<string> GetAvailableProcessors()
    {
        return _processors.Keys.ToList();
    }
}

// 客户端代码
public class Client
{
    public static async Task Main()
    {
        // 创建并注册支付处理器
        var factory = new PaymentProcessorFactory();
        factory.RegisterProcessor("paypal", new PayPalAdapter("paypal-api-key", "paypal-secret-key"));
        factory.RegisterProcessor("stripe", new StripeAdapter("stripe-api-key"));
        
        Console.WriteLine("可用的支付处理器:");
        foreach (var processor in factory.GetAvailableProcessors())
        {
            Console.WriteLine($"- {processor}");
        }
        
        // 创建支付请求
        var paymentRequest = new PaymentRequest
        {
            Amount = 99.99m,
            Currency = "USD",
            PaymentMethod = "credit_card",
            CardDetails = new CardDetails
            {
                CardNumber = "4111111111111111",
                CardHolderName = "John Doe",
                ExpiryMonth = "12",
                ExpiryYear = "2025",
                Cvv = "123"
            },
            BillingAddress = new BillingAddress
            {
                Line1 = "123 Main St",
                City = "New York",
                State = "NY",
                PostalCode = "10001",
                Country = "US",
                PhoneNumber = "+1234567890"
            },
            AdditionalData = new Dictionary<string, string>
            {
                { "email", "john.doe@example.com" },
                { "description", "Purchase from Example Store" }
            }
        };
        
        // 处理支付 - PayPal
        Console.WriteLine("\n使用PayPal处理支付:");
        var paypalProcessor = factory.GetProcessor("paypal");
        var paypalResult = await paypalProcessor.ProcessPaymentAsync(paymentRequest);
        
        Console.WriteLine($"支付结果: {(paypalResult.Success ? "成功" : "失败")}");
        Console.WriteLine($"交易ID: {paypalResult.TransactionId}");
        Console.WriteLine($"状态: {paypalResult.Status}");
        
        if (paypalResult.Success)
        {
            // 查询支付状态
            Console.WriteLine("\n查询PayPal支付状态:");
            var statusResult = await paypalProcessor.GetPaymentStatusAsync(paypalResult.TransactionId);
            Console.WriteLine($"状态: {statusResult.Status}");
            
            // 处理退款
            Console.WriteLine("\n处理PayPal退款:");
            var refundRequest = new RefundRequest
            {
                TransactionId = paypalResult.TransactionId,
                Amount = 49.99m, // 部分退款
                Reason = "Customer requested"
            };
            
            var refundResult = await paypalProcessor.RefundPaymentAsync(refundRequest);
            Console.WriteLine($"退款结果: {(refundResult.Success ? "成功" : "失败")}");
            Console.WriteLine($"退款ID: {refundResult.RefundId}");
            Console.WriteLine($"退款状态: {refundResult.Status}");
        }
        
        // 处理支付 - Stripe
        Console.WriteLine("\n使用Stripe处理支付:");
        var stripeProcessor = factory.GetProcessor("stripe");
        var stripeResult = await stripeProcessor.ProcessPaymentAsync(paymentRequest);
        
        Console.WriteLine($"支付结果: {(stripeResult.Success ? "成功" : "失败")}");
        Console.WriteLine($"交易ID: {stripeResult.TransactionId}");
        Console.WriteLine($"状态: {stripeResult.Status}");
        
        if (stripeResult.Success)
        {
            // 查询支付状态
            Console.WriteLine("\n查询Stripe支付状态:");
            var statusResult = await stripeProcessor.GetPaymentStatusAsync(stripeResult.TransactionId);
            Console.WriteLine($"状态: {statusResult.Status}");
            
            // 处理退款
            Console.WriteLine("\n处理Stripe退款:");
            var refundRequest = new RefundRequest
            {
                TransactionId = stripeResult.TransactionId,
                Amount = 99.99m, // 全额退款
                Reason = "Duplicate charge"
            };
            
            var refundResult = await stripeProcessor.RefundPaymentAsync(refundRequest);
            Console.WriteLine($"退款结果: {(refundResult.Success ? "成功" : "失败")}");
            Console.WriteLine($"退款ID: {refundResult.RefundId}");
            Console.WriteLine($"退款状态: {refundResult.Status}");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932

业务场景结合:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

// 1. 外部遗留系统接口

// CRM系统接口(遗留系统)
public interface ILegacyCrmSystem
{
    Task<CustomerData> GetCustomerByIdAsync(string customerId);
    Task<bool> UpdateCustomerInfoAsync(CustomerData customerData);
    Task<List<string>> GetCustomerOrderIdsAsync(string customerId);
}

// 遗留CRM数据模型
public class CustomerData
{
    public string CustomerId { get; set; }
    public string Title { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string CompanyName { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
    public string MobileNumber { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string Region { get; set; }
    public string PostCode { get; set; }
    public string Country { get; set; }
    public string CustomerType { get; set; } // Individual or Business
    public DateTime JoinDate { get; set; }
    public decimal LifetimeValue { get; set; }
    public bool IsActive { get; set; }
}

// 遗留CRM系统实现
public class LegacyCrmSystem : ILegacyCrmSystem
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<LegacyCrmSystem> _logger;
    private readonly string _baseUrl;
    private readonly string _apiKey;
    
    public LegacyCrmSystem(HttpClient httpClient, ILogger<LegacyCrmSystem> logger, IConfiguration configuration)
    {
        _httpClient = httpClient;
        _logger = logger;
        _baseUrl = configuration["LegacyCrm:BaseUrl"];
        _apiKey = configuration["LegacyCrm:ApiKey"];
        
        _httpClient.DefaultRequestHeaders.Add("X-API-KEY", _apiKey);
    }
    
    public async Task<CustomerData> GetCustomerByIdAsync(string customerId)
    {
        try
        {
            _logger.LogInformation("获取客户信息,ID: {CustomerId}", customerId);
            var response = await _httpClient.GetAsync($"{_baseUrl}/customers/{customerId}");
            
            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("获取客户信息失败,状态码: {StatusCode}", response.StatusCode);
                return null;
            }
            
            var customer = await response.Content.ReadFromJsonAsync<CustomerData>();
            return customer;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取客户信息时出错,ID: {CustomerId}", customerId);
            throw;
        }
    }
    
    public async Task<bool> UpdateCustomerInfoAsync(CustomerData customerData)
    {
        try
        {
            _logger.LogInformation("更新客户信息,ID: {CustomerId}", customerData.CustomerId);
            
            var content = new StringContent(
                JsonSerializer.Serialize(customerData),
                Encoding.UTF8,
                "application/json");
                
            var response = await _httpClient.PutAsync($"{_baseUrl}/customers/{customerData.CustomerId}", content);
            
            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("更新客户信息失败,状态码: {StatusCode}", response.StatusCode);
                return false;
            }
            
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "更新客户信息时出错,ID: {CustomerId}", customerData.CustomerId);
            throw;
        }
    }
    
    public async Task<List<string>> GetCustomerOrderIdsAsync(string customerId)
    {
        try
        {
            _logger.LogInformation("获取客户订单,ID: {CustomerId}", customerId);
            var response = await _httpClient.GetAsync($"{_baseUrl}/customers/{customerId}/orders");
            
            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("获取客户订单失败,状态码: {StatusCode}", response.StatusCode);
                return new List<string>();
            }
            
            var orders = await response.Content.ReadFromJsonAsync<List<string>>();
            return orders;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取客户订单时出错,ID: {CustomerId}", customerId);
            throw;
        }
    }
}

// 2. 新系统接口

// 新的客户服务接口
public interface ICustomerService
{
    Task<Customer> GetCustomerAsync(string id);
    Task<bool> UpdateCustomerAsync(Customer customer);
    Task<List<Order>> GetCustomerOrdersAsync(string customerId);
    Task<bool> AddCustomerNoteAsync(string customerId, string note);
    Task<List<CustomerNote>> GetCustomerNotesAsync(string customerId);
    Task<CustomerStatistics> GetCustomerStatisticsAsync(string customerId);
}

// 新系统的数据模型
public class Customer
{
    public string Id { get; set; }
    public PersonalInfo PersonalInfo { get; set; }
    public ContactInfo ContactInfo { get; set; }
    public Address Address { get; set; }
    public CustomerProfile Profile { get; set; }
}

public class PersonalInfo
{
    public string Title { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName => $"{FirstName} {LastName}";
    public string CompanyName { get; set; }
}

public class ContactInfo
{
    public string Email { get; set; }
    public string PrimaryPhone { get; set; }
    public string MobilePhone { get; set; }
    public string PreferredContact { get; set; } // Email, Phone, Mobile
}

public class Address
{
    public string Street1 { get; set; }
    public string Street2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
    public string Country { get; set; }
    public string FormattedAddress => 
        $"{Street1}, {(string.IsNullOrEmpty(Street2) ? "" : Street2 + ", ")}{City}, {State} {PostalCode}, {Country}";
}

public class CustomerProfile
{
    public CustomerType Type { get; set; }
    public DateTime RegisteredDate { get; set; }
    public decimal TotalSpent { get; set; }
    public int TotalOrders { get; set; }
    public bool IsActive { get; set; }
    public string LoyaltyTier { get; set; } // None, Silver, Gold, Platinum
}

public enum CustomerType
{
    Individual,
    Business
}

public class Order
{
    public string Id { get; set; }
    public string CustomerId { get; set; }
    public DateTime OrderDate { get; set; }
    public decimal TotalAmount { get; set; }
    public string Status { get; set; }
    public List<OrderItem> Items { get; set; }
    public string ShippingAddress { get; set; }
    public PaymentInfo Payment { get; set; }
}

public class OrderItem
{
    public string ProductId { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal TotalPrice => Quantity * UnitPrice;
}

public class PaymentInfo
{
    public string Method { get; set; }
    public string Status { get; set; }
    public DateTime? PaymentDate { get; set; }
}

public class CustomerNote
{
    public string Id { get; set; }
    public string CustomerId { get; set; }
    public string Text { get; set; }
    public string CreatedBy { get; set; }
    public DateTime CreatedAt { get; set; }
}

public class CustomerStatistics
{
    public string CustomerId { get; set; }
    public int TotalOrders { get; set; }
    public decimal TotalSpent { get; set; }
    public decimal AverageOrderValue { get; set; }
    public DateTime FirstOrderDate { get; set; }
    public DateTime LastOrderDate { get; set; }
    public int DaysSinceLastOrder { get; set; }
    public string TopCategory { get; set; }
    public string LoyaltyTier { get; set; }
}

// 3. 适配器实现

// CRM适配器 - 将遗留CRM系统适配到新系统的接口
public class LegacyCrmAdapter : ICustomerService
{
    private readonly ILegacyCrmSystem _legacyCrm;
    private readonly ILogger<LegacyCrmAdapter> _logger;
    private readonly IOrderService _orderService; // 假设有一个订单服务来获取订单详情
    
    public LegacyCrmAdapter(
        ILegacyCrmSystem legacyCrm,
        IOrderService orderService,
        ILogger<LegacyCrmAdapter> logger)
    {
        _legacyCrm = legacyCrm;
        _orderService = orderService;
        _logger = logger;
    }
    
    public async Task<Customer> GetCustomerAsync(string id)
    {
        try
        {
            var legacyCustomer = await _legacyCrm.GetCustomerByIdAsync(id);
            if (legacyCustomer == null)
            {
                return null;
            }
            
            // 转换数据模型
            return MapToCustomer(legacyCustomer);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "适配器获取客户时出错,ID: {CustomerId}", id);
            throw;
        }
    }
    
    public async Task<bool> UpdateCustomerAsync(Customer customer)
    {
        try
        {
            // 转换为遗留系统的数据模型
            var legacyCustomer = MapToLegacyCustomer(customer);
            
            // 调用遗留系统的更新方法
            return await _legacyCrm.UpdateCustomerInfoAsync(legacyCustomer);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "适配器更新客户时出错,ID: {CustomerId}", customer.Id);
            throw;
        }
    }
    
    public async Task<List<Order>> GetCustomerOrdersAsync(string customerId)
    {
        try
        {
            // 获取订单ID列表
            var orderIds = await _legacyCrm.GetCustomerOrderIdsAsync(customerId);
            if (orderIds == null || orderIds.Count == 0)
            {
                return new List<Order>();
            }
            
            // 获取每个订单的详细信息
            var orders = new List<Order>();
            foreach (var orderId in orderIds)
            {
                try
                {
                    var order = await _orderService.GetOrderAsync(orderId);
                    if (order != null)
                    {
                        orders.Add(order);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "获取订单详情时出错,订单ID: {OrderId}", orderId);
                    // 继续处理其他订单
                }
            }
            
            return orders;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "适配器获取客户订单时出错,ID: {CustomerId}", customerId);
            throw;
        }
    }
    
    public async Task<bool> AddCustomerNoteAsync(string customerId, string note)
    {
        // 遗留系统不支持客户笔记功能
        _logger.LogWarning("遗留CRM系统不支持添加客户笔记,该功能被忽略");
        return false;
    }
    
    public async Task<List<CustomerNote>> GetCustomerNotesAsync(string customerId)
    {
        // 遗留系统不支持客户笔记功能
        _logger.LogWarning("遗留CRM系统不支持客户笔记,返回空列表");
        return new List<CustomerNote>();
    }
    
    public async Task<CustomerStatistics> GetCustomerStatisticsAsync(string customerId)
    {
        try
        {
            // 获取客户信息
            var customer = await _legacyCrm.GetCustomerByIdAsync(customerId);
            if (customer == null)
            {
                return null;
            }
            
            // 获取订单
            var orders = await GetCustomerOrdersAsync(customerId);
            
            // 计算统计信息
            var statistics = new CustomerStatistics
            {
                CustomerId = customerId,
                TotalOrders = orders.Count,
                TotalSpent = customer.LifetimeValue,
                AverageOrderValue = orders.Count > 0 ? customer.LifetimeValue / orders.Count : 0,
                FirstOrderDate = orders.Count > 0 ? orders.Min(o => o.OrderDate) : DateTime.MinValue,
                LastOrderDate = orders.Count > 0 ? orders.Max(o => o.OrderDate) : DateTime.MinValue
            };
            
            // 计算自上次订单以来的天数
            if (statistics.LastOrderDate != DateTime.MinValue)
            {
                statistics.DaysSinceLastOrder = (int)(DateTime.Now - statistics.LastOrderDate).TotalDays;
            }
            
            // 设置忠诚度等级(基于总消费)
            statistics.LoyaltyTier = DetermineLoyaltyTier(customer.LifetimeValue);
            
            // 计算最常购买的类别(此功能在遗留系统中不可用,返回未知)
            statistics.TopCategory = "Unknown";
            
            return statistics;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "适配器获取客户统计时出错,ID: {CustomerId}", customerId);
            throw;
        }
    }
    
    // 辅助方法 - 将遗留系统的客户数据转换为新系统的模型
    private Customer MapToCustomer(CustomerData legacyCustomer)
    {
        return new Customer
        {
            Id = legacyCustomer.CustomerId,
            PersonalInfo = new PersonalInfo
            {
                Title = legacyCustomer.Title,
                FirstName = legacyCustomer.FirstName,
                LastName = legacyCustomer.LastName,
                CompanyName = legacyCustomer.CompanyName
            },
            ContactInfo = new ContactInfo
            {
                Email = legacyCustomer.Email,
                PrimaryPhone = legacyCustomer.PhoneNumber,
                MobilePhone = legacyCustomer.MobileNumber,
                PreferredContact = "Email" // 默认值,遗留系统没有此字段
            },
            Address = new Address
            {
                Street1 = legacyCustomer.AddressLine1,
                Street2 = legacyCustomer.AddressLine2,
                City = legacyCustomer.City,
                State = legacyCustomer.Region,
                PostalCode = legacyCustomer.PostCode,
                Country = legacyCustomer.Country
            },
            Profile = new CustomerProfile
            {
                Type = legacyCustomer.CustomerType == "Business" ? CustomerType.Business : CustomerType.Individual,
                RegisteredDate = legacyCustomer.JoinDate,
                TotalSpent = legacyCustomer.LifetimeValue,
                IsActive = legacyCustomer.IsActive,
                LoyaltyTier = DetermineLoyaltyTier(legacyCustomer.LifetimeValue)
            }
        };
    }
    
    // 辅助方法 - 将新系统的客户数据转换为遗留系统的模型
    private CustomerData MapToLegacyCustomer(Customer customer)
    {
        return new CustomerData
        {
            CustomerId = customer.Id,
            Title = customer.PersonalInfo.Title,
            FirstName = customer.PersonalInfo.FirstName,
            LastName = customer.PersonalInfo.LastName,
            CompanyName = customer.PersonalInfo.CompanyName,
            Email = customer.ContactInfo.Email,
            PhoneNumber = customer.ContactInfo.PrimaryPhone,
            MobileNumber = customer.ContactInfo.MobilePhone,
            AddressLine1 = customer.Address.Street1,
            AddressLine2 = customer.Address.Street2,
            City = customer.Address.City,
            Region = customer.Address.State,
            PostCode = customer.Address.PostalCode,
            Country = customer.Address.Country,
            CustomerType = customer.Profile.Type == CustomerType.Business ? "Business" : "Individual",
            JoinDate = customer.Profile.RegisteredDate,
            LifetimeValue = customer.Profile.TotalSpent,
            IsActive = customer.Profile.IsActive
        };
    }
    
    // 辅助方法 - 根据客户总消费确定忠诚度等级
    private string DetermineLoyaltyTier(decimal lifetimeValue)
    {
        if (lifetimeValue >= 10000)
            return "Platinum";
        if (lifetimeValue >= 5000)
            return "Gold";
        if (lifetimeValue >= 1000)
            return "Silver";
        return "None";
    }
}

// 4. 订单服务接口(假设的依赖)
public interface IOrderService
{
    Task<Order> GetOrderAsync(string orderId);
    Task<List<Order>> GetOrdersByCustomerAsync(string customerId);
}

// 5. 控制器示例 - 使用适配后的接口
[Route("api/[controller]")]
[ApiController]
public class CustomersController : ControllerBase
{
    private readonly ICustomerService _customerService;
    private readonly ILogger<CustomersController> _logger;
    
    public CustomersController(ICustomerService customerService, ILogger<CustomersController> logger)
    {
        _customerService = customerService;
        _logger = logger;
    }
    
    [HttpGet("{id}")]
    public async Task<IActionResult> GetCustomer(string id)
    {
        try
        {
            var customer = await _customerService.GetCustomerAsync(id);
            if (customer == null)
            {
                return NotFound();
            }
            
            return Ok(customer);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取客户信息时出错,ID: {CustomerId}", id);
            return StatusCode(500, "获取客户信息时出错");
        }
    }
    
    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateCustomer(string id, [FromBody] Customer customer)
    {
        if (id != customer.Id)
        {
            return BadRequest("客户ID不匹配");
        }
        
        try
        {
            var result = await _customerService.UpdateCustomerAsync(customer);
            if (!result)
            {
                return StatusCode(500, "更新客户信息失败");
            }
            
            return NoContent();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "更新客户信息时出错,ID: {CustomerId}", id);
            return StatusCode(500, "更新客户信息时出错");
        }
    }
    
    [HttpGet("{id}/orders")]
    public async Task<IActionResult> GetCustomerOrders(string id)
    {
        try
        {
            var orders = await _customerService.GetCustomerOrdersAsync(id);
            return Ok(orders);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取客户订单时出错,ID: {CustomerId}", id);
            return StatusCode(500, "获取客户订单时出错");
        }
    }
    
    [HttpGet("{id}/statistics")]
    public async Task<IActionResult> GetCustomerStatistics(string id)
    {
        try
        {
            var statistics = await _customerService.GetCustomerStatisticsAsync(id);
            if (statistics == null)
            {
                return NotFound();
            }
            
            return Ok(statistics);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取客户统计信息时出错,ID: {CustomerId}", id);
            return StatusCode(500, "获取客户统计信息时出错");
        }
    }
    
    [HttpPost("{id}/notes")]
    public async Task<IActionResult> AddCustomerNote(string id, [FromBody] string note)
    {
        try
        {
            var result = await _customerService.AddCustomerNoteAsync(id, note);
            if (!result)
            {
                return StatusCode(500, "添加客户笔记失败");
            }
            
            return NoContent();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "添加客户笔记时出错,ID: {CustomerId}", id);
            return StatusCode(500, "添加客户笔记时出错");
        }
    }
    
    [HttpGet("{id}/notes")]
    public async Task<IActionResult> GetCustomerNotes(string id)
    {
        try
        {
            var notes = await _customerService.GetCustomerNotesAsync(id);
            return Ok(notes);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取客户笔记时出错,ID: {CustomerId}", id);
            return StatusCode(500, "获取客户笔记时出错");
        }
    }
}

// 6. 服务注册和依赖注入配置
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    
    public IConfiguration Configuration { get; }
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        
        // 添加HttpClient
        services.AddHttpClient<ILegacyCrmSystem, LegacyCrmSystem>();
        
        // 注册服务
        services.AddScoped<ILegacyCrmSystem, LegacyCrmSystem>();
        services.AddScoped<IOrderService, OrderService>(); // 假设有实现
        
        // 关键点:注册适配器作为ICustomerService的实现
        services.AddScoped<ICustomerService, LegacyCrmAdapter>();
        
        // 添加日志
        services.AddLogging();
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // 标准ASP.NET Core配置...
    }
}

// 7. 使用示例 - 客户端代码
public class CustomerManager
{
    private readonly ICustomerService _customerService;
    
    public CustomerManager(ICustomerService customerService)
    {
        _customerService = customerService;
    }
    
    public async Task<CustomerViewModel> GetCustomerDetailsAsync(string customerId)
    {
        // 获取客户信息
        var customer = await _customerService.GetCustomerAsync(customerId);
        if (customer == null)
        {
            return null;
        }
        
        // 获取客户订单
        var orders = await _customerService.GetCustomerOrdersAsync(customerId);
        
        // 获取客户统计信息
        var statistics = await _customerService.GetCustomerStatisticsAsync(customerId);
        
        // 获取客户笔记
        var notes = await _customerService.GetCustomerNotesAsync(customerId);
        
        // 构建视图模型
        return new CustomerViewModel
        {
            Id = customer.Id,
            FullName = customer.PersonalInfo.FullName,
            Email = customer.ContactInfo.Email,
            Phone = customer.ContactInfo.PrimaryPhone,
            Address = customer.Address.FormattedAddress,
            CustomerType = customer.Profile.Type.ToString(),
            JoinDate = customer.Profile.RegisteredDate,
            IsActive = customer.Profile.IsActive,
            TotalOrders = orders.Count,
            TotalSpent = statistics?.TotalSpent ?? 0,
            AverageOrderValue = statistics?.AverageOrderValue ?? 0,
            LoyaltyTier = statistics?.LoyaltyTier ?? "None",
            RecentOrders = orders.OrderByDescending(o => o.OrderDate).Take(5).Select(o => new OrderSummary
            {
                Id = o.Id,
                Date = o.OrderDate,
                Amount = o.TotalAmount,
                Status = o.Status
            }).ToList(),
            Notes = notes.Select(n => new NoteViewModel
            {
                Text = n.Text,
                CreatedBy = n.CreatedBy,
                CreatedAt = n.CreatedAt
            }).ToList()
        };
    }
    
    // 更多方法...
}

// 视图模型
public class CustomerViewModel
{
    public string Id { get; set; }
    public string FullName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public string Address { get; set; }
    public string CustomerType { get; set; }
    public DateTime JoinDate { get; set; }
    public bool IsActive { get; set; }
    public int TotalOrders { get; set; }
    public decimal TotalSpent { get; set; }
    public decimal AverageOrderValue { get; set; }
    public string LoyaltyTier { get; set; }
    public List<OrderSummary> RecentOrders { get; set; } = new List<OrderSummary>();
    public List<NoteViewModel> Notes { get; set; } = new List<NoteViewModel>();
}

public class OrderSummary
{
    public string Id { get; set; }
    public DateTime Date { get; set; }
    public decimal Amount { get; set; }
    public string Status { get; set; }
}

public class NoteViewModel
{
    public string Text { get; set; }
    public string CreatedBy { get; set; }
    public DateTime CreatedAt { get; set; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756

# 7. 桥接模式

原理:
桥接模式将抽象部分与其实现部分分离,使它们都可以独立地变化。它通过组合而不是继承来实现,从而提高了系统的灵活性。

思路:

  1. 定义抽象部分的接口
  2. 创建实现部分的接口
  3. 在抽象部分中包含实现部分的引用
  4. 通过组合将抽象和实现连接起来

前辈经验:

  • 当需要避免抽象和实现之间的永久绑定时,使用桥接模式
  • 当抽象和实现都需要通过子类独立扩展时,桥接模式非常有用
  • 桥接模式使用组合替代继承,从而减少了类的数量和复杂性
  • 该模式符合"开闭原则",允许添加新的抽象和实现而不修改现有代码
  • 在多个维度变化的系统中,桥接模式可以防止"类爆炸"问题

业务场景:
开发一个跨平台的图形绘制系统,需要支持不同的形状(圆形、矩形等)在不同的渲染平台(Windows、MacOS、Web等)上绘制。

简单实现:

// 实现部分的接口
public interface IRenderer
{
    void RenderCircle(float radius);
    void RenderRectangle(float width, float height);
}

// 具体实现类 - Windows渲染器
public class WindowsRenderer : IRenderer
{
    public void RenderCircle(float radius)
    {
        Console.WriteLine($"使用Windows API绘制半径为{radius}的圆形");
    }
    
    public void RenderRectangle(float width, float height)
    {
        Console.WriteLine($"使用Windows API绘制{width}x{height}的矩形");
    }
}

// 具体实现类 - Web渲染器
public class WebRenderer : IRenderer
{
    public void RenderCircle(float radius)
    {
        Console.WriteLine($"使用HTML5 Canvas绘制半径为{radius}的圆形");
    }
    
    public void RenderRectangle(float width, float height)
    {
        Console.WriteLine($"使用HTML5 Canvas绘制{width}x{height}的矩形");
    }
}

// 抽象部分的基类
public abstract class Shape
{
    protected IRenderer _renderer;
    
    public Shape(IRenderer renderer)
    {
        _renderer = renderer;
    }
    
    public abstract void Draw();
    public abstract void Resize(float factor);
}

// 扩展抽象部分 - 圆形
public class Circle : Shape
{
    private float _radius;
    
    public Circle(IRenderer renderer, float radius) : base(renderer)
    {
        _radius = radius;
    }
    
    public override void Draw()
    {
        _renderer.RenderCircle(_radius);
    }
    
    public override void Resize(float factor)
    {
        _radius *= factor;
    }
}

// 扩展抽象部分 - 矩形
public class Rectangle : Shape
{
    private float _width;
    private float _height;
    
    public Rectangle(IRenderer renderer, float width, float height) : base(renderer)
    {
        _width = width;
        _height = height;
    }
    
    public override void Draw()
    {
        _renderer.RenderRectangle(_width, _height);
    }
    
    public override void Resize(float factor)
    {
        _width *= factor;
        _height *= factor;
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        // 创建不同的渲染器
        IRenderer windowsRenderer = new WindowsRenderer();
        IRenderer webRenderer = new WebRenderer();
        
        // 创建不同的形状
        Shape circle1 = new Circle(windowsRenderer, 5);
        Shape circle2 = new Circle(webRenderer, 10);
        Shape rectangle1 = new Rectangle(windowsRenderer, 10, 5);
        Shape rectangle2 = new Rectangle(webRenderer, 20, 15);
        
        // 绘制所有形状
        circle1.Draw();     // Windows圆形
        circle2.Draw();     // Web圆形
        rectangle1.Draw();  // Windows矩形
        rectangle2.Draw();  // Web矩形
        
        // 调整大小并重新绘制
        circle1.Resize(2);
        circle1.Draw();     // 放大后的Windows圆形
        
        rectangle2.Resize(0.5f);
        rectangle2.Draw();  // 缩小后的Web矩形
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

复杂实现:

using System;
using System.Collections.Generic;
using System.Drawing;

// 1. 实现部分的接口
public interface IRenderer
{
    void RenderCircle(float x, float y, float radius);
    void RenderRectangle(float x, float y, float width, float height);
    void RenderTriangle(float x1, float y1, float x2, float y2, float x3, float y3);
    void SetColor(Color color);
    void SetFill(bool fill);
    void SetLineWidth(float width);
    void DrawText(float x, float y, string text, string fontName, float fontSize);
    void ClearCanvas();
    void BeginDraw();
    void EndDraw();
}

// 2. 具体实现类 - Windows GDI渲染器
public class GdiRenderer : IRenderer
{
    private Color _currentColor = Color.Black;
    private bool _fill = false;
    private float _lineWidth = 1.0f;
    
    public void RenderCircle(float x, float y, float radius)
    {
        Console.WriteLine($"GDI: 绘制位于({x},{y}),半径为{radius}的圆形");
        Console.WriteLine($"   颜色: {_currentColor}, 填充: {_fill}, 线宽: {_lineWidth}");
    }
    
    public void RenderRectangle(float x, float y, float width, float height)
    {
        Console.WriteLine($"GDI: 绘制位于({x},{y}),尺寸为{width}x{height}的矩形");
        Console.WriteLine($"   颜色: {_currentColor}, 填充: {_fill}, 线宽: {_lineWidth}");
    }
    
    public void RenderTriangle(float x1, float y1, float x2, float y2, float x3, float y3)
    {
        Console.WriteLine($"GDI: 绘制三角形,顶点为({x1},{y1}), ({x2},{y2}), ({x3},{y3})");
        Console.WriteLine($"   颜色: {_currentColor}, 填充: {_fill}, 线宽: {_lineWidth}");
    }
    
    public void SetColor(Color color)
    {
        _currentColor = color;
        Console.WriteLine($"GDI: 设置颜色为{color}");
    }
    
    public void SetFill(bool fill)
    {
        _fill = fill;
        Console.WriteLine($"GDI: 设置填充为{fill}");
    }
    
    public void SetLineWidth(float width)
    {
        _lineWidth = width;
        Console.WriteLine($"GDI: 设置线宽为{width}");
    }
    
    public void DrawText(float x, float y, string text, string fontName, float fontSize)
    {
        Console.WriteLine($"GDI: 在({x},{y})绘制文本\"{text}\",字体为{fontName},大小为{fontSize}");
        Console.WriteLine($"   颜色: {_currentColor}");
    }
    
    public void ClearCanvas()
    {
        Console.WriteLine("GDI: 清空画布");
    }
    
    public void BeginDraw()
    {
        Console.WriteLine("GDI: 开始绘制");
    }
    
    public void EndDraw()
    {
        Console.WriteLine("GDI: 结束绘制");
    }
}

// 3. 具体实现类 - OpenGL渲染器
public class OpenGLRenderer : IRenderer
{
    private Color _currentColor = Color.Black;
    private bool _fill = false;
    private float _lineWidth = 1.0f;
    
    public void RenderCircle(float x, float y, float radius)
    {
        Console.WriteLine($"OpenGL: 绘制位于({x},{y}),半径为{radius}的圆形");
        Console.WriteLine($"   颜色: {_currentColor}, 填充: {_fill}, 线宽: {_lineWidth}");
    }
    
    public void RenderRectangle(float x, float y, float width, float height)
    {
        Console.WriteLine($"OpenGL: 绘制位于({x},{y}),尺寸为{width}x{height}的矩形");
        Console.WriteLine($"   颜色: {_currentColor}, 填充: {_fill}, 线宽: {_lineWidth}");
    }
    
    public void RenderTriangle(float x1, float y1, float x2, float y2, float x3, float y3)
    {
        Console.WriteLine($"OpenGL: 绘制三角形,顶点为({x1},{y1}), ({x2},{y2}), ({x3},{y3})");
        Console.WriteLine($"   颜色: {_currentColor}, 填充: {_fill}, 线宽: {_lineWidth}");
    }
    
    public void SetColor(Color color)
    {
        _currentColor = color;
        Console.WriteLine($"OpenGL: 设置颜色为{color}");
    }
    
    public void SetFill(bool fill)
    {
        _fill = fill;
        Console.WriteLine($"OpenGL: 设置填充为{fill}");
    }
    
    public void SetLineWidth(float width)
    {
        _lineWidth = width;
        Console.WriteLine($"OpenGL: 设置线宽为{width}");
    }
    
    public void DrawText(float x, float y, string text, string fontName, float fontSize)
    {
        Console.WriteLine($"OpenGL: 在({x},{y})绘制文本\"{text}\",字体为{fontName},大小为{fontSize}");
        Console.WriteLine($"   颜色: {_currentColor}");
    }
    
    public void ClearCanvas()
    {
        Console.WriteLine("OpenGL: 清空画布");
    }
    
    public void BeginDraw()
    {
        Console.WriteLine("OpenGL: 开始绘制");
    }
    
    public void EndDraw()
    {
        Console.WriteLine("OpenGL: 结束绘制");
    }
}

// 4. 具体实现类 - HTML5 Canvas渲染器
public class CanvasRenderer : IRenderer
{
    private Color _currentColor = Color.Black;
    private bool _fill = false;
    private float _lineWidth = 1.0f;
    
    public void RenderCircle(float x, float y, float radius)
    {
        string operation = _fill ? "fillCircle" : "strokeCircle";
        Console.WriteLine($"Canvas: context.{operation}({x}, {y}, {radius});");
    }
    
    public void RenderRectangle(float x, float y, float width, float height)
    {
        string operation = _fill ? "fillRect" : "strokeRect";
        Console.WriteLine($"Canvas: context.{operation}({x}, {y}, {width}, {height});");
    }
    
    public void RenderTriangle(float x1, float y1, float x2, float y2, float x3, float y3)
    {
        Console.WriteLine($"Canvas: context.beginPath();");
        Console.WriteLine($"Canvas: context.moveTo({x1}, {y1});");
        Console.WriteLine($"Canvas: context.lineTo({x2}, {y2});");
        Console.WriteLine($"Canvas: context.lineTo({x3}, {y3});");
        Console.WriteLine($"Canvas: context.closePath();");
        
        string operation = _fill ? "fill" : "stroke";
        Console.WriteLine($"Canvas: context.{operation}();");
    }
    
    public void SetColor(Color color)
    {
        string hex = $"#{color.R:X2}{color.G:X2}{color.B:X2}";
        Console.WriteLine($"Canvas: context.fillStyle = \"{hex}\";");
        Console.WriteLine($"Canvas: context.strokeStyle = \"{hex}\";");
    }
    
    public void SetFill(bool fill)
    {
        _fill = fill;
    }
    
    public void SetLineWidth(float width)
    {
        _lineWidth = width;
        Console.WriteLine($"Canvas: context.lineWidth = {width};");
    }
    
    public void DrawText(float x, float y, string text, string fontName, float fontSize)
    {
        Console.WriteLine($"Canvas: context.font = \"{fontSize}px {fontName}\";");
        Console.WriteLine($"Canvas: context.fillText(\"{text}\", {x}, {y});");
    }
    
    public void ClearCanvas()
    {
        Console.WriteLine("Canvas: context.clearRect(0, 0, canvas.width, canvas.height);");
    }
    
    public void BeginDraw()
    {
        Console.WriteLine("Canvas: 开始绘制");
    }
    
    public void EndDraw()
    {
        Console.WriteLine("Canvas: 结束绘制");
    }
}

// 5. 抽象部分的基类
public abstract class Shape
{
    protected IRenderer _renderer;
    protected Color _color;
    protected bool _filled;
    protected float _lineWidth;
    protected float _x;
    protected float _y;
    
    public Shape(IRenderer renderer)
    {
        _renderer = renderer;
        _color = Color.Black;
        _filled = false;
        _lineWidth = 1.0f;
        _x = 0;
        _y = 0;
    }
    
    public void SetPosition(float x, float y)
    {
        _x = x;
        _y = y;
    }
    
    public void SetColor(Color color)
    {
        _color = color;
    }
    
    public void SetFilled(bool filled)
    {
        _filled = filled;
    }
    
    public void SetLineWidth(float width)
    {
        _lineWidth = width;
    }
    
    public abstract void Draw();
    public abstract void Resize(float factor);
    public abstract float GetArea();
    public abstract float GetPerimeter();
}

// 6. 扩展抽象部分 - 圆形
public class Circle : Shape
{
    private float _radius;
    
    public Circle(IRenderer renderer, float radius) : base(renderer)
    {
        _radius = radius;
    }
    
    public override void Draw()
    {
        _renderer.SetColor(_color);
        _renderer.SetFill(_filled);
        _renderer.SetLineWidth(_lineWidth);
        _renderer.RenderCircle(_x, _y, _radius);
    }
    
    public override void Resize(float factor)
    {
        _radius *= factor;
    }
    
    public override float GetArea()
    {
        return (float)Math.PI * _radius * _radius;
    }
    
    public override float GetPerimeter()
    {
        return 2 * (float)Math.PI * _radius;
    }
}

// 7. 扩展抽象部分 - 矩形
public class Rectangle : Shape
{
    private float _width;
    private float _height;
    
    public Rectangle(IRenderer renderer, float width, float height) : base(renderer)
    {
        _width = width;
        _height = height;
    }
    
    public override void Draw()
    {
        _renderer.SetColor(_color);
        _renderer.SetFill(_filled);
        _renderer.SetLineWidth(_lineWidth);
        _renderer.RenderRectangle(_x, _y, _width, _height);
    }
    
    public override void Resize(float factor)
    {
        _width *= factor;
        _height *= factor;
    }
    
    public override float GetArea()
    {
        return _width * _height;
    }
    
    public override float GetPerimeter()
    {
        return 2 * (_width + _height);
    }
}

// 8. 扩展抽象部分 - 三角形
public class Triangle : Shape
{
    private float _x1, _y1, _x2, _y2, _x3, _y3;
    
    public Triangle(IRenderer renderer, float x1, float y1, float x2, float y2, float x3, float y3) : base(renderer)
    {
        _x1 = x1;
        _y1 = y1;
        _x2 = x2;
        _y2 = y2;
        _x3 = x3;
        _y3 = y3;
    }
    
    public override void Draw()
    {
        _renderer.SetColor(_color);
        _renderer.SetFill(_filled);
        _renderer.SetLineWidth(_lineWidth);
        _renderer.RenderTriangle(_x1, _y1, _x2, _y2, _x3, _y3);
    }
    
    public override void Resize(float factor)
    {
        // 相对于原点缩放
        _x1 *= factor;
        _y1 *= factor;
        _x2 *= factor;
        _y2 *= factor;
        _x3 *= factor;
        _y3 *= factor;
    }
    
    public override float GetArea()
    {
        // 使用向量叉积计算三角形面积
        return Math.Abs((_x1 * (_y2 - _y3) + _x2 * (_y3 - _y1) + _x3 * (_y1 - _y2)) / 2);
    }
    
    public override float GetPerimeter()
    {
        // 计算三边长度并求和
        float side1 = (float)Math.Sqrt(Math.Pow(_x2 - _x1, 2) + Math.Pow(_y2 - _y1, 2));
        float side2 = (float)Math.Sqrt(Math.Pow(_x3 - _x2, 2) + Math.Pow(_y3 - _y2, 2));
        float side3 = (float)Math.Sqrt(Math.Pow(_x1 - _x3, 2) + Math.Pow(_y1 - _y3, 2));
        
        return side1 + side2 + side3;
    }
}

// 9. 复合形状 - 使用装饰器模式扩展
public class CompoundShape : Shape
{
    private List<Shape> _shapes = new List<Shape>();
    
    public CompoundShape(IRenderer renderer) : base(renderer)
    {
    }
    
    public void AddShape(Shape shape)
    {
        _shapes.Add(shape);
    }
    
    public void RemoveShape(Shape shape)
    {
        _shapes.Remove(shape);
    }
    
    public override void Draw()
    {
        _renderer.BeginDraw();
        
        foreach (var shape in _shapes)
        {
            shape.Draw();
        }
        
        _renderer.EndDraw();
    }
    
    public override void Resize(float factor)
    {
        foreach (var shape in _shapes)
        {
            shape.Resize(factor);
        }
    }
    
    public override float GetArea()
    {
        float totalArea = 0;
        foreach (var shape in _shapes)
        {
            totalArea += shape.GetArea();
        }
        return totalArea;
    }
    
    public override float GetPerimeter()
    {
        // 复合形状的周长计算可能没有意义,这里简单累加
        float totalPerimeter = 0;
        foreach (var shape in _shapes)
        {
            totalPerimeter += shape.GetPerimeter();
        }
        return totalPerimeter;
    }
}

// 10. 扩展:文本形状
public class TextShape : Shape
{
    private string _text;
    private string _fontName;
    private float _fontSize;
    
    public TextShape(IRenderer renderer, string text, string fontName = "Arial", float fontSize = 12) : base(renderer)
    {
        _text = text;
        _fontName = fontName;
        _fontSize = fontSize;
    }
    
    public void SetText(string text)
    {
        _text = text;
    }
    
    public void SetFont(string fontName, float fontSize)
    {
        _fontName = fontName;
        _fontSize = fontSize;
    }
    
    public override void Draw()
    {
        _renderer.SetColor(_color);
        _renderer.DrawText(_x, _y, _text, _fontName, _fontSize);
    }
    
    public override void Resize(float factor)
    {
        _fontSize *= factor;
    }
    
    public override float GetArea()
    {
        // 文本形状的面积计算可能没有意义
        return 0;
    }
    
    public override float GetPerimeter()
    {
        // 文本形状的周长计算可能没有意义
        return 0;
    }
}

// 11. 画布类 - 使用桥接模式的客户端
public class Canvas
{
    private IRenderer _renderer;
    private List<Shape> _shapes = new List<Shape>();
    
    public Canvas(IRenderer renderer)
    {
        _renderer = renderer;
    }
    
    public void AddShape(Shape shape)
    {
        _shapes.Add(shape);
    }
    
    public void RemoveShape(Shape shape)
    {
        _shapes.Remove(shape);
    }
    
    public void ClearShapes()
    {
        _shapes.Clear();
    }
    
    public void DrawAllShapes()
    {
        _renderer.BeginDraw();
        _renderer.ClearCanvas();
        
        foreach (var shape in _shapes)
        {
            shape.Draw();
        }
        
        _renderer.EndDraw();
    }
    
    public void ResizeAllShapes(float factor)
    {
        foreach (var shape in _shapes)
        {
            shape.Resize(factor);
        }
    }
    
    public float CalculateTotalArea()
    {
        float totalArea = 0;
        foreach (var shape in _shapes)
        {
            totalArea += shape.GetArea();
        }
        return totalArea;
    }
}

// 12. 工厂类 - 用于创建特定平台的渲染器
public class RendererFactory
{
    public static IRenderer CreateRenderer(RenderingPlatform platform)
    {
        switch (platform)
        {
            case RenderingPlatform.GDI:
                return new GdiRenderer();
            case RenderingPlatform.OpenGL:
                return new OpenGLRenderer();
            case RenderingPlatform.Canvas:
                return new CanvasRenderer();
            default:
                throw new ArgumentException($"不支持的渲染平台: {platform}");
        }
    }
}

public enum RenderingPlatform
{
    GDI,
    OpenGL,
    Canvas
}

// 13. 客户端代码
public class Client
{
    public static void Main()
    {
        // 创建不同的渲染器
        IRenderer gdiRenderer = RendererFactory.CreateRenderer(RenderingPlatform.GDI);
        IRenderer openGLRenderer = RendererFactory.CreateRenderer(RenderingPlatform.OpenGL);
        IRenderer canvasRenderer = RendererFactory.CreateRenderer(RenderingPlatform.Canvas);
        
        // 创建画布
        Canvas gdiCanvas = new Canvas(gdiRenderer);
        Canvas openGLCanvas = new Canvas(openGLRenderer);
        Canvas webCanvas = new Canvas(canvasRenderer);
        
        // 创建并配置形状
        Circle circle = new Circle(gdiRenderer, 5);
        circle.SetPosition(10, 10);
        circle.SetColor(Color.Red);
        circle.SetFilled(true);
        
        Rectangle rectangle = new Rectangle(gdiRenderer, 20, 10);
        rectangle.SetPosition(30, 30);
        rectangle.SetColor(Color.Blue);
        rectangle.SetLineWidth(2);
        
        Triangle triangle = new Triangle(gdiRenderer, 0, 0, 10, 20, 20, 0);
        triangle.SetColor(Color.Green);
        
        TextShape text = new TextShape(gdiRenderer, "Hello, Bridge Pattern!");
        text.SetPosition(50, 50);
        text.SetColor(Color.Black);
        
        // 添加形状到GDI画布
        gdiCanvas.AddShape(circle);
        gdiCanvas.AddShape(rectangle);
        gdiCanvas.AddShape(triangle);
        gdiCanvas.AddShape(text);
        
        // 绘制GDI画布上的所有形状
        Console.WriteLine("===== GDI 画布 =====");
        gdiCanvas.DrawAllShapes();
        
        // 创建复合形状
        CompoundShape compoundShape = new CompoundShape(openGLRenderer);
        compoundShape.AddShape(new Circle(openGLRenderer, 15));
        compoundShape.AddShape(new Rectangle(openGLRenderer, 40, 30));
        
        // 添加形状到OpenGL画布
        openGLCanvas.AddShape(compoundShape);
        openGLCanvas.AddShape(new Triangle(openGLRenderer, 100, 100, 150, 200, 200, 100));
        
        // 绘制OpenGL画布上的所有形状
        Console.WriteLine("\n===== OpenGL 画布 =====");
        openGLCanvas.DrawAllShapes();
        
        // 创建并添加形状到Web画布
        webCanvas.AddShape(new Circle(canvasRenderer, 25));
        webCanvas.AddShape(new Rectangle(canvasRenderer, 60, 40));
        webCanvas.AddShape(new TextShape(canvasRenderer, "HTML5 Canvas"));
        
        // 绘制Web画布上的所有形状
        Console.WriteLine("\n===== HTML5 Canvas 画布 =====");
        webCanvas.DrawAllShapes();
        
        // 缩放形状并重新绘制
        Console.WriteLine("\n===== 缩放后的 GDI 画布 =====");
        gdiCanvas.ResizeAllShapes(1.5f);
        gdiCanvas.DrawAllShapes();
        
        // 计算总面积
        float totalArea = gdiCanvas.CalculateTotalArea();
        Console.WriteLine($"\n所有形状的总面积: {totalArea}");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658

业务场景结合:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;

// 1. 消息发送系统 - 使用桥接模式分离消息类型和发送方式

// 实现部分 - 消息发送接口
public interface IMessageSender
{
    Task SendMessageAsync(string recipient, string subject, string body, IDictionary<string, string> metadata = null);
    bool IsAvailable();
    IDictionary<string, string> GetCapabilities();
}

// 具体实现 - 电子邮件发送器
public class EmailSender : IMessageSender
{
    private readonly ILogger<EmailSender> _logger;
    private readonly string _smtpServer;
    private readonly int _smtpPort;
    private readonly string _username;
    private readonly string _password;
    private readonly string _fromAddress;
    
    public EmailSender(
        string smtpServer, 
        int smtpPort, 
        string username, 
        string password, 
        string fromAddress,
        ILogger<EmailSender> logger)
    {
        _smtpServer = smtpServer;
        _smtpPort = smtpPort;
        _username = username;
        _password = password;
        _fromAddress = fromAddress;
        _logger = logger;
    }
    
    public async Task SendMessageAsync(string recipient, string subject, string body, IDictionary<string, string> metadata = null)
    {
        try
        {
            _logger.LogInformation("通过邮件发送消息到 {Recipient}, 主题: {Subject}", recipient, subject);
            
            // 在实际应用中,这里会调用SMTP客户端发送邮件
            // SmtpClient client = new SmtpClient(_smtpServer, _smtpPort);
            // ...
            
            // 模拟邮件发送
            await Task.Delay(500);
            
            _logger.LogInformation("邮件发送成功: {Recipient}", recipient);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送邮件时出错: {ErrorMessage}", ex.Message);
            throw;
        }
    }
    
    public bool IsAvailable()
    {
        // 检查SMTP服务器是否可用
        // 简化示例,始终返回true
        return true;
    }
    
    public IDictionary<string, string> GetCapabilities()
    {
        return new Dictionary<string, string>
        {
            { "SupportsHtml", "true" },
            { "SupportsAttachments", "true" },
            { "MaxAttachmentSize", "10485760" }, // 10MB
            { "DeliveryTracking", "basic" }
        };
    }
}

// 具体实现 - SMS短信发送器
public class SmsSender : IMessageSender
{
    private readonly ILogger<SmsSender> _logger;
    private readonly string _apiKey;
    private readonly string _apiSecret;
    private readonly string _fromNumber;
    
    public SmsSender(
        string apiKey,
        string apiSecret,
        string fromNumber,
        ILogger<SmsSender> logger)
    {
        _apiKey = apiKey;
        _apiSecret = apiSecret;
        _fromNumber = fromNumber;
        _logger = logger;
    }
    
    public async Task SendMessageAsync(string recipient, string subject, string body, IDictionary<string, string> metadata = null)
    {
        try
        {
            // 短信不使用主题,我们把body内容直接发送
            _logger.LogInformation("通过短信发送消息到 {Recipient}", recipient);
            
            // 在实际应用中,这里会调用SMS服务提供商的API
            // HttpClient client = new HttpClient();
            // ...
            
            // 检查消息长度
            if (body.Length > 160)
            {
                _logger.LogWarning("短信内容超过160个字符,可能会分多条发送");
            }
            
            // 模拟短信发送
            await Task.Delay(300);
            
            _logger.LogInformation("短信发送成功: {Recipient}", recipient);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送短信时出错: {ErrorMessage}", ex.Message);
            throw;
        }
    }
    
    public bool IsAvailable()
    {
        // 检查短信服务是否可用
        // 简化示例,始终返回true
        return true;
    }
    
    public IDictionary<string, string> GetCapabilities()
    {
        return new Dictionary<string, string>
        {
            { "SupportsHtml", "false" },
            { "SupportsAttachments", "false" },
            { "MaxMessageLength", "160" },
            { "DeliveryTracking", "advanced" }
        };
    }
}

// 具体实现 - 消息推送发送器
public class PushNotificationSender : IMessageSender
{
    private readonly ILogger<PushNotificationSender> _logger;
    private readonly string _appId;
    private readonly string _apiKey;
    
    public PushNotificationSender(
        string appId,
        string apiKey,
        ILogger<PushNotificationSender> logger)
    {
        _appId = appId;
        _apiKey = apiKey;
        _logger = logger;
    }
    
    public async Task SendMessageAsync(string recipient, string subject, string body, IDictionary<string, string> metadata = null)
    {
        try
        {
            _logger.LogInformation("通过推送通知发送消息到 {Recipient}", recipient);
            
            // 在实际应用中,这里会调用推送服务提供商的API
            // var pushClient = new PushServiceClient(_appId, _apiKey);
            // ...
            
            // 获取额外数据
            string category = metadata != null && metadata.ContainsKey("category") 
                ? metadata["category"] 
                : "general";
                
            // 模拟推送通知发送
            await Task.Delay(200);
            
            _logger.LogInformation("推送通知发送成功: {Recipient}, 类别: {Category}", recipient, category);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送推送通知时出错: {ErrorMessage}", ex.Message);
            throw;
        }
    }
    
    public bool IsAvailable()
    {
        // 检查推送服务是否可用
        // 简化示例,始终返回true
        return true;
    }
    
    public IDictionary<string, string> GetCapabilities()
    {
        return new Dictionary<string, string>
        {
            { "SupportsHtml", "false" },
            { "SupportsAttachments", "false" },
            { "MaxTitleLength", "50" },
            { "MaxBodyLength", "200" },
            { "SupportsActions", "true" },
            { "SupportsSilent", "true" }
        };
    }
}

// 抽象部分 - 消息基类
public abstract class Message
{
    protected readonly IMessageSender _sender;
    protected readonly ILogger _logger;
    
    public string Recipient { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }
    public DateTime ScheduledTime { get; set; }
    public Dictionary<string, string> Metadata { get; } = new Dictionary<string, string>();
    
    protected Message(IMessageSender sender, ILogger logger)
    {
        _sender = sender;
        _logger = logger;
        ScheduledTime = DateTime.Now; // 默认立即发送
    }
    
    public virtual async Task SendAsync()
    {
        if (!_sender.IsAvailable())
        {
            _logger.LogWarning("消息发送通道不可用,无法发送消息到 {Recipient}", Recipient);
            throw new InvalidOperationException("消息发送通道不可用");
        }
        
        if (ScheduledTime > DateTime.Now)
        {
            var delay = ScheduledTime - DateTime.Now;
            _logger.LogInformation("消息计划在 {ScheduledTime} 发送,延迟 {DelaySeconds} 秒", 
                ScheduledTime, delay.TotalSeconds);
            await Task.Delay(delay);
        }
        
        await _sender.SendMessageAsync(Recipient, Subject, Body, Metadata);
    }
    
    public void ScheduleForLater(TimeSpan delay)
    {
        ScheduledTime = DateTime.Now.Add(delay);
    }
    
    public abstract bool Validate();
    public abstract string GetMessageType();
}

// 具体抽象实现 - 普通文本消息
public class TextMessage : Message
{
    public TextMessage(IMessageSender sender, ILogger<TextMessage> logger)
        : base(sender, logger)
    {
    }
    
    public override bool Validate()
    {
        if (string.IsNullOrWhiteSpace(Recipient))
        {
            _logger.LogWarning("消息验证失败: 收件人为空");
            return false;
        }
        
        if (string.IsNullOrWhiteSpace(Body))
        {
            _logger.LogWarning("消息验证失败: 正文为空");
            return false;
        }
        
        return true;
    }
    
    public override string GetMessageType()
    {
        return "文本消息";
    }
}

// 具体抽象实现 - HTML邮件消息
public class HtmlMessage : Message
{
    public string HtmlContent { get; set; }
    public List<string> Attachments { get; } = new List<string>();
    
    public HtmlMessage(IMessageSender sender, ILogger<HtmlMessage> logger)
        : base(sender, logger)
    {
    }
    
    public void AddAttachment(string filePath)
    {
        if (!File.Exists(filePath))
        {
            _logger.LogWarning("附件文件不存在: {FilePath}", filePath);
            return;
        }
        
        Attachments.Add(filePath);
        _logger.LogInformation("添加附件: {FilePath}", filePath);
    }
    
    public override async Task SendAsync()
    {
        var senderCapabilities = _sender.GetCapabilities();
        
        // 检查发送者是否支持HTML
        if (!bool.TryParse(senderCapabilities.GetValueOrDefault("SupportsHtml", "false"), out bool supportsHtml) || !supportsHtml)
        {
            _logger.LogWarning("发送者不支持HTML内容,将发送纯文本版本");
            // 降级为纯文本
            Body = ConvertHtmlToPlainText(HtmlContent);
        }
        else
        {
            Body = HtmlContent;
        }
        
        // 检查发送者是否支持附件
        if (Attachments.Count > 0)
        {
            if (!bool.TryParse(senderCapabilities.GetValueOrDefault("SupportsAttachments", "false"), out bool supportsAttachments) || !supportsAttachments)
            {
                _logger.LogWarning("发送者不支持附件,将忽略所有附件");
            }
            else
            {
                // 在实际应用中,这里会处理附件
                // 例如,对于EmailSender,我们会将附件添加到邮件中
                _logger.LogInformation("准备发送附件,数量: {AttachmentCount}", Attachments.Count);
                
                // 添加附件信息到元数据
                Metadata["AttachmentCount"] = Attachments.Count.ToString();
            }
        }
        
        await base.SendAsync();
    }
    
    public override bool Validate()
    {
        if (string.IsNullOrWhiteSpace(Recipient))
        {
            _logger.LogWarning("消息验证失败: 收件人为空");
            return false;
        }
        
        if (string.IsNullOrWhiteSpace(Subject))
        {
            _logger.LogWarning("消息验证失败: 主题为空");
            return false;
        }
        
        if (string.IsNullOrWhiteSpace(HtmlContent))
        {
            _logger.LogWarning("消息验证失败: HTML内容为空");
            return false;
        }
        
        return true;
    }
    
    public override string GetMessageType()
    {
        return "HTML消息";
    }
    
    private string ConvertHtmlToPlainText(string html)
    {
        // 简化的HTML到纯文本转换
        // 在实际应用中,会使用更复杂的HTML解析库
        string text = html;
        text = text.Replace("<br>", "\n");
        text = text.Replace("<br/>", "\n");
        text = text.Replace("<br />", "\n");
        text = text.Replace("<p>", "\n");
        text = text.Replace("</p>", "\n");
        text = text.Replace("&nbsp;", " ");
        
        // 移除其他HTML标签
        bool inTag = false;
        StringBuilder result = new StringBuilder();
        
        foreach (char c in text)
        {
            if (c == '<')
            {
                inTag = true;
                continue;
            }
            
            if (c == '>')
            {
                inTag = false;
                continue;
            }
            
            if (!inTag)
            {
                result.Append(c);
            }
        }
        
        return result.ToString().Trim();
    }
}

// 具体抽象实现 - 通知消息
public class NotificationMessage : Message
{
    public string Category { get; set; } = "general";
    public string ActionUrl { get; set; }
    public bool IsSilent { get; set; }
    
    public NotificationMessage(IMessageSender sender, ILogger<NotificationMessage> logger)
        : base(sender, logger)
    {
    }
    
    public override async Task SendAsync()
    {
        // 添加通知特定的元数据
        Metadata["category"] = Category;
        
        if (!string.IsNullOrEmpty(ActionUrl))
        {
            Metadata["action_url"] = ActionUrl;
        }
        
        Metadata["silent"] = IsSilent.ToString().ToLower();
        
        await base.SendAsync();
    }
    
    public override bool Validate()
    {
        if (string.IsNullOrWhiteSpace(Recipient))
        {
            _logger.LogWarning("消息验证失败: 收件人为空");
            return false;
        }
        
        if (string.IsNullOrWhiteSpace(Subject))
        {
            _logger.LogWarning("消息验证失败: 主题为空");
            return false;
        }
        
        if (string.IsNullOrWhiteSpace(Body))
        {
            _logger.LogWarning("消息验证失败: 正文为空");
            return false;
        }
        
        if (!string.IsNullOrEmpty(ActionUrl) && !Uri.IsWellFormedUriString(ActionUrl, UriKind.Absolute))
        {
            _logger.LogWarning("消息验证失败: 操作URL格式无效: {ActionUrl}", ActionUrl);
            return false;
        }
        
        return true;
    }
    
    public override string GetMessageType()
    {
        return "通知消息";
    }
}

// 消息工厂类
public class MessageFactory
{
    private readonly IServiceProvider _serviceProvider;
    
    public MessageFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
    
    public TextMessage CreateTextMessage(string senderType)
    {
        var sender = GetSender(senderType);
        var logger = _serviceProvider.GetRequiredService<ILogger<TextMessage>>();
        return new TextMessage(sender, logger);
    }
    
    public HtmlMessage CreateHtmlMessage(string senderType)
    {
        var sender = GetSender(senderType);
        var logger = _serviceProvider.GetRequiredService<ILogger<HtmlMessage>>();
        return new HtmlMessage(sender, logger);
    }
    
    public NotificationMessage CreateNotificationMessage(string senderType)
    {
        var sender = GetSender(senderType);
        var logger = _serviceProvider.GetRequiredService<ILogger<NotificationMessage>>();
        return new NotificationMessage(sender, logger);
    }
    
    private IMessageSender GetSender(string senderType)
    {
        return senderType.ToLower() switch
        {
            "email" => _serviceProvider.GetRequiredService<EmailSender>(),
            "sms" => _serviceProvider.GetRequiredService<SmsSender>(),
            "push" => _serviceProvider.GetRequiredService<PushNotificationSender>(),
            _ => throw new ArgumentException($"不支持的发送者类型: {senderType}")
        };
    }
}

// 消息服务 - 封装消息发送逻辑
public class MessagingService
{
    private readonly MessageFactory _messageFactory;
    private readonly ILogger<MessagingService> _logger;
    
    public MessagingService(MessageFactory messageFactory, ILogger<MessagingService> logger)
    {
        _messageFactory = messageFactory;
        _logger = logger;
    }
    
    public async Task SendWelcomeEmailAsync(string email, string name)
    {
        try
        {
            var message = _messageFactory.CreateHtmlMessage("email");
            message.Recipient = email;
            message.Subject = "欢迎加入我们的平台!";
            
            string htmlContent = $@"
            <html>
            <body>
                <h1>欢迎,{name}!</h1>

                <p>感谢您注册我们的平台。</p>

                <p>我们很高兴您能加入我们的社区!</p>

                <p>如需帮助,请随时联系我们的<a href='mailto:support@example.com'>支持团队</a>。</p>

            </body>

            </html>";
            
            message.HtmlContent = htmlContent;
            
            if (message.Validate())
            {
                await message.SendAsync();
                _logger.LogInformation("已发送欢迎邮件到 {Email}", email);
            }
            else
            {
                _logger.LogWarning("欢迎邮件验证失败,未能发送到 {Email}", email);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送欢迎邮件时出错: {ErrorMessage}", ex.Message);
            throw;
        }
    }
    
    public async Task SendPasswordResetSmsAsync(string phoneNumber, string resetCode)
    {
        try
        {
            var message = _messageFactory.CreateTextMessage("sms");
            message.Recipient = phoneNumber;
            message.Body = $"您的密码重置码是: {resetCode}。该验证码将在10分钟内有效。";
            
            if (message.Validate())
            {
                await message.SendAsync();
                _logger.LogInformation("已发送密码重置短信到 {PhoneNumber}", phoneNumber);
            }
            else
            {
                _logger.LogWarning("密码重置短信验证失败,未能发送到 {PhoneNumber}", phoneNumber);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送密码重置短信时出错: {ErrorMessage}", ex.Message);
            throw;
        }
    }
    
    public async Task SendNewOrderNotificationAsync(string userId, string orderNumber, decimal amount)
    {
        try
        {
            var message = _messageFactory.CreateNotificationMessage("push");
            message.Recipient = userId;
            message.Subject = "新订单确认";
            message.Body = $"您的订单 #{orderNumber} 已确认,金额为 ${amount:F2}。";
            message.Category = "order";
            message.ActionUrl = $"https://example.com/orders/{orderNumber}";
            
            if (message.Validate())
            {
                await message.SendAsync();
                _logger.LogInformation("已发送订单通知到用户 {UserId},订单号: {OrderNumber}", userId, orderNumber);
            }
            else
            {
                _logger.LogWarning("订单通知验证失败,未能发送到用户 {UserId}", userId);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送订单通知时出错: {ErrorMessage}", ex.Message);
            throw;
        }
    }
    
    public async Task SendPromotionEmailAsync(string email, string name, string promotionCode, TimeSpan delay)
    {
        try
        {
            var message = _messageFactory.CreateHtmlMessage("email");
            message.Recipient = email;
            message.Subject = "特别优惠,仅限您!";
            
            string htmlContent = $@"
            <html>
            <body>
                <h1>亲爱的 {name},我们有一个特别优惠给您!</h1>

                <p>使用以下优惠码可获得所有商品15%的折扣:</p>

                <div style='background-color: #f0f0f0; padding: 10px; text-align: center; font-size: 20px;'>
                    <strong>{promotionCode}</strong>

                </div>

                <p>此优惠将在7天内有效。</p>

            </body>

            </html>";
            
            message.HtmlContent = htmlContent;
            
            // 设置延迟发送
            message.ScheduleForLater(delay);
            
            if (message.Validate())
            {
                await message.SendAsync();
                _logger.LogInformation("已计划发送促销邮件到 {Email},将在 {ScheduledTime} 发送", 
                    email, message.ScheduledTime);
            }
            else
            {
                _logger.LogWarning("促销邮件验证失败,未能计划发送到 {Email}", email);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "计划发送促销邮件时出错: {ErrorMessage}", ex.Message);
            throw;
        }
    }
}

// 依赖注入配置
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 配置日志
        services.AddLogging();
        
        // 注册消息发送器
        services.AddSingleton<EmailSender>(provider => 
            new EmailSender(
                "smtp.example.com", 
                587, 
                "username", 
                "password", 
                "noreply@example.com",
                provider.GetRequiredService<ILogger<EmailSender>>()));
                
        services.AddSingleton<SmsSender>(provider => 
            new SmsSender(
                "sms-api-key", 
                "sms-api-secret", 
                "+15551234567",
                provider.GetRequiredService<ILogger<SmsSender>>()));
                
        services.AddSingleton<PushNotificationSender>(provider => 
            new PushNotificationSender(
                "push-app-id", 
                "push-api-key",
                provider.GetRequiredService<ILogger<PushNotificationSender>>()));
        
        // 注册消息工厂
        services.AddSingleton<MessageFactory>();
        
        // 注册消息服务
        services.AddScoped<MessagingService>();
    }
}

// 客户端代码示例
public class Program
{
    public static async Task Main(string[] args)
    {
        // 创建服务集合和提供者
        var services = new ServiceCollection();
        
        // 配置服务
        services.AddLogging(builder =>
        {
            builder.AddConsole();
            builder.SetMinimumLevel(LogLevel.Debug);
        });
        
        // 应用Startup配置
        var startup = new Startup();
        startup.ConfigureServices(services);
        
        var serviceProvider = services.BuildServiceProvider();
        
        // 获取消息服务
        var messagingService = serviceProvider.GetRequiredService<MessagingService>();
        
        // 发送各种类型的消息
        try
        {
            // 发送欢迎邮件
            await messagingService.SendWelcomeEmailAsync("john.doe@example.com", "John Doe");
            
            // 发送密码重置短信
            await messagingService.SendPasswordResetSmsAsync("+15551234567", "123456");
            
            // 发送订单通知
            await messagingService.SendNewOrderNotificationAsync("user-123", "ORD-9876", 125.99m);
            
            // 计划发送促销邮件(延迟5秒,便于演示)
            await messagingService.SendPromotionEmailAsync(
                "jane.smith@example.com",
                "Jane Smith",
                "SUMMER25",
                TimeSpan.FromSeconds(5));
                
            // 等待足够长时间,确保延迟消息能够发送
            await Task.Delay(10000);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发送消息时出错: {ex.Message}");
        }
        
        Console.WriteLine("所有消息已处理完毕。按任意键退出...");
        Console.ReadKey();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780

# 8. 组合模式

原理:
组合模式允许客户端统一处理单个对象和对象组合(如树形结构)。它使客户端能够忽略单个对象和组合对象之间的差异,对它们进行一致的处理。

思路:

  1. 定义一个抽象组件类,为组合中的对象声明接口
  2. 创建叶子类(单个对象)实现组件接口
  3. 创建组合类(包含其他组件的对象)实现组件接口
  4. 在组合类中维护子组件集合,实现组件接口方法

前辈经验:

  • 当需要表示对象的"部分-整体"层次结构时,使用组合模式
  • 当希望客户端能够统一处理单个对象和组合对象时,组合模式非常有用
  • 组合模式符合"开闭原则",新增组件类型不需要修改现有代码
  • 在设计组合模式时,考虑是否需要提供父组件引用以支持向上遍历
  • 注意组合模式可能会使系统设计变得过于通用,导致运行时类型检查的需要

业务场景:
文件系统目录结构,需要统一处理文件和目录,而目录可以包含其他文件和目录。

简单实现:

// 抽象组件
public abstract class FileSystemItem
{
    public string Name { get; set; }
    
    public FileSystemItem(string name)
    {
        Name = name;
    }
    
    public abstract long GetSize();
    public abstract void Print(string indent = "");
}

// 叶子组件 - 文件
public class File : FileSystemItem
{
    public long Size { get; set; }
    
    public File(string name, long size) : base(name)
    {
        Size = size;
    }
    
    public override long GetSize()
    {
        return Size;
    }
    
    public override void Print(string indent = "")
    {
        Console.WriteLine($"{indent}文件: {Name}, 大小: {Size} 字节");
    }
}

// 组合组件 - 目录
public class Directory : FileSystemItem
{
    private List<FileSystemItem> _children = new List<FileSystemItem>();
    
    public Directory(string name) : base(name)
    {
    }
    
    // 添加子项
    public void Add(FileSystemItem item)
    {
        _children.Add(item);
    }
    
    // 移除子项
    public void Remove(FileSystemItem item)
    {
        _children.Remove(item);
    }
    
    public override long GetSize()
    {
        long totalSize = 0;
        foreach (var item in _children)
        {
            totalSize += item.GetSize();
        }
        return totalSize;
    }
    
    public override void Print(string indent = "")
    {
        Console.WriteLine($"{indent}目录: {Name}, 大小: {GetSize()} 字节");
        
        // 打印所有子项
        foreach (var item in _children)
        {
            item.Print(indent + "  ");
        }
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        // 创建文件系统结构
        var root = new Directory("根目录");
        
        var documents = new Directory("文档");
        var pictures = new Directory("图片");
        
        root.Add(documents);
        root.Add(pictures);
        
        var file1 = new File("document1.txt", 1000);
        var file2 = new File("document2.txt", 2000);
        documents.Add(file1);
        documents.Add(file2);
        
        var file3 = new File("image1.jpg", 5000);
        var file4 = new File("image2.jpg", 6000);
        pictures.Add(file3);
        pictures.Add(file4);
        
        // 在文档目录下创建子目录
        var subDir = new Directory("子目录");
        documents.Add(subDir);
        
        var file5 = new File("document3.txt", 3000);
        subDir.Add(file5);
        
        // 打印整个文件系统
        root.Print();
        
        // 获取总大小
        Console.WriteLine($"\n总大小: {root.GetSize()} 字节");
        
        // 获取单个目录大小
        Console.WriteLine($"文档目录大小: {documents.GetSize()} 字节");
        Console.WriteLine($"图片目录大小: {pictures.GetSize()} 字节");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

复杂实现:

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

// 抽象组件 - 文件系统项基类
public abstract class FileSystemItem
{
    public string Name { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime ModifiedAt { get; set; }
    public FileSystemItem Parent { get; private set; }
    
    protected FileSystemItem(string name)
    {
        Name = name;
        CreatedAt = DateTime.Now;
        ModifiedAt = DateTime.Now;
    }
    
    // 设置父项
    public void SetParent(FileSystemItem parent)
    {
        Parent = parent;
    }
    
    // 获取完整路径
    public string GetPath()
    {
        if (Parent == null)
        {
            return Name;
        }
        
        return Parent.GetPath() + "/" + Name;
    }
    
    // 获取所有祖先
    public List<FileSystemItem> GetAncestors()
    {
        var ancestors = new List<FileSystemItem>();
        var current = Parent;
        
        while (current != null)
        {
            ancestors.Add(current);
            current = current.Parent;
        }
        
        return ancestors;
    }
    
    public abstract long GetSize();
    public abstract void Print(string indent = "");
    public abstract FileSystemItem Clone();
    public abstract FileSystemItem Find(string name);
    public abstract int GetItemCount();
    public abstract FileSystemItem GetRoot();
}

// 叶子组件 - 文件
public class File : FileSystemItem
{
    public long Size { get; set; }
    public string Extension => System.IO.Path.GetExtension(Name);
    public string ContentType { get; set; }
    
    public File(string name, long size, string contentType = null) : base(name)
    {
        Size = size;
        ContentType = contentType ?? DetermineContentType(name);
    }
    
    public override long GetSize()
    {
        return Size;
    }
    
    public override void Print(string indent = "")
    {
        Console.WriteLine($"{indent}文件: {Name}, 大小: {FormatSize(Size)}, 类型: {ContentType}");
    }
    
    public override FileSystemItem Clone()
    {
        var clone = new File(Name, Size, ContentType)
        {
            CreatedAt = this.CreatedAt,
            ModifiedAt = DateTime.Now
        };
        return clone;
    }
    
    public override FileSystemItem Find(string name)
    {
        return Name.Equals(name, StringComparison.OrdinalIgnoreCase) ? this : null;
    }
    
    public override int GetItemCount()
    {
        return 1; // 文件只算一个项目
    }
    
    public override FileSystemItem GetRoot()
    {
        var current = this;
        while (current.Parent != null)
        {
            current = current.Parent;
        }
        return current;
    }
    
    private string DetermineContentType(string filename)
    {
        string ext = System.IO.Path.GetExtension(filename).ToLower();
        
        return ext switch
        {
            ".txt" => "text/plain",
            ".html" => "text/html",
            ".css" => "text/css",
            ".js" => "application/javascript",
            ".json" => "application/json",
            ".xml" => "application/xml",
            ".pdf" => "application/pdf",
            ".jpg" or ".jpeg" => "image/jpeg",
            ".png" => "image/png",
            ".gif" => "image/gif",
            ".svg" => "image/svg+xml",
            ".mp3" => "audio/mpeg",
            ".mp4" => "video/mp4",
            ".zip" => "application/zip",
            ".doc" or ".docx" => "application/msword",
            ".xls" or ".xlsx" => "application/vnd.ms-excel",
            ".ppt" or ".pptx" => "application/vnd.ms-powerpoint",
            _ => "application/octet-stream"
        };
    }
    
    private string FormatSize(long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB", "TB" };
        int order = 0;
        double size = bytes;
        
        while (size >= 1024 && order < sizes.Length - 1)
        {
            order++;
            size /= 1024;
        }
        
        return $"{size:0.##} {sizes[order]}";
    }
}

// 组合组件 - 目录
public class Directory : FileSystemItem
{
    private List<FileSystemItem> _children = new List<FileSystemItem>();
    
    public Directory(string name) : base(name)
    {
    }
    
    // 添加子项
    public void Add(FileSystemItem item)
    {
        _children.Add(item);
        item.SetParent(this);
        ModifiedAt = DateTime.Now;
    }
    
    // 移除子项
    public void Remove(FileSystemItem item)
    {
        _children.Remove(item);
        ModifiedAt = DateTime.Now;
    }
    
    // 获取所有子项
    public List<FileSystemItem> GetChildren()
    {
        return new List<FileSystemItem>(_children);
    }
    
    // 获取文件列表
    public List<File> GetFiles()
    {
        return _children.OfType<File>().ToList();
    }
    
    // 获取子目录列表
    public List<Directory> GetDirectories()
    {
        return _children.OfType<Directory>().ToList();
    }
    
    // 清空目录
    public void Clear()
    {
        _children.Clear();
        ModifiedAt = DateTime.Now;
    }
    
    // 移动子项到新位置
    public void MoveItem(FileSystemItem item, int newIndex)
    {
        if (_children.Contains(item) && newIndex >= 0 && newIndex < _children.Count)
        {
            _children.Remove(item);
            _children.Insert(newIndex, item);
            ModifiedAt = DateTime.Now;
        }
    }
    
    public override long GetSize()
    {
        return _children.Sum(item => item.GetSize());
    }
    
    public override void Print(string indent = "")
    {
        Console.WriteLine($"{indent}目录: {Name}, 项目数: {GetItemCount()}, 大小: {FormatSize(GetSize())}");
        
        foreach (var item in _children)
        {
            item.Print(indent + "  ");
        }
    }
    
    public override FileSystemItem Clone()
    {
        var clone = new Directory(Name)
        {
            CreatedAt = this.CreatedAt,
            ModifiedAt = DateTime.Now
        };
        
        foreach (var child in _children)
        {
            var childClone = child.Clone();
            clone.Add(childClone);
        }
        
        return clone;
    }
    
    // 深度搜索查找项目
    public override FileSystemItem Find(string name)
    {
        // 首先检查当前目录名称
        if (Name.Equals(name, StringComparison.OrdinalIgnoreCase))
        {
            return this;
        }
        
        // 然后搜索子项
        foreach (var child in _children)
        {
            var found = child.Find(name);
            if (found != null)
            {
                return found;
            }
        }
        
        return null;
    }
    
    // 按扩展名获取文件
    public List<File> FindFilesByExtension(string extension)
    {
        var result = new List<File>();
        
        foreach (var child in _children)
        {
            if (child is File file && file.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase))
            {
                result.Add(file);
            }
            else if (child is Directory dir)
            {
                result.AddRange(dir.FindFilesByExtension(extension));
            }
        }
        
        return result;
    }
    
    // 按内容类型获取文件
    public List<File> FindFilesByContentType(string contentType)
    {
        var result = new List<File>();
        
        foreach (var child in _children)
        {
            if (child is File file && file.ContentType.StartsWith(contentType, StringComparison.OrdinalIgnoreCase))
            {
                result.Add(file);
            }
            else if (child is Directory dir)
            {
                result.AddRange(dir.FindFilesByContentType(contentType));
            }
        }
        
        return result;
    }
    
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
// 递归获取所有文件(续)
public List<File> GetAllFiles()
{
    var result = new List<File>();

    foreach (var child in _children)
    {
        if (child is File file)
        {
            result.Add(file);
        }
        else if (child is Directory dir)
        {
            result.AddRange(dir.GetAllFiles());
        }
    }

    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

​

public override int GetItemCount()
{
    // 包括所有子项的数量,包括子目录和它们的子项
    int count = 0;
    foreach (var child in _children)
    {
        count += child.GetItemCount();
    }

    return count;
}

public override FileSystemItem GetRoot()
{
    var current = this;
    while (current.Parent != null)
    {
        current = current.Parent;
    }
    return current;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private string FormatSize(long bytes)
{
    string[] sizes = { "B", "KB", "MB", "GB", "TB" };
    int order = 0;
    double size = bytes;
    while (size >= 1024 && order < sizes.Length - 1)
    {
        order++;
        size /= 1024;
    }

    return $"{size:0.##} {sizes[order]}";

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 访问者接口 - 用于在不修改组件类的情况下添加新操作
public interface IFileSystemVisitor
{
    void VisitFile(File file);
    void VisitDirectory(Directory directory);
}

// 具体访问者 - 统计信息收集器
public class StatisticsVisitor : IFileSystemVisitor
{
    public int TotalFiles { get; private set; }
    public int TotalDirectories { get; private set; }
    public long TotalSize { get; private set; }
    public Dictionary<string, int> FileTypeCount { get; } = new Dictionary<string, int>();

    private HashSet<Directory> _visitedDirectories = new HashSet<Directory>();

    public void VisitFile(File file)
    {
        TotalFiles++;
        TotalSize += file.Size;

        string extension = file.Extension.ToLower();
        if (FileTypeCount.ContainsKey(extension))
        {
            FileTypeCount[extension]++;
        }
        else
        {
            FileTypeCount[extension] = 1;
        }
    }

    public void VisitDirectory(Directory directory)
    {
        if (_visitedDirectories.Contains(directory))
        {
            return; // 避免循环引用
        }

        _visitedDirectories.Add(directory);
        TotalDirectories++;

        foreach (var child in directory.GetChildren())
        {
            if (child is File file)
            {
                VisitFile(file);
            }
            else if (child is Directory dir)
            {
                VisitDirectory(dir);
            }
        }
    }

    public void PrintStatistics()
    {
        Console.WriteLine("文件系统统计信息:");
        Console.WriteLine($"总目录数: {TotalDirectories}");
        Console.WriteLine($"总文件数: {TotalFiles}");
        Console.WriteLine($"总大小: {FormatSize(TotalSize)}");

        Console.WriteLine("\n文件类型统计:");
        foreach (var type in FileTypeCount.OrderByDescending(x => x.Value))
        {
            Console.WriteLine($"{type.Key}: {type.Value} 个文件");
        }
    }

    private string FormatSize(long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB", "TB" };
        int order = 0;
        double size = bytes;

        while (size >= 1024 && order < sizes.Length - 1)
        {
            order++;
            size /= 1024;
        }

        return $"{size:0.##} {sizes[order]}";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 搜索操作类 - 使用组合模式的高级搜索功能
public class FileSystemSearcher
{
    private readonly FileSystemItem _root;
    public FileSystemSearcher(FileSystemItem root)
    {
        _root = root;
    }

    // 按名称搜索
    public List<FileSystemItem> FindByName(string searchPattern, bool recursive = true)
    {
        var results = new List<FileSystemItem>();
        Search(_root, item => item.Name.Contains(searchPattern, StringComparison.OrdinalIgnoreCase), results, recursive);
        return results;
    }

    // 按大小搜索文件
    public List<File> FindFilesBySize(long minSize, long maxSize, bool recursive = true)
    {
        var results = new List<FileSystemItem>();
        Search(_root, item => item is File file && file.Size >= minSize && file.Size <= maxSize, results, recursive);
        return results.Cast<File>().ToList();
    }

    // 按修改日期搜索
    public List<FileSystemItem> FindByModifiedDate(DateTime startDate, DateTime endDate, bool recursive = true)
    {
        var results = new List<FileSystemItem>();
        Search(_root, item => item.ModifiedAt >= startDate && item.ModifiedAt <= endDate, results, recursive);
        return results;
    }

    // 按内容类型搜索文件
    public List<File> FindFilesByContentType(string contentType, bool recursive = true)
    {
        var results = new List<FileSystemItem>();
        Search(_root, item => item is File file && file.ContentType.StartsWith(contentType, StringComparison.OrdinalIgnoreCase), results, recursive);
        return results.Cast<File>().ToList();
    }

    // 通用搜索方法
    private void Search(FileSystemItem item, Func<FileSystemItem, bool> predicate, List<FileSystemItem> results, bool recursive)
    {
        if (predicate(item))
        {
            results.Add(item);
        }

        if (item is Directory directory && recursive)
        {
            foreach (var child in directory.GetChildren())
            {
                Search(child, predicate, results, recursive);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

​

// 文件系统导出器 - 将文件系统结构导出为不同格式
public class FileSystemExporter
{
    // 导出为文本格式
    public static string ExportToText(FileSystemItem root)
    {
        var sb = new StringBuilder();
        ExportToTextRecursive(root, "", sb);
        return sb.ToString();
    }

    private static void ExportToTextRecursive(FileSystemItem item, string indent, StringBuilder sb)
    {
        if (item is File file)
        {
            sb.AppendLine($"{indent}[文件] {file.Name} ({FormatSize(file.Size)})");
        }
        else if (item is Directory directory)
        {
            sb.AppendLine($"{indent}[目录] {directory.Name}");

            foreach (var child in directory.GetChildren())
            {
                ExportToTextRecursive(child, indent + "  ", sb);
            }
        }
    }

    // 导出为JSON格式
    public static string ExportToJson(FileSystemItem root)
    {
        return ConvertToJsonRecursive(root).ToString();
    }

    private static System.Text.Json.JsonElement ConvertToJsonRecursive(FileSystemItem item)
    {
        var options = new System.Text.Json.JsonSerializerOptions
        {
            WriteIndented = true
        };

        if (item is File file)
        {
            var fileJson = new
            {
                type = "file",
                name = file.Name,
                size = file.Size,
                sizeFormatted = FormatSize(file.Size),
                contentType = file.ContentType,
                created = file.CreatedAt,
                modified = file.ModifiedAt,
                path = file.GetPath()
            };

            string json = System.Text.Json.JsonSerializer.Serialize(fileJson, options);
            using var doc = System.Text.Json.JsonDocument.Parse(json);
            return doc.RootElement.Clone();
        }
        else if (item is Directory directory)
        {
            var children = new List<System.Text.Json.JsonElement>();

            foreach (var child in directory.GetChildren())
            {
                children.Add(ConvertToJsonRecursive(child));
            }

            var dirJson = new
            {
                type = "directory",
                name = directory.Name,
                created = directory.CreatedAt,
                modified = directory.ModifiedAt,
                path = directory.GetPath(),
                itemCount = directory.GetItemCount(),
                size = directory.GetSize(),
                sizeFormatted = FormatSize(directory.GetSize()),
                children = children
            };

            string json = System.Text.Json.JsonSerializer.Serialize(dirJson, options);
            using var doc = System.Text.Json.JsonDocument.Parse(json);
            return doc.RootElement.Clone();
        }

        return new System.Text.Json.JsonElement();
    }

    private static string FormatSize(long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB", "TB" };
        int order = 0;
        double size = bytes;

        while (size >= 1024 && order < sizes.Length - 1)
        {
            order++;
            size /= 1024;
        }

        return $"{size:0.##} {sizes[order]}";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// 客户端代码
public class Client
{
    public static void Main()
    {
        // 创建复杂的文件系统结构
        var root = new Directory("root");
        // 创建一级目录
        var documents = new Directory("Documents");
        var pictures = new Directory("Pictures");
        var music = new Directory("Music");
        var videos = new Directory("Videos");

        root.Add(documents);
        root.Add(pictures);
        root.Add(music);
        root.Add(videos);

        // 添加文档
        documents.Add(new File("resume.docx", 25600, "application/msword"));
        documents.Add(new File("report.pdf", 1024000, "application/pdf"));
        documents.Add(new File("notes.txt", 2048, "text/plain"));

        // 创建子目录
        var workDocs = new Directory("Work");
        documents.Add(workDocs);

        workDocs.Add(new File("project_plan.xlsx", 15360, "application/vnd.ms-excel"));
        workDocs.Add(new File("presentation.pptx", 2097152, "application/vnd.ms-powerpoint"));

        // 添加图片
        pictures.Add(new File("vacation.jpg", 2097152, "image/jpeg"));
        pictures.Add(new File("family.png", 3145728, "image/png"));

        var naturePics = new Directory("Nature");
        pictures.Add(naturePics);

        naturePics.Add(new File("mountains.jpg", 4194304, "image/jpeg"));
        naturePics.Add(new File("beach.jpg", 3670016, "image/jpeg"));

        // 添加音乐
        music.Add(new File("song1.mp3", 4194304, "audio/mpeg"));
        music.Add(new File("song2.mp3", 5242880, "audio/mpeg"));

        // 添加视频
        videos.Add(new File("movie.mp4", 104857600, "video/mp4"));

        // 使用文件系统
        Console.WriteLine("=== 文件系统结构 ===");
        root.Print();

        Console.WriteLine("\n=== 搜索功能 ===");
        var searcher = new FileSystemSearcher(root);

        // 按名称搜索
        Console.WriteLine("搜索包含'jpg'的项目:");
        var jpgItems = searcher.FindByName("jpg");
        foreach (var item in jpgItems)
        {
            Console.WriteLine($"- {item.GetPath()}");
        }

        // 按类型搜索
        Console.WriteLine("\n搜索所有图片文件:");
        var imageFiles = searcher.FindFilesByContentType("image/");
        foreach (var file in imageFiles)
        {
            Console.WriteLine($"- {file.GetPath()} ({FormatSize(file.Size)})");
        }

        // 按大小搜索
        Console.WriteLine("\n搜索大于2MB且小于5MB的文件:");
        var sizeFiles = searcher.FindFilesBySize(2 * 1024 * 1024, 5 * 1024 * 1024);
        foreach (var file in sizeFiles)
        {
            Console.WriteLine($"- {file.GetPath()} ({FormatSize(file.Size)})");
        }

        // 使用访问者模式收集统计信息
        Console.WriteLine("\n=== 统计信息 ===");
        var statistics = new StatisticsVisitor();
        statistics.VisitDirectory(root);
        statistics.PrintStatistics();

        // 导出文件系统
        Console.WriteLine("\n=== 导出为文本 ===");
        string textExport = FileSystemExporter.ExportToText(root);
        Console.WriteLine(textExport);

        Console.WriteLine("\n=== 复制目录 ===");
        var documentsCopy = (Directory)documents.Clone();
        documentsCopy.Name = "Documents_Backup";
        root.Add(documentsCopy);
        Console.WriteLine("Documents目录已复制为Documents_Backup");

        // 再次打印文件系统结构
        Console.WriteLine("\n=== 更新后的文件系统结构 ===");
        root.Print();
    }

    private static string FormatSize(long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB", "TB" };
        int order = 0;
        double size = bytes;

        while (size >= 1024 && order < sizes.Length - 1)
        {
            order++;
            size /= 1024;
        }

        return $"{size:0.##} {sizes[order]}";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
**业务场景结合**:
    ```csharp
    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;

// 组织结构管理系统 - 使用组合模式表示公司层次结构

// 1. 组件接口
public interface IOrganizationComponent
{
    string Id { get; }
    string Name { get; set; }
    IOrganizationComponent Parent { get; }

    void SetParent(IOrganizationComponent parent);
    decimal GetTotalBudget();
    int GetEmployeeCount();
    string GetFullPath();
    void Accept(IOrganizationVisitor visitor);
    void Print(string indent = "");
}

// 2. 抽象组件基类
public abstract class OrganizationComponentBase : IOrganizationComponent
{
    private IOrganizationComponent _parent;

    public string Id { get; }
    public string Name { get; set; }
    public DateTime CreatedDate { get; }
    public DateTime ModifiedDate { get; set; }

    public IOrganizationComponent Parent => _parent;

    protected OrganizationComponentBase(string id, string name)
    {
        Id = id;
        Name = name;
        CreatedDate = DateTime.Now;
        ModifiedDate = DateTime.Now;
    }

    public void SetParent(IOrganizationComponent parent)
    {
        _parent = parent;
    }

    public string GetFullPath()
    {
        if (_parent == null)
        {
            return Name;
        }

        return _parent.GetFullPath() + " > " + Name;
    }

    public abstract decimal GetTotalBudget();
    public abstract int GetEmployeeCount();
    public abstract void Accept(IOrganizationVisitor visitor);
    public abstract void Print(string indent = "");
}

// 3. 叶子组件 - 部门
public class Department : OrganizationComponentBase
{
    public string Description { get; set; }
    public decimal Budget { get; set; }
    public string Location { get; set; }
    public string Manager { get; set; }
    public int EmployeeCount { get; set; }

    public Department(string id, string name) : base(id, name)
    {
        Budget = 0;
        EmployeeCount = 0;
    }

    public override decimal GetTotalBudget()
    {
        return Budget;
    }

    public override int GetEmployeeCount()
    {
        return EmployeeCount;
    }

    public override void Accept(IOrganizationVisitor visitor)
    {
        visitor.VisitDepartment(this);
    }

    public override void Print(string indent = "")
    {
        Console.WriteLine($"{indent}部门: {Name}");
        Console.WriteLine($"{indent}  描述: {Description}");
        Console.WriteLine($"{indent}  预算: {Budget:C}");
        Console.WriteLine($"{indent}  地点: {Location}");
        Console.WriteLine($"{indent}  经理: {Manager}");
        Console.WriteLine($"{indent}  员工数: {EmployeeCount}");
    }
}

// 4. 组合组件 - 组织单位(可以包含部门和其他组织单位)
public class OrganizationUnit : OrganizationComponentBase
{
    private readonly List<IOrganizationComponent> _children = new List<IOrganizationComponent>();

    public string Description { get; set; }
    public string Director { get; set; }

    public OrganizationUnit(string id, string name) : base(id, name)
    {
    }

    // 添加子组件
    public void Add(IOrganizationComponent component)
    {
        _children.Add(component);
        component.SetParent(this);
        ModifiedDate = DateTime.Now;
    }

    // 移除子组件
    public void Remove(IOrganizationComponent component)
    {
        _children.Remove(component);
        ModifiedDate = DateTime.Now;
    }

    // 获取子组件
    public List<IOrganizationComponent> GetChildren()
    {
        return new List<IOrganizationComponent>(_children);
    }

    // 获取特定子组件
    public IOrganizationComponent GetChild(string id)
    {
        return _children.FirstOrDefault(c => c.Id == id);
    }

    public override decimal GetTotalBudget()
    {
        return _children.Sum(c => c.GetTotalBudget());
    }

    public override int GetEmployeeCount()
    {
        return _children.Sum(c => c.GetEmployeeCount());
    }

    public override void Accept(IOrganizationVisitor visitor)
    {
        visitor.VisitOrganizationUnit(this);

        foreach (var child in _children)
        {
            child.Accept(visitor);
        }
    }

    public override void Print(string indent = "")
    {
        Console.WriteLine($"{indent}组织单位: {Name}");
        Console.WriteLine($"{indent}  描述: {Description}");
        Console.WriteLine($"{indent}  主管: {Director}");
        Console.WriteLine($"{indent}  总预算: {GetTotalBudget():C}");
        Console.WriteLine($"{indent}  总员工数: {GetEmployeeCount()}");

        Console.WriteLine($"{indent}  子组件:");
        foreach (var child in _children)
        {
            child.Print(indent + "    ");
        }
    }

    // 查找特定名称的组件
    public IOrganizationComponent FindByName(string name)
    {
        if (Name.Equals(name, StringComparison.OrdinalIgnoreCase))
        {
            return this;
        }

        foreach (var child in _children)
        {
            if (child is OrganizationUnit unit)
            {
                var result = unit.FindByName(name);
                if (result != null)
                {
                    return result;
                }
            }
            else if (child.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
            {
                return child;
            }
        }

        return null;
    }

    // 查找所有符合条件的组件
    public List<IOrganizationComponent> FindAll(Func<IOrganizationComponent, bool> predicate)
    {
        var results = new List<IOrganizationComponent>();

        if (predicate(this))
        {
            results.Add(this);
        }

        foreach (var child in _children)
        {
            if (child is OrganizationUnit unit)
            {
                results.AddRange(unit.FindAll(predicate));
            }
            else if (predicate(child))
            {
                results.Add(child);
            }
        }

        return results;
    }
}

// 5. 访问者接口
public interface IOrganizationVisitor
{
    void VisitDepartment(Department department);
    void VisitOrganizationUnit(OrganizationUnit unit);
}

// 6. 具体访问者 - 预算分析器
public class BudgetAnalysisVisitor : IOrganizationVisitor
{
    public decimal TotalBudget { get; private set; }
    public int TotalDepartments { get; private set; }
    public Dictionary<string, decimal> BudgetByUnit { get; } = new Dictionary<string, decimal>();
    public Department HighestBudgetDepartment { get; private set; }
    public Department LowestBudgetDepartment { get; private set; }
    public decimal AverageDepartmentBudget => TotalDepartments > 0 ? TotalBudget / TotalDepartments : 0;

    private readonly ILogger<BudgetAnalysisVisitor> _logger;

    public BudgetAnalysisVisitor(ILogger<BudgetAnalysisVisitor> logger = null)
    {
        _logger = logger;
    }

    public void VisitDepartment(Department department)
    {
        TotalBudget += department.Budget;
        TotalDepartments++;

        _logger?.LogDebug("访问部门: {Department}, 预算: {Budget}", department.Name, department.Budget);

        // 跟踪最高/最低预算部门
        if (HighestBudgetDepartment == null || department.Budget > HighestBudgetDepartment.Budget)
        {
            HighestBudgetDepartment = department;
        }

        if (LowestBudgetDepartment == null || department.Budget < LowestBudgetDepartment.Budget)
        {
            LowestBudgetDepartment = department;
        }
    }

    public void VisitOrganizationUnit(OrganizationUnit unit)
    {
        _logger?.LogDebug("访问组织单位: {Unit}", unit.Name);

        // 更新当前单位的预算(将由子组件计算)
        BudgetByUnit[unit.Id] = unit.GetTotalBudget();
    }

    public void PrintAnalysis()
    {
        Console.WriteLine("=== 预算分析 ===");
        Console.WriteLine($"总预算: {TotalBudget:C}");
        Console.WriteLine($"部门数量: {TotalDepartments}");
        Console.WriteLine($"平均部门预算: {AverageDepartmentBudget:C}");

        if (HighestBudgetDepartment != null)
        {
            Console.WriteLine($"最高预算部门: {HighestBudgetDepartment.Name} ({HighestBudgetDepartment.Budget:C})");
        }

        if (LowestBudgetDepartment != null)
        {
            Console.WriteLine($"最低预算部门: {LowestBudgetDepartment.Name} ({LowestBudgetDepartment.Budget:C})");
        }

        Console.WriteLine("\n各单位预算:");
        foreach (var entry in BudgetByUnit.OrderByDescending(x => x.Value))
        {
            Console.WriteLine($"- {entry.Key}: {entry.Value:C}");
        }
    }
}

// 7. 具体访问者 - 人员统计分析器
public class StaffingAnalysisVisitor : IOrganizationVisitor
{
    public int TotalEmployees { get; private set; }
    public int TotalDepartments { get; private set; }
    public Dictionary<string, int> EmployeesByUnit { get; } = new Dictionary<string, int>();
    public Department LargestDepartment { get; private set; }
    public Department SmallestDepartment { get; private set; }
    public double AverageDepartmentSize => TotalDepartments > 0 ? (double)TotalEmployees / TotalDepartments : 0;

    public void VisitDepartment(Department department)
    {
        TotalEmployees += department.EmployeeCount;
        TotalDepartments++;

        // 跟踪最大/最小部门
        if (LargestDepartment == null || department.EmployeeCount > LargestDepartment.EmployeeCount)
        {
            LargestDepartment = department;
        }

        if (SmallestDepartment == null || department.EmployeeCount < SmallestDepartment.EmployeeCount)
        {
            SmallestDepartment = department;
        }
    }

    public void VisitOrganizationUnit(OrganizationUnit unit)
    {
        // 更新当前单位的员工数(将由子组件计算)
        EmployeesByUnit[unit.Id] = unit.GetEmployeeCount();
    }

    public void PrintAnalysis()
    {
        Console.WriteLine("=== 人员统计分析 ===");
        Console.WriteLine($"总员工数: {TotalEmployees}");
        Console.WriteLine($"部门数量: {TotalDepartments}");
        Console.WriteLine($"平均部门规模: {AverageDepartmentSize:F1} 人");

        if (LargestDepartment != null)
        {
            Console.WriteLine($"最大部门: {LargestDepartment.Name} ({LargestDepartment.EmployeeCount} 人)");
        }

        if (SmallestDepartment != null)
        {
            Console.WriteLine($"最小部门: {SmallestDepartment.Name} ({SmallestDepartment.EmployeeCount} 人)");
        }

        Console.WriteLine("\n各单位人员:");
        foreach (var entry in EmployeesByUnit.OrderByDescending(x => x.Value))
        {
            Console.WriteLine($"- {entry.Key}: {entry.Value} 人");
        }
    }
}

// 8. 组织结构导出器
public class OrganizationExporter
{
    public static string ExportToCsv(OrganizationUnit root)
    {
        var sb = new StringBuilder();
        sb.AppendLine("ID,Name,Type,Parent,Budget,EmployeeCount,Path");

        ExportToCsvRecursive(root, sb);

        return sb.ToString();
    }

    private static void ExportToCsvRecursive(IOrganizationComponent component, StringBuilder sb)
    {
        // 添加当前组件
        string type = component is Department ? "Department" : "OrganizationUnit";
        string parentId = component.Parent?.Id ?? "";
        string budget = component is Department dept ? dept.Budget.ToString() : component.GetTotalBudget().ToString();
        string employeeCount = component is Department d ? d.EmployeeCount.ToString() : component.GetEmployeeCount().ToString();

        sb.AppendLine($"{component.Id},{component.Name},{type},{parentId},{budget},{employeeCount},{component.GetFullPath()}");

        // 递归处理子组件
        if (component is OrganizationUnit unit)
        {
            foreach (var child in unit.GetChildren())
            {
                ExportToCsvRecursive(child, sb);
            }
        }
    }

    public static string ExportToJson(OrganizationUnit root)
    {
        var organizationJson = ConvertToJsonObject(root);
        return JsonSerializer.Serialize(organizationJson, new JsonSerializerOptions { WriteIndented = true });
    }

    private static object ConvertToJsonObject(IOrganizationComponent component)
    {
        if (component is Department department)
        {
            return new
            {
                id = department.Id,
                name = department.Name,
                type = "Department",
                description = department.Description,
                budget = department.Budget,
                location = department.Location,
                manager = department.Manager,
                employeeCount = department.EmployeeCount,
                path = department.GetFullPath()
            };
        }
        else if (component is OrganizationUnit unit)
        {
            var children = new List<object>();

            foreach (var child in unit.GetChildren())
            {
                children.Add(ConvertToJsonObject(child));
            }

            return new
            {
                id = unit.Id,
                name = unit.Name,
                type = "OrganizationUnit",
                description = unit.Description,
                director = unit.Director,
                totalBudget = unit.GetTotalBudget(),
                totalEmployees = unit.GetEmployeeCount(),
                path = unit.GetFullPath(),
                children = children
            };
        }

        return null;
    }
}

// 9. 组织结构管理服务
public class OrganizationService
{
    private readonly OrganizationUnit _rootUnit;
    private readonly ILogger<OrganizationService> _logger;

    public OrganizationService(OrganizationUnit rootUnit, ILogger<OrganizationService> logger)
    {
        _rootUnit = rootUnit;
        _logger = logger;
    }

    // 创建新的组织单位
    public OrganizationUnit CreateOrganizationUnit(string parentId, string id, string name, string description, string director)
    {
        var parent = FindOrganizationUnitById(parentId);
        if (parent == null)
        {
            _logger.LogWarning("未找到父组织单位: {ParentId}", parentId);
            return null;
        }

        var newUnit = new OrganizationUnit(id, name)
        {
            Description = description,
            Director = director
        };

        parent.Add(newUnit);
        _logger.LogInformation("创建新组织单位: {Id}, {Name}, 父单位: {ParentId}", id, name, parentId);

        return newUnit;
    }

    // 创建新的部门
    public Department CreateDepartment(string parentId, string id, string name, string description, decimal budget, string location, string manager, int employeeCount)
    {
        var parent = FindOrganizationUnitById(parentId);
        if (parent == null)
        {
            _logger.LogWarning("未找到父组织单位: {ParentId}", parentId);
            return null;
        }

        var newDepartment = new Department(id, name)
        {
            Description = description,
            Budget = budget,
            Location = location,
            Manager = manager,
            EmployeeCount = employeeCount
        };

        parent.Add(newDepartment);
        _logger.LogInformation("创建新部门: {Id}, {Name}, 父单位: {ParentId}", id, name, parentId);

        return newDepartment;
    }

    // 移动组织组件
    public bool MoveComponent(string componentId, string newParentId)
    {
        var component = FindComponentById(componentId);
        if (component == null)
        {
            _logger.LogWarning("未找到组件: {ComponentId}", componentId);
            return false;
        }

        var newParent = FindOrganizationUnitById(newParentId);
        if (newParent == null)
        {
            _logger.LogWarning("未找到新父组织单位: {NewParentId}", newParentId);
            return false;
        }

        // 移除组件从当前父节点
        if (component.Parent is OrganizationUnit currentParent)
        {
            currentParent.Remove(component);
        }

        // 添加到新的父节点
        newParent.Add(component);

        _logger.LogInformation("移动组件 {ComponentId} 到新父单位 {NewParentId}", componentId, newParentId);
        return true;
    }

    // 删除组织组件
    public bool DeleteComponent(string componentId)
    {
        var component = FindComponentById(componentId);
        if (component == null)
        {
            _logger.LogWarning("未找到组件: {ComponentId}", componentId);
            return false;
        }

        if (component.Parent is OrganizationUnit parent)
        {
            parent.Remove(component);
            _logger.LogInformation("删除组件: {ComponentId}, {ComponentName}", componentId, component.Name);
            return true;
        }

        _logger.LogWarning("组件 {ComponentId} 没有父节点,无法删除", componentId);
        return false;
    }

    // 更新部门预算
    public bool UpdateDepartmentBudget(string departmentId, decimal newBudget)
    {
        var component = FindComponentById(departmentId);
        if (component is Department department)
        {
            decimal oldBudget = department.Budget;
            department.Budget = newBudget;
            department.ModifiedDate = DateTime.Now;

            _logger.LogInformation("更新部门 {DepartmentId} 预算: {OldBudget} -> {NewBudget}",
                                   departmentId, oldBudget, newBudget);

            return true;
        }

        _logger.LogWarning("未找到部门或组件不是部门: {DepartmentId}", departmentId);
        return false;
    }

    // 更新部门员工数
    public bool UpdateDepartmentEmployeeCount(string departmentId, int newCount)
    {
        var component = FindComponentById(departmentId);
        if (component is Department department)
        {
            int oldCount = department.EmployeeCount;
            department.EmployeeCount = newCount;
            department.ModifiedDate = DateTime.Now;

            _logger.LogInformation("更新部门 {DepartmentId} 员工数: {OldCount} -> {NewCount}",
                                   departmentId, oldCount, newCount);

            return true;
        }

        _logger.LogWarning("未找到部门或组件不是部门: {DepartmentId}", departmentId);
        return false;
    }

    // 获取预算分析
    public BudgetAnalysisVisitor AnalyzeBudget()
    {
        var visitor = new BudgetAnalysisVisitor(_logger);
        _rootUnit.Accept(visitor);
        return visitor;
    }

    // 获取人员分析
    public StaffingAnalysisVisitor AnalyzeStaffing()
    {
        var visitor = new StaffingAnalysisVisitor();
        _rootUnit.Accept(visitor);
        return visitor;
    }

    // 导出为CSV
    public string ExportToCsv()
    {
        return OrganizationExporter.ExportToCsv(_rootUnit);
    }

    // 导出为JSON
    public string ExportToJson()
    {
        return OrganizationExporter.ExportToJson(_rootUnit);
    }

    // 查找组织单位
    private OrganizationUnit FindOrganizationUnitById(string id)
    {
        if (_rootUnit.Id == id)
        {
            return _rootUnit;
        }

        return FindOrganizationUnitByIdRecursive(_rootUnit, id);
    }

    private OrganizationUnit FindOrganizationUnitByIdRecursive(OrganizationUnit unit, string id)
    {
        foreach (var child in unit.GetChildren())
        {
            if (child is OrganizationUnit childUnit)
            {
                if (childUnit.Id == id)
                {
                    return childUnit;
                }

                var result = FindOrganizationUnitByIdRecursive(childUnit, id);
                if (result != null)
                {
                    return result;
                }
            }
        }

        return null;
    }

    // 查找任意组件
    private IOrganizationComponent FindComponentById(string id)
    {
        if (_rootUnit.Id == id)
        {
            return _rootUnit;
        }

        return FindComponentByIdRecursive(_rootUnit, id);
    }

    private IOrganizationComponent FindComponentByIdRecursive(OrganizationUnit unit, string id)
    {
        foreach (var child in unit.GetChildren())
        {
            if (child.Id == id)
            {
                return child;
            }

            if (child is OrganizationUnit childUnit)
            {
                var result = FindComponentByIdRecursive(childUnit, id);
                if (result != null)
                {
                    return result;
                }
            }
        }

        return null;
    }

    // 搜索组件
    public List<IOrganizationComponent> SearchComponents(string nameContains)
    {
        if (string.IsNullOrEmpty(nameContains))
        {
            return new List<IOrganizationComponent>();
        }

        return _rootUnit.FindAll(c => c.Name.Contains(nameContains, StringComparison.OrdinalIgnoreCase));
    }

    // 获取根组织单位
    public OrganizationUnit GetRootUnit()
    {
        return _rootUnit;
    }
}

// 10. 应用示例
public class Program
{
    public static void Main()
    {
        // 设置依赖注入
        var services = new ServiceCollection();

        // 添加日志
        services.AddLogging(configure => configure.AddConsole());

        // 创建组织结构
        var company = new OrganizationUnit("ORG-001", "技术创新公司");
        company.Description = "一家专注于技术创新的公司";
        company.Director = "张首席执行官";

        // 注册组织服务
        services.AddSingleton<OrganizationService>(provider => 
                                                   new OrganizationService(
                                                       company, 
                                                       provider.GetRequiredService<ILogger<OrganizationService>>()));

        var serviceProvider = services.BuildServiceProvider();
        var organizationService = serviceProvider.GetRequiredService<OrganizationService>();

        // 构建组织结构
        BuildOrganizationStructure(organizationService);

        // 打印组织结构
        Console.WriteLine("=== 组织结构 ===");
        organizationService.GetRootUnit().Print();

        // 进行预算分析
        Console.WriteLine("\n=== 预算分析 ===");
        var budgetAnalysis = organizationService.AnalyzeBudget();
        budgetAnalysis.PrintAnalysis();

        // 进行人员分析
        Console.WriteLine("\n=== 人员分析 ===");
        var staffingAnalysis = organizationService.AnalyzeStaffing();
        staffingAnalysis.PrintAnalysis();

        // 演示更新操作
        Console.WriteLine("\n=== 组织变更示例 ===");

        // 更新部门预算
        organizationService.UpdateDepartmentBudget("DEP-003", 2000000);
        Console.WriteLine("已更新市场部预算");

        // 移动部门
        organizationService.MoveComponent("DEP-005", "ORG-002");
        Console.WriteLine("已将客户支持部门移动到产品部门下");

        // 再次打印组织结构
        Console.WriteLine("\n=== 更新后的组织结构 ===");
        organizationService.GetRootUnit().Print();

        // 导出组织结构
        string jsonExport = organizationService.ExportToJson();
        Console.WriteLine("\n=== JSON导出 (部分) ===");
        Console.WriteLine(jsonExport.Substring(0, 500) + "...");

        // 搜索示例
        Console.WriteLine("\n=== 搜索'研发'相关部门 ===");
        var searchResults = organizationService.SearchComponents("研发");
        foreach (var result in searchResults)
        {
            Console.WriteLine($"- {result.GetFullPath()}");
        }
    }

    private static void BuildOrganizationStructure(OrganizationService service)
    {
        // 创建一级部门
        var engineeringUnit = service.CreateOrganizationUnit("ORG-001", "ORG-002", "产品研发部", "负责所有产品的研发工作", "李技术总监");
        var adminUnit = service.CreateOrganizationUnit("ORG-001", "ORG-003", "行政管理部", "负责公司行政和人力资源管理", "王行政总监");

        // 创建工程部下属部门
        service.CreateDepartment("ORG-002", "DEP-001", "前端研发部", "负责Web和移动应用前端开发", 1500000, "北京", "赵经理", 15);
        service.CreateDepartment("ORG-002", "DEP-002", "后端研发部", "负责服务器和API开发", 2000000, "北京", "钱经理", 20);
        service.CreateDepartment("ORG-002", "DEP-006", "QA测试部", "负责软件质量保证和测试", 800000, "北京", "孙经理", 10);
        service.CreateDepartment("ORG-002", "DEP-007", "产品设计部", "负责用户体验和界面设计", 700000, "上海", "周经理", 8);

        // 创建行政部下属部门
        service.CreateDepartment("ORG-003", "DEP-003", "市场部", "负责市场营销和品牌推广", 1200000, "北京", "吴经理", 12);
        service.CreateDepartment("ORG-003", "DEP-004", "人力资源部", "负责招聘和员工发展", 500000, "北京", "郑经理", 5);
        service.CreateDepartment("ORG-003", "DEP-005", "客户支持部", "负责客户服务和技术支持", 600000, "上海", "冯经理", 10);

        // 创建第二级组织单位
        var researchUnit = service.CreateOrganizationUnit("ORG-002", "ORG-004", "研究院", "负责前沿技术研究", "刘研究院院长");

        // 创建研究院下属部门
        service.CreateDepartment("ORG-004", "DEP-008", "AI研发部", "负责人工智能技术研发", 3000000, "北京", "陈经理", 15);
        service.CreateDepartment("ORG-004", "DEP-009", "区块链研发部", "负责区块链技术研发", 2500000, "深圳", "杨经理", 10);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811

# 9. 装饰模式

原理:
装饰模式允许向现有对象添加新功能,同时又不改变其结构。它通过将对象包装在装饰器类中,然后用这个装饰器包装的对象替代原始对象。

思路:

  1. 创建一个接口或抽象类定义核心功能
  2. 创建具体组件类实现接口
  3. 创建装饰器抽象类,它实现同样的接口并包含对被装饰组件的引用
  4. 创建具体装饰器类,扩展装饰器抽象类并添加新功能

前辈经验:

  • 当需要在不修改现有代码的情况下动态添加功能时,使用装饰模式
  • 装饰模式比继承更灵活,可以在运行时组合不同的装饰器
  • 装饰模式符合"开闭原则",允许系统在不修改现有代码的情况下扩展功能
  • 装饰器通常保持接口的一致性,所以客户端代码不需要修改
  • 多个装饰器的嵌套可能会导致代码难以调试,应合理使用

业务场景:
开发一个数据处理系统,需要在不修改现有代码的情况下为数据流添加各种处理功能,如压缩、加密、缓存等。

简单实现:

// 组件接口
public interface IDataSource
{
    string ReadData();
    void WriteData(string data);
}

// 具体组件
public class FileDataSource : IDataSource
{
    private string _filename;
    
    public FileDataSource(string filename)
    {
        _filename = filename;
    }
    
    public string ReadData()
    {
        Console.WriteLine($"从文件 {_filename} 读取数据");
        // 实际代码中会从文件读取数据
        return "原始数据";
    }
    
    public void WriteData(string data)
    {
        Console.WriteLine($"向文件 {_filename} 写入数据: {data}");
        // 实际代码中会向文件写入数据
    }
}

// 抽象装饰器
public abstract class DataSourceDecorator : IDataSource
{
    protected IDataSource _wrappee;
    
    public DataSourceDecorator(IDataSource source)
    {
        _wrappee = source;
    }
    
    public virtual string ReadData()
    {
        return _wrappee.ReadData();
    }
    
    public virtual void WriteData(string data)
    {
        _wrappee.WriteData(data);
    }
}

// 具体装饰器 - 加密
public class EncryptionDecorator : DataSourceDecorator
{
    public EncryptionDecorator(IDataSource source) : base(source)
    {
    }
    
    public override string ReadData()
    {
        string data = base.ReadData();
        return Decrypt(data);
    }
    
    public override void WriteData(string data)
    {
        string encryptedData = Encrypt(data);
        base.WriteData(encryptedData);
    }
    
    private string Encrypt(string data)
    {
        Console.WriteLine("应用加密");
        // 简化示例,实际中会使用真实加密算法
        return "ENCRYPTED: " + data;
    }
    
    private string Decrypt(string data)
    {
        Console.WriteLine("应用解密");
        // 简化示例,实际中会使用真实解密算法
        if (data.StartsWith("ENCRYPTED: "))
        {
            return data.Substring("ENCRYPTED: ".Length);
        }
        return data;
    }
}

// 具体装饰器 - 压缩
public class CompressionDecorator : DataSourceDecorator
{
    public CompressionDecorator(IDataSource source) : base(source)
    {
    }
    
    public override string ReadData()
    {
        string data = base.ReadData();
        return Decompress(data);
    }
    
    public override void WriteData(string data)
    {
        string compressedData = Compress(data);
        base.WriteData(compressedData);
    }
    
    private string Compress(string data)
    {
        Console.WriteLine("应用压缩");
        // 简化示例,实际中会使用真实压缩算法
        return "COMPRESSED: " + data;
    }
    
    private string Decompress(string data)
    {
        Console.WriteLine("应用解压");
        // 简化示例,实际中会使用真实解压算法
        if (data.StartsWith("COMPRESSED: "))
        {
            return data.Substring("COMPRESSED: ".Length);
        }
        return data;
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        // 创建原始数据源
        IDataSource source = new FileDataSource("data.txt");
        
        // 写入原始数据
        Console.WriteLine("=== 使用原始数据源 ===");
        source.WriteData("Hello, World!");
        string originalData = source.ReadData();
        Console.WriteLine($"读取数据: {originalData}");
        
        // 用加密装饰器包装
        Console.WriteLine("\n=== 使用加密装饰器 ===");
        IDataSource encryptedSource = new EncryptionDecorator(source);
        encryptedSource.WriteData("Hello, World!");
        string decryptedData = encryptedSource.ReadData();
        Console.WriteLine($"读取数据: {decryptedData}");
        
        // 用压缩装饰器包装
        Console.WriteLine("\n=== 使用压缩装饰器 ===");
        IDataSource compressedSource = new CompressionDecorator(source);
        compressedSource.WriteData("Hello, World!");
        string decompressedData = compressedSource.ReadData();
        Console.WriteLine($"读取数据: {decompressedData}");
        
        // 结合多个装饰器(先压缩再加密)
        Console.WriteLine("\n=== 使用压缩+加密装饰器 ===");
        IDataSource compressedEncryptedSource = new EncryptionDecorator(
            new CompressionDecorator(source));
        compressedEncryptedSource.WriteData("Hello, World!");
        string finalData = compressedEncryptedSource.ReadData();
        Console.WriteLine($"读取数据: {finalData}");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

复杂实现:

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.IO.Compression;

// 数据源接口 - 基本组件
public interface IDataSource
{
    Task<byte[]> ReadDataAsync();
    Task WriteDataAsync(byte[] data);
    string GetName();
}

// 具体组件 - 文件数据源
public class FileDataSource : IDataSource
{
    private readonly string _filePath;
    
    public FileDataSource(string filePath)
    {
        _filePath = filePath;
    }
    
    public async Task<byte[]> ReadDataAsync()
    {
        if (!File.Exists(_filePath))
        {
            return new byte[0];
        }
        
        return await File.ReadAllBytesAsync(_filePath);
    }
    
    public async Task WriteDataAsync(byte[] data)
    {
        string directory = Path.GetDirectoryName(_filePath);
        if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }
        
        await File.WriteAllBytesAsync(_filePath, data);
    }
    
    public string GetName()
    {
        return $"文件({_filePath})";
    }
}

// 具体组件 - 内存数据源
public class MemoryDataSource : IDataSource
{
    private byte[] _data;
    private readonly string _name;
    
    public MemoryDataSource(string name = "内存数据")
    {
        _data = new byte[0];
        _name = name;
    }
    
    public Task<byte[]> ReadDataAsync()
    {
        return Task.FromResult(_data);
    }
    
    public Task WriteDataAsync(byte[] data)
    {
        _data = data;
        return Task.CompletedTask;
    }
    
    public string GetName()
    {
        return _name;
    }
}

// 抽象装饰器
public abstract class DataSourceDecorator : IDataSource
{
    protected readonly IDataSource _wrappee;
    private readonly string _decoratorName;
    
    public DataSourceDecorator(IDataSource wrappee, string decoratorName)
    {
        _wrappee = wrappee;
        _decoratorName = decoratorName;
    }
    
    public virtual async Task<byte[]> ReadDataAsync()
    {
        return await _wrappee.ReadDataAsync();
    }
    
    public virtual async Task WriteDataAsync(byte[] data)
    {
        await _wrappee.WriteDataAsync(data);
    }
    
    public string GetName()
    {
        return $"{_decoratorName}({_wrappee.GetName()})";
    }
}

// 具体装饰器 - 加密
public class EncryptionDecorator : DataSourceDecorator
{
    private readonly byte[] _key;
    private readonly byte[] _iv;
    
    public EncryptionDecorator(IDataSource wrappee, byte[] key = null, byte[] iv = null) 
        : base(wrappee, "加密")
    {
        // 如果未提供加密密钥,使用默认值
        _key = key ?? new byte[32] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
        _iv = iv ?? new byte[16] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
    }
    
    public override async Task<byte[]> ReadDataAsync()
    {
        byte[] encryptedData = await base.ReadDataAsync();
        
        if (encryptedData.Length == 0)
        {
            return encryptedData;
        }
        
        return Decrypt(encryptedData);
    }
    
    public override async Task WriteDataAsync(byte[] data)
    {
        byte[] encryptedData = Encrypt(data);
        await base.WriteDataAsync(encryptedData);
    }
    
    private byte[] Encrypt(byte[] data)
    {
        if (data == null || data.Length == 0)
            return data;
            
        using (Aes aes = Aes.Create())
        {
            aes.Key = _key;
            aes.IV = _iv;
            
            using (MemoryStream output = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(output, aes.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cryptoStream.Write(data, 0, data.Length);
                    cryptoStream.FlushFinalBlock();
                }
                
                return output.ToArray();
            }
        }
    }
    
    private byte[] Decrypt(byte[] data)
    {
        if (data == null || data.Length == 0)
            return data;
            
        using (Aes aes = Aes.Create())
        {
            aes.Key = _key;
            aes.IV = _iv;
            
            using (MemoryStream input = new MemoryStream(data))
            using (MemoryStream output = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(input, aes.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    
                    while ((bytesRead = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        output.Write(buffer, 0, bytesRead);
                    }
                }
                
                return output.ToArray();
            }
        }
    }
}

// 具体装饰器 - 压缩
public class CompressionDecorator : DataSourceDecorator
{
    private readonly CompressionLevel _compressionLevel;
    
    public CompressionDecorator(IDataSource wrappee, CompressionLevel compressionLevel = CompressionLevel.Optimal) 
        : base(wrappee, "压缩")
    {
        _compressionLevel = compressionLevel;
    }
    
    public override async Task<byte[]> ReadDataAsync()
    {
        byte[] compressedData = await base.ReadDataAsync();
        
        if (compressedData.Length == 0)
        {
            return compressedData;
        }
        
        return Decompress(compressedData);
    }
    
    public override async Task WriteDataAsync(byte[] data)
    {
        byte[] compressedData = Compress(data);
        await base.WriteDataAsync(compressedData);
    }
    
    private byte[] Compress(byte[] data)
    {
        if (data == null || data.Length == 0)
            return data;
            
        using (MemoryStream output = new MemoryStream())
        {
            using (GZipStream gzip = new GZipStream(output, _compressionLevel))
            {
                gzip.Write(data, 0, data.Length);
            }
            
            return output.ToArray();
        }
    }
    
    private byte[] Decompress(byte[] data)
    {
        if (data == null || data.Length == 0)
            return data;
            
        using (MemoryStream input = new MemoryStream(data))
        using (MemoryStream output = new MemoryStream())
        {
            using (GZipStream gzip = new GZipStream(input, CompressionMode.Decompress))
            {
                gzip.CopyTo(output);
            }
            
            return output.ToArray();
        }
    }
}

// 具体装饰器 - 缓存
public class CachingDecorator : DataSourceDecorator
{
    private byte[] _cachedData;
    private readonly TimeSpan _cacheExpiration;
    private DateTime _lastCacheTime;
    private bool _isCacheValid;
    
    public CachingDecorator(IDataSource wrappee, TimeSpan? cacheExpiration = null) 
        : base(wrappee, "缓存")
    {
        _cacheExpiration = cacheExpiration ?? TimeSpan.FromMinutes(10);
        _isCacheValid = false;
    }
    
    public override async Task<byte[]> ReadDataAsync()
    {
        if (_isCacheValid && (DateTime.Now - _lastCacheTime) < _cacheExpiration)
        {
            Console.WriteLine("从缓存读取数据");
            return _cachedData;
        }
        
        Console.WriteLine("缓存未命中,从源读取数据");
        byte[] data = await base.ReadDataAsync();
        _cachedData = data;
        _lastCacheTime = DateTime.Now;
        _isCacheValid = true;
        
        return data;
    }
    
    public override async Task WriteDataAsync(byte[] data)
    {
        await base.WriteDataAsync(data);
        
        // 更新缓存
        _cachedData = data;
        _lastCacheTime = DateTime.Now;
        _isCacheValid = true;
    }
    
    // 使缓存失效
    public void InvalidateCache()
    {
        _isCacheValid = false;
    }
}

// 具体装饰器 - 日志记录
public class LoggingDecorator : DataSourceDecorator
{
    private readonly bool _logData;
    private readonly string _logFilePath;
    
    public LoggingDecorator(IDataSource wrappee, string logFilePath = "data_operations.log", bool logData = false) 
        : base(wrappee, "日志")
    {
        _logFilePath = logFilePath;
        _logData = logData;
    }
    
    public override async Task<byte[]> ReadDataAsync()
    {
        DateTime startTime = DateTime.Now;
        byte[] data = await base.ReadDataAsync();
        TimeSpan elapsed = DateTime.Now - startTime;
        
        await LogOperationAsync("读取", data.Length, elapsed);
        
        return data;
    }
    
    public override async Task WriteDataAsync(byte[] data)
    {
        DateTime startTime = DateTime.Now;
        await base.WriteDataAsync(data);
        TimeSpan elapsed = DateTime.Now - startTime;
        
        await LogOperationAsync("写入", data.Length, elapsed);
    }
    
    private async Task LogOperationAsync(string operation, int dataSize, TimeSpan elapsed)
    {
        string directory = Path.GetDirectoryName(_logFilePath);
        if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }
        
        string logMessage = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {operation} {_wrappee.GetName()}, 大小: {FormatSize(dataSize)}, 耗时: {elapsed.TotalMilliseconds:F2}ms";
        
        if (_logData && dataSize > 0)
        {
            logMessage += $", 数据预览: {(dataSize > 50 ? "..." : "")}";
        }
        
        await File.AppendAllTextAsync(_logFilePath, logMessage + Environment.NewLine);
    }
    
    private string FormatSize(long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB", "TB" };
        int order = 0;
        double size = bytes;
        
        while (size >= 1024 && order < sizes.Length - 1)
        {
            order++;
            size /= 1024;
        }
        
        return $"{size:0.##} {sizes[order]}";
    }
}

// 具体装饰器 - 版本控制
public class VersionControlDecorator : DataSourceDecorator
{
    private readonly string _historyDirectory;
    private readonly int _maxVersions;
    
    public VersionControlDecorator(IDataSource wrappee, string historyDirectory = "history", int maxVersions = 10) 
        : base(wrappee, "版本控制")
    {
        _historyDirectory = historyDirectory;
        _maxVersions = maxVersions;
    }
    
    public override async Task<byte[]> ReadDataAsync()
    {
        return await base.ReadDataAsync();
    }
    
    public override async Task WriteDataAsync(byte[] data)
    {
        // 先保存当前版本
        await SaveVersionAsync(data);
        
        // 再写入新数据
        await base.WriteDataAsync(data);
        
        // 清理过期版本
        await CleanupOldVersionsAsync();
    }
    
    private async Task SaveVersionAsync(byte[] data)
    {
        if (!Directory.Exists(_historyDirectory))
        {
            Directory.CreateDirectory(_historyDirectory);
        }
        
        byte[] currentData = await base.ReadDataAsync();
        if (currentData.Length > 0)
        {
            string versionFileName = $"{_wrappee.GetName().GetHashCode()}_{DateTime.Now:yyyyMMddHHmmss}.bak";
            string versionPath = Path.Combine(_historyDirectory, versionFileName);
            
            await File.WriteAllBytesAsync(versionPath, currentData);
            Console.WriteLine($"已保存版本: {versionPath}");
        }
    }
    
    private async Task CleanupOldVersionsAsync()
    {
        if (!Directory.Exists(_historyDirectory))
        {
            return;
        }
        
        string prefix = $"{_wrappee.GetName().GetHashCode()}_";
        
        var files = Directory.GetFiles(_historyDirectory)
            .Where(f => Path.GetFileName(f).StartsWith(prefix))
            .OrderByDescending(f => f)
            .Skip(_maxVersions)
            .ToList();
            
        foreach (var file in files)
        {
            File.Delete(file);
            Console.WriteLine($"已删除过期版本: {file}");
        }
        
        await Task.CompletedTask;
    }
    
    // 获取可用版本列表
    public List<string> GetAvailableVersions()
    {
        if (!Directory.Exists(_historyDirectory))
        {
            return new List<string>();
        }
        
        string prefix = $"{_wrappee.GetName().GetHashCode()}_";
        
        return Directory.GetFiles(_historyDirectory)
            .Where(f => Path.GetFileName(f).StartsWith(prefix))
            .OrderByDescending(f => f)
            .Select(f => Path.GetFileName(f))
            .ToList();
    }
    
    // 恢复特定版本
    public async Task RestoreVersionAsync(string versionFileName)
    {
        string versionPath = Path.Combine(_historyDirectory, versionFileName);
        
        if (File.Exists(versionPath))
        {
            byte[] versionData = await File.ReadAllBytesAsync(versionPath);
            await base.WriteDataAsync(versionData);
            Console.WriteLine($"已恢复版本: {versionFileName}");
        }
        else
        {
            throw new FileNotFoundException($"找不到版本文件: {versionFileName}");
        }
    }
}

// 具体装饰器 - 数据校验
public class ValidationDecorator : DataSourceDecorator
{
    private readonly Func<byte[], bool> _validator;
    private readonly string _validationName;
    
    public ValidationDecorator(IDataSource wrappee, Func<byte[], bool> validator, string validationName = "数据验证") 
        : base(wrappee, validationName)
    {
        _validator = validator;
        _validationName = validationName;
    }
    
    public override async Task<byte[]> ReadDataAsync()
    {
        byte[] data = await base.ReadDataAsync();
        
        if (data.Length > 0 && !_validator(data))
        {
            throw new InvalidDataException($"{_validationName} 失败: 读取的数据无效");
        }
        
        return data;
    }
    
    public override async Task WriteDataAsync(byte[] data)
    {
        if (!_validator(data))
        {
            throw new InvalidDataException($"{_validationName} 失败: 要写入的数据无效");
        }
        
        await base.WriteDataAsync(data);
    }
}

// 具体装饰器 - 转换
public class TransformationDecorator : DataSourceDecorator
{
    private readonly Func<byte[], byte[]> _readTransform;
    private readonly Func<byte[], byte[]> _writeTransform;
    
    public TransformationDecorator(
        IDataSource wrappee, 
        Func<byte[], byte[]> readTransform, 
        Func<byte[], byte[]> writeTransform,
        string transformName = "转换") 
        : base(wrappee, transformName)
    {
        _readTransform = readTransform;
        _writeTransform = writeTransform;
    }
    
    public override async Task<byte[]> ReadDataAsync()
    {
        byte[] data = await base.ReadDataAsync();
        
        if (data.Length > 0 && _readTransform != null)
        {
            return _readTransform(data);
        }
        
        return data;
    }
    
    public override async Task WriteDataAsync(byte[] data)
    {
        if (data.Length > 0 && _writeTransform != null)
        {
            data = _writeTransform(data);
        }
        
        await base.WriteDataAsync(data);
    }
}

// 工厂类 - 创建常用数据源配置
public class DataSourceFactory
{
    // 创建基本文件数据源
    public static IDataSource CreateFileDataSource(string filePath)
    {
        return new FileDataSource(filePath);
    }
    
    // 创建内存数据源
    public static IDataSource CreateMemoryDataSource(string name = "内存数据")
    {
        return new MemoryDataSource(name);
    }
    
    // 创建加密文件数据源
    public static IDataSource CreateEncryptedFileDataSource(string filePath, byte[] key = null, byte[] iv = null)
    {
        return new EncryptionDecorator(new FileDataSource(filePath), key, iv);
    }
    
    // 创建压缩文件数据源
    public static IDataSource CreateCompressedFileDataSource(string filePath)
    {
        return new CompressionDecorator(new FileDataSource(filePath));
    }
    
    // 创建带缓存的文件数据源
    public static IDataSource CreateCachedFileDataSource(string filePath, TimeSpan? cacheExpiration = null)
    {
        return new CachingDecorator(new FileDataSource(filePath), cacheExpiration);
    }
    
    // 创建安全的文件数据源(压缩+加密+日志)
    public static IDataSource CreateSecureFileDataSource(string filePath, string logFilePath = "secure_operations.log")
    {
        IDataSource source = new FileDataSource(filePath);
        source = new CompressionDecorator(source);
        source = new EncryptionDecorator(source);
        source = new LoggingDecorator(source, logFilePath);
        
        return source;
    }
    
    // 创建带版本控制的文件数据源
    public static IDataSource CreateVersionedFileDataSource(string filePath, string historyDirectory = "history", int maxVersions = 10)
    {
        return new VersionControlDecorator(new FileDataSource(filePath), historyDirectory, maxVersions);
    }
    
    // 创建完整的企业级文件数据源(压缩+加密+缓存+日志+版本控制+校验)
    public static IDataSource CreateEnterpriseFileDataSource(string filePath)
    {
        // 创建基础数据源
        IDataSource source = new FileDataSource(filePath);
        
        // 添加校验(简单示例:检查数据不为空)
        source = new ValidationDecorator(source, data => data != null && data.Length > 0, "非空验证");
        
        // 添加版本控制
        source = new VersionControlDecorator(source);
        
        // 添加压缩
        source = new CompressionDecorator(source);
        
        // 添加加密
        source = new EncryptionDecorator(source);
        
        // 添加缓存
        source = new CachingDecorator(source, TimeSpan.FromMinutes(5));
        
        // 添加日志
        source = new LoggingDecorator(source, "enterprise_operations.log");
        
        return source;
    }
}

// 客户端代码
public class Client
{
    public static async Task Main()
    {
        // 创建临时目录用于测试
        string testDir = "test_data";
        if (!Directory.Exists(testDir))
        {
            Directory.CreateDirectory(testDir);
        }
        
        // 基本文件数据源
        Console.WriteLine("=== 基本文件数据源 ===");
        await TestDataSourceAsync(
            DataSourceFactory.CreateFileDataSource(Path.Combine(testDir, "simple.txt")), 
            "Hello, World!");
        
        // 加密文件数据源
        Console.WriteLine("\n=== 加密文件数据源 ===");
        await TestDataSourceAsync(
            DataSourceFactory.CreateEncryptedFileDataSource(Path.Combine(testDir, "encrypted.txt")), 
            "Secret data that needs protection");
        
        // 压缩文件数据源
        Console.WriteLine("\n=== 压缩文件数据源 ===");
        await TestDataSourceAsync(
            DataSourceFactory.CreateCompressedFileDataSource(Path.Combine(testDir, "compressed.txt")), 
            string.Join(" ", Enumerable.Repeat("This data will be compressed", 100)));
        
        // 带缓存的文件数据源
        Console.WriteLine("\n=== 带缓存的文件数据源 ===");
        var cachedSource = DataSourceFactory.CreateCachedFileDataSource(
            Path.Combine(testDir, "cached.txt"), 
            TimeSpan.FromSeconds(10));
            
        await TestDataSourceAsync(cachedSource, "Cached data");
        Console.WriteLine("再次读取(应从缓存中获取):");
        byte[] data = await cachedSource.ReadDataAsync();
        Console.WriteLine($"读取的数据: {Encoding.UTF8.GetString(data)}");
        
        // 创建自定义组合
        Console.WriteLine("\n=== 自定义组合:带日志的加密压缩文件 ===");
        IDataSource customSource = new FileDataSource(Path.Combine(testDir, "custom.txt"));
        customSource = new CompressionDecorator(customSource);
        customSource = new EncryptionDecorator(customSource);
        customSource = new LoggingDecorator(customSource, Path.Combine(testDir, "custom.log"));
        
        await TestDataSourceAsync(customSource, "This data goes through multiple transformations");
        
        // 版本控制示例
        Console.WriteLine("\n=== 带版本控制的文件数据源 ===");
        var versionedSource = DataSourceFactory.CreateVersionedFileDataSource(
            Path.Combine(testDir, "versioned.txt"), 
            Path.Combine(testDir, "history"));
            
        // 写入不同版本
        for (int i = 1; i <= 3; i++)
        {
            await versionedSource.WriteDataAsync(Encoding.UTF8.GetBytes($"Version {i} of the document"));
            Console.WriteLine($"已写入版本 {i}");
        }
        
        // 显示当前版本
        data = await versionedSource.ReadDataAsync();
        Console.WriteLine($"当前数据: {Encoding.UTF8.GetString(data)}");
        
        // 检查和恢复版本
        if (versionedSource is VersionControlDecorator vcd)
        {
            var versions = vcd.GetAvailableVersions();
            Console.WriteLine($"可用版本数: {versions.Count}");
            
            if (versions.Count > 0)
            {
                string oldVersion = versions.Last();
                Console.WriteLine($"恢复到版本: {oldVersion}");
                await vcd.RestoreVersionAsync(oldVersion);
                
                data = await versionedSource.ReadDataAsync();
                Console.WriteLine($"恢复后的数据: {Encoding.UTF8.GetString(data)}");
            }
        }
        
        // 验证装饰器
        Console.WriteLine("\n=== 带验证的数据源 ===");
        var validatedSource = new ValidationDecorator(
            new FileDataSource(Path.Combine(testDir, "validated.txt")),
            data => data.Length <= 100, // 只允许写入小于100字节的数据
            "大小验证");
            
        try
        {
            // 尝试写入有效数据
            await validatedSource.WriteDataAsync(Encoding.UTF8.GetBytes("Small valid data"));
            Console.WriteLine("成功写入有效数据");
            
            // 尝试写入无效数据
            await validatedSource.WriteDataAsync(Encoding.UTF8.GetBytes(new string('X', 200)));
        }
        catch (Exception ex)
        {
            Console.WriteLine($"预期的验证错误: {ex.Message}");
        }
        
        // 企业级数据源
        Console.WriteLine("\n=== 企业级文件数据源 ===");
        var enterpriseSource = DataSourceFactory.CreateEnterpriseFileDataSource(
            Path.Combine(testDir, "enterprise.dat"));
            
        await TestDataSourceAsync(enterpriseSource, "Critical enterprise data with full protection");
        
        Console.WriteLine("\n所有测试完成。");
    }
    
    private static async Task TestDataSourceAsync(IDataSource source, string testData)
    {
        Console.WriteLine($"测试数据源: {source.GetName()}");
        
        // 写入数据
        byte[] dataToWrite = Encoding.UTF8.GetBytes(testData);
        await source.WriteDataAsync(dataToWrite);
        Console.WriteLine($"已写入 {dataToWrite.Length} 字节");
        
        // 读取数据
        byte[] dataRead = await source.ReadDataAsync();
        string readText = Encoding.UTF8.GetString(dataRead);
        Console.WriteLine($"已读取 {dataRead.Length} 字节");
        Console.WriteLine($"读取的数据: {(readText.Length > 50 ? readText.Substring(0, 50) + "..." : readText)}");
        
        // 验证数据完整性
        bool dataMatch = testData.Equals(readText);
        Console.WriteLine($"数据完整性检查: {(dataMatch ? "通过" : "失败")}");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771

业务场景结合:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

// Web API服务场景 - 使用装饰模式增强HTTP请求处理

// 1. 核心组件接口
public interface IApiClient
{
    Task<ApiResponse> SendRequestAsync(ApiRequest request);
    string GetClientName();
}

// 请求和响应模型
public class ApiRequest
{
    public string Url { get; set; }
    public HttpMethod Method { get; set; } = HttpMethod.Get;
    public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
    public string Body { get; set; }
    public int TimeoutSeconds { get; set; } = 30;
    
    // 用于标识请求的唯一键(用于缓存)
    public string GetCacheKey()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append($"{Method}:{Url}");
        
        if (!string.IsNullOrEmpty(Body))
        {
            sb.Append($":{Body}");
        }
        
        return sb.ToString();
    }
}

public class ApiResponse
{
    public bool IsSuccess { get; set; }
    public int StatusCode { get; set; }
    public string Content { get; set; }
    public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
    public TimeSpan RequestTime { get; set; }
    public string ErrorMessage { get; set; }
    
    // 将响应内容解析为指定类型
    public T ParseContent<T>()
    {
        if (string.IsNullOrEmpty(Content))
        {
            return default;
        }
        
        return JsonConvert.DeserializeObject<T>(Content);
    }
    
    // 将响应内容解析为动态对象
    public dynamic ParseContentAsDynamic()
    {
        if (string.IsNullOrEmpty(Content))
        {
            return null;
        }
        
        return JObject.Parse(Content);
    }
}

// 2. 具体组件 - 基本API客户端
public class BasicApiClient : IApiClient
{
    private readonly HttpClient _httpClient;
    private readonly string _clientName;
    
    public BasicApiClient(HttpClient httpClient, string clientName = "基本API客户端")
    {
        _httpClient = httpClient;
        _clientName = clientName;
    }
    
    public async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        var response = new ApiResponse();
        var stopwatch = Stopwatch.StartNew();
        
        try
        {
            // 创建HTTP请求消息
            var requestMessage = new HttpRequestMessage(request.Method, request.Url);
            
            // 添加请求头
            foreach (var header in request.Headers)
            {
                requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value);
            }
            
            // 添加请求体
            if (!string.IsNullOrEmpty(request.Body))
            {
                requestMessage.Content = new StringContent(request.Body, Encoding.UTF8, "application/json");
            }
            
            // 发送请求
            var httpResponse = await _httpClient.SendAsync(requestMessage);
            
            // 处理响应
            response.StatusCode = (int)httpResponse.StatusCode;
            response.IsSuccess = httpResponse.IsSuccessStatusCode;
            response.Content = await httpResponse.Content.ReadAsStringAsync();
            
            // 获取响应头
            foreach (var header in httpResponse.Headers)
            {
                response.Headers[header.Key] = string.Join(", ", header.Value);
            }
        }
        catch (Exception ex)
        {
            response.IsSuccess = false;
            response.ErrorMessage = ex.Message;
        }
        finally
        {
            stopwatch.Stop();
            response.RequestTime = stopwatch.Elapsed;
        }
        
        return response;
    }
    
    public string GetClientName()
    {
        return _clientName;
    }
}

// 3. 抽象装饰器 - API客户端装饰器
public abstract class ApiClientDecorator : IApiClient
{
    protected readonly IApiClient _wrappee;
    protected readonly string _decoratorName;
    
    public ApiClientDecorator(IApiClient apiClient, string decoratorName)
    {
        _wrappee = apiClient;
        _decoratorName = decoratorName;
    }
    
    public virtual async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        return await _wrappee.SendRequestAsync(request);
    }
    
    public string GetClientName()
    {
        return $"{_decoratorName}({_wrappee.GetClientName()})";
    }
}

// 4. 具体装饰器 - 重试装饰器
public class RetryDecorator : ApiClientDecorator
{
    private readonly int _maxRetries;
    private readonly TimeSpan _retryDelay;
    private readonly Func<ApiResponse, bool> _retryCondition;
    private readonly ILogger<RetryDecorator> _logger;
    
    public RetryDecorator(
        IApiClient apiClient, 
        int maxRetries = 3, 
        TimeSpan? retryDelay = null,
        Func<ApiResponse, bool> retryCondition = null,
        ILogger<RetryDecorator> logger = null) 
        : base(apiClient, "重试")
    {
        _maxRetries = maxRetries;
        _retryDelay = retryDelay ?? TimeSpan.FromSeconds(1);
        _retryCondition = retryCondition ?? (response => !response.IsSuccess);
        _logger = logger;
    }
    
    public override async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        ApiResponse response = null;
        int retryCount = 0;
        
        do
        {
            if (retryCount > 0)
            {
                _logger?.LogWarning("请求失败,尝试重试 ({RetryCount}/{MaxRetries}) - {Url}", 
                    retryCount, _maxRetries, request.Url);
                    
                await Task.Delay(_retryDelay);
            }
            
            response = await _wrappee.SendRequestAsync(request);
            retryCount++;
            
        } while (retryCount <= _maxRetries && _retryCondition(response));
        
        if (retryCount > 1)
        {
            _logger?.LogInformation("请求经过 {RetryCount} 次尝试后{Result} - {Url}",
                retryCount, response.IsSuccess ? "成功" : "仍然失败", request.Url);
        }
        
        return response;
    }
}

// 5. 具体装饰器 - 缓存装饰器
public class CachingDecorator : ApiClientDecorator
{
    private readonly IMemoryCache _cache;
    private readonly TimeSpan _cacheExpiration;
    private readonly Func<ApiRequest, bool> _shouldCacheRequest;
    private readonly ILogger<CachingDecorator> _logger;
    
    public CachingDecorator(
        IApiClient apiClient,
        IMemoryCache cache,
        TimeSpan? cacheExpiration = null,
        Func<ApiRequest, bool> shouldCacheRequest = null,
        ILogger<CachingDecorator> logger = null)
        : base(apiClient, "缓存")
    {
        _cache = cache;
        _cacheExpiration = cacheExpiration ?? TimeSpan.FromMinutes(5);
        _shouldCacheRequest = shouldCacheRequest ?? (request => request.Method == HttpMethod.Get);
        _logger = logger;
    }
    
    public override async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        // 只缓存符合条件的请求
        if (!_shouldCacheRequest(request))
        {
            return await _wrappee.SendRequestAsync(request);
        }
        
        string cacheKey = request.GetCacheKey();
        
        // 尝试从缓存获取
        if (_cache.TryGetValue(cacheKey, out ApiResponse cachedResponse))
        {
            _logger?.LogInformation("从缓存返回响应 - {Url}", request.Url);
            return cachedResponse;
        }
        
        // 缓存未命中,执行请求
        _logger?.LogInformation("缓存未命中,执行请求 - {Url}", request.Url);
        var response = await _wrappee.SendRequestAsync(request);
        
        // 如果请求成功,添加到缓存
        if (response.IsSuccess)
        {
            _logger?.LogDebug("将响应添加到缓存 - {Url}, 过期时间: {ExpirationTime}", 
                request.Url, _cacheExpiration);
                
            _cache.Set(cacheKey, response, _cacheExpiration);
        }
        
        return response;
    }
    
    // 使缓存失效
    public void InvalidateCache(ApiRequest request)
    {
        string cacheKey = request.GetCacheKey();
        _cache.Remove(cacheKey);
        _logger?.LogInformation("缓存已失效 - {Url}", request.Url);
    }
    
    // 使所有缓存失效(需要在真实实现中添加更复杂的缓存键跟踪)
    public void InvalidateAllCache()
    {
        // 这里简化处理,实际实现可能需要更复杂的缓存管理
        if (_cache is MemoryCache memoryCache)
        {
            memoryCache.Compact(1.0);
            _logger?.LogWarning("所有缓存已清空");
        }
    }
}

// 6. 具体装饰器 - 日志装饰器
public class LoggingDecorator : ApiClientDecorator
{
    private readonly ILogger<LoggingDecorator> _logger;
    private readonly bool _logRequestBody;
    private readonly bool _logResponseBody;
    
    public LoggingDecorator(
        IApiClient apiClient,
        ILogger<LoggingDecorator> logger,
        bool logRequestBody = false,
        bool logResponseBody = false)
        : base(apiClient, "日志")
    {
        _logger = logger;
        _logRequestBody = logRequestBody;
        _logResponseBody = logResponseBody;
    }
    
    public override async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        // 记录请求信息
        var requestInfo = $"请求: {request.Method} {request.Url}";
        
        if (_logRequestBody && !string.IsNullOrEmpty(request.Body))
        {
            requestInfo += $", 请求体: {TruncateIfNeeded(request.Body)}";
        }
        
        _logger.LogInformation(requestInfo);
        
        // 记录请求头
        if (request.Headers.Count > 0)
        {
            _logger.LogDebug("请求头: {Headers}", JsonConvert.SerializeObject(request.Headers));
        }
        
        // 执行请求
        var stopwatch = Stopwatch.StartNew();
        var response = await _wrappee.SendRequestAsync(request);
        stopwatch.Stop();
        
        // 记录响应信息
        var responseInfo = $"响应: {response.StatusCode}, 耗时: {response.RequestTime.TotalMilliseconds:F2}ms";
        
        if (!response.IsSuccess)
        {
            responseInfo += $", 错误: {response.ErrorMessage}";
            _logger.LogWarning(responseInfo);
        }
        else
        {
            _logger.LogInformation(responseInfo);
        }
        
        // 记录响应体
        if (_logResponseBody && !string.IsNullOrEmpty(response.Content))
        {
            _logger.LogDebug("响应体: {Content}", TruncateIfNeeded(response.Content));
        }
        
        return response;
    }
    
    private string TruncateIfNeeded(string content, int maxLength = 500)
    {
        if (content.Length <= maxLength)
            return content;
            
        return content.Substring(0, maxLength) + "...";
    }
}

// 7. 具体装饰器 - 认证装饰器
public class AuthenticationDecorator : ApiClientDecorator
{
    private readonly Func<Task<string>> _tokenProvider;
    private readonly string _tokenHeaderName;
    private readonly string _tokenPrefix;
    private readonly ILogger<AuthenticationDecorator> _logger;
    
    public AuthenticationDecorator(
        IApiClient apiClient,
        Func<Task<string>> tokenProvider,
        string tokenHeaderName = "Authorization",
        string tokenPrefix = "Bearer ",
        ILogger<AuthenticationDecorator> logger = null)
        : base(apiClient, "认证")
    {
        _tokenProvider = tokenProvider;
        _tokenHeaderName = tokenHeaderName;
        _tokenPrefix = tokenPrefix;
        _logger = logger;
    }
    
    public override async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        try
        {
            // 获取身份验证令牌
            string token = await _tokenProvider();
            
            // 设置请求头
            if (!string.IsNullOrEmpty(token))
            {
                request.Headers[_tokenHeaderName] = $"{_tokenPrefix}{token}";
                _logger?.LogDebug("已添加认证令牌到请求 - {Url}", request.Url);
            }
            else
            {
                _logger?.LogWarning("无法获取认证令牌 - {Url}", request.Url);
            }
        }
        catch (Exception ex)
        {
            _logger?.LogError(ex, "获取认证令牌时出错 - {Url}", request.Url);
        }
        
        return await _wrappee.SendRequestAsync(request);
    }
}

// 8. 具体装饰器 - 断路器装饰器
public class CircuitBreakerDecorator : ApiClientDecorator
{
    private readonly int _failureThreshold;
    private readonly TimeSpan _resetTimeout;
    private readonly ILogger<CircuitBreakerDecorator> _logger;
    
    private int _failureCount = 0;
    private bool _isOpen = false;
    private DateTime _lastFailureTime = DateTime.MinValue;
    
    public CircuitBreakerDecorator(
        IApiClient apiClient,
        int failureThreshold = 3,
        TimeSpan? resetTimeout = null,
        ILogger<CircuitBreakerDecorator> logger = null)
        : base(apiClient, "断路器")
    {
        _failureThreshold = failureThreshold;
        _resetTimeout = resetTimeout ?? TimeSpan.FromSeconds(30);
        _logger = logger;
    }
    
    public override async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        // 检查断路器状态
        if (_isOpen)
        {
            // 检查是否应该重置断路器
            if (DateTime.Now - _lastFailureTime > _resetTimeout)
            {
                _logger?.LogInformation("断路器超时重置 - {Url}", request.Url);
                _isOpen = false;
                _failureCount = 0;
            }
            else
            {
                _logger?.LogWarning("断路器开路,请求被拒绝 - {Url}", request.Url);
                return new ApiResponse
                {
                    IsSuccess = false,
                    StatusCode = 503, // Service Unavailable
                    ErrorMessage = "Circuit breaker is open, request rejected"
                };
            }
        }
        
        try
        {
            var response = await _wrappee.SendRequestAsync(request);
            
            // 检查请求是否成功
            if (!response.IsSuccess)
            {
                RecordFailure();
            }
            else
            {
                // 重置失败计数
                _failureCount = 0;
            }
            
            return response;
        }
        catch (Exception)
        {
            RecordFailure();
            throw;
        }
    }
    
    private void RecordFailure()
    {
        _failureCount++;
        _lastFailureTime = DateTime.Now;
        
        _logger?.LogWarning("记录失败,当前失败计数: {FailureCount}/{FailureThreshold}", 
            _failureCount, _failureThreshold);
            
        if (_failureCount >= _failureThreshold)
        {
            _isOpen = true;
            _logger?.LogError("断路器已开路,将拒绝后续请求");
        }
    }
}

// 9. 具体装饰器 - 超时装饰器
public class TimeoutDecorator : ApiClientDecorator
{
    private readonly TimeSpan _defaultTimeout;
    private readonly ILogger<TimeoutDecorator> _logger;
    
    public TimeoutDecorator(
        IApiClient apiClient,
        TimeSpan? defaultTimeout = null,
        ILogger<TimeoutDecorator> logger = null)
        : base(apiClient, "超时控制")
    {
        _defaultTimeout = defaultTimeout ?? TimeSpan.FromSeconds(30);
        _logger = logger;
    }
    
    public override async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        // 使用请求指定的超时时间或默认值
        TimeSpan timeout = request.TimeoutSeconds > 0
            ? TimeSpan.FromSeconds(request.TimeoutSeconds)
            : _defaultTimeout;
            
        _logger?.LogDebug("设置请求超时: {Timeout}秒 - {Url}", timeout.TotalSeconds, request.Url);
        
        try
        {
            var task = _wrappee.SendRequestAsync(request);
            
            // 创建一个在指定超时后完成的任务
            var timeoutTask = Task.Delay(timeout);
            
            // 等待两个任务中的一个完成
            var completedTask = await Task.WhenAny(task, timeoutTask);
            
            if (completedTask == timeoutTask)
            {
                _logger?.LogWarning("请求超时 - {Url}", request.Url);
                return new ApiResponse
                {
                    IsSuccess = false,
                    StatusCode = 408, // Request Timeout
                    ErrorMessage = $"Request timed out after {timeout.TotalSeconds} seconds"
                };
            }
            
            // 请求在超时前完成
            return await task;
        }
        catch (Exception ex)
        {
            _logger?.LogError(ex, "请求处理中出错 - {Url}", request.Url);
            return new ApiResponse
            {
                IsSuccess = false,
                ErrorMessage = ex.Message
            };
        }
    }
}

// 10. 具体装饰器 - 负载均衡装饰器
public class LoadBalancingDecorator : ApiClientDecorator
{
    private readonly List<IApiClient> _clients;
    private readonly LoadBalancingStrategy _strategy;
    private readonly Random _random = new Random();
    private int _roundRobinIndex = 0;
    private readonly ILogger<LoadBalancingDecorator> _logger;
    
    public enum LoadBalancingStrategy
    {
        RoundRobin,
        Random
    }
    
    public LoadBalancingDecorator(
        IEnumerable<IApiClient> clients,
        LoadBalancingStrategy strategy = LoadBalancingStrategy.RoundRobin,
        ILogger<LoadBalancingDecorator> logger = null)
        : base(clients.First(), "负载均衡") // 基类需要一个client,但我们会忽略它
    {
        _clients = new List<IApiClient>(clients);
        _strategy = strategy;
        _logger = logger;
        
        if (_clients.Count == 0)
        {
            throw new ArgumentException("至少需要一个API客户端");
        }
    }
    
    public override async Task<ApiResponse> SendRequestAsync(ApiRequest request)
    {
        // 选择一个客户端
        IApiClient selectedClient = SelectClient();
        
        _logger?.LogDebug("使用负载均衡策略 {Strategy},选择客户端: {ClientName}",
            _strategy, selectedClient.GetClientName());
            
        return await selectedClient.SendRequestAsync(request);
    }
    
    private IApiClient SelectClient()
    {
        switch (_strategy)
        {
            case LoadBalancingStrategy.RoundRobin:
                lock (this) // 确保线程安全
                {
                    var client = _clients[_roundRobinIndex];
                    _roundRobinIndex = (_roundRobinIndex + 1) % _clients.Count;
                    return client;
                }
                
            case LoadBalancingStrategy.Random:
                return _clients[_random.Next(_clients.Count)];
                
            default:
                return _clients[0];
        }
    }
}

// 11. 客户端工厂 - 创建预配置的API客户端
public class ApiClientFactory
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<ApiClientFactory> _logger;
    
    public ApiClientFactory(IServiceProvider serviceProvider, ILogger<ApiClientFactory> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }
    
    // 创建基本HTTP客户端
    public IApiClient CreateBasicClient(string name = "基本客户端")
    {
        var httpClient = _serviceProvider.GetRequiredService<IHttpClientFactory>().CreateClient();
        return new BasicApiClient(httpClient, name);
    }
    
    // 创建带重试功能的客户端
    public IApiClient CreateRetryClient(
        string name = "重试客户端",
        int maxRetries = 3)
    {
        var baseClient = CreateBasicClient(name);
        var logger = _serviceProvider.GetRequiredService<ILogger<RetryDecorator>>();
        
        return new RetryDecorator(baseClient, maxRetries, logger: logger);
    }
    
    // 创建带缓存功能的客户端
    public IApiClient CreateCachingClient(
        string name = "缓存客户端",
        TimeSpan? cacheExpiration = null)
    {
        var baseClient = CreateBasicClient(name);
        var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
        var logger = _serviceProvider.GetRequiredService<ILogger<CachingDecorator>>();
        
        return new CachingDecorator(baseClient, cache, cacheExpiration, logger: logger);
    }
    
    // 创建带日志功能的客户端
    public IApiClient CreateLoggingClient(string name = "日志客户端")
    {
        var baseClient = CreateBasicClient(name);
        var logger = _serviceProvider.GetRequiredService<ILogger<LoggingDecorator>>();
        
        return new LoggingDecorator(baseClient, logger);
    }
    
    // 创建完整的REST API客户端(缓存+重试+日志+超时)
    public IApiClient CreateRestApiClient(string name = "REST客户端")
    {
        var baseClient = CreateBasicClient(name);
        
        // 添加日志装饰器
        var loggerDecorator = _serviceProvider.GetRequiredService<ILogger<LoggingDecorator>>();
        var clientWithLogging = new LoggingDecorator(baseClient, loggerDecorator);
        
        // 添加超时装饰器
        var timeoutLogger = _serviceProvider.GetRequiredService<ILogger<TimeoutDecorator>>();
        var clientWithTimeout = new TimeoutDecorator(clientWithLogging, logger: timeoutLogger);
        
        // 添加重试装饰器
        var retryLogger = _serviceProvider.GetRequiredService<ILogger<RetryDecorator>>();
        var clientWithRetry = new RetryDecorator(clientWithTimeout, logger: retryLogger);
        
        // 添加缓存装饰器
        var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
        var cacheLogger = _serviceProvider.GetRequiredService<ILogger<CachingDecorator>>();
        var clientWithCache = new CachingDecorator(clientWithRetry, cache, logger: cacheLogger);
        
        return clientWithCache;
    }
    
    // 创建企业级客户端(包含所有装饰器)
    public IApiClient CreateEnterpriseClient(
        string name = "企业客户端",
        Func<Task<string>> tokenProvider = null)
    {
        var baseClient = CreateBasicClient(name);
        
        // 添加日志装饰器
        var loggerDecorator = _serviceProvider.GetRequiredService<ILogger<LoggingDecorator>>();
        var client = new LoggingDecorator(baseClient, loggerDecorator, logResponseBody: true);
        
        // 添加超时装饰器
        var timeoutLogger = _serviceProvider.GetRequiredService<ILogger<TimeoutDecorator>>();
        client = new TimeoutDecorator(client, TimeSpan.FromSeconds(60), timeoutLogger);
        
        // 添加断路器装饰器
        var circuitBreakerLogger = _serviceProvider.GetRequiredService<ILogger<CircuitBreakerDecorator>>();
        client = new CircuitBreakerDecorator(client, 5, TimeSpan.FromMinutes(1), circuitBreakerLogger);
        
        // 添加重试装饰器
        var retryLogger = _serviceProvider.GetRequiredService<ILogger<RetryDecorator>>();
        client = new RetryDecorator(client, 3, TimeSpan.FromSeconds(2), logger: retryLogger);
        
        // 添加认证装饰器(如果提供了令牌提供程序)
        if (tokenProvider != null)
        {
            var authLogger = _serviceProvider.GetRequiredService<ILogger<AuthenticationDecorator>>();
            client = new AuthenticationDecorator(client, tokenProvider, logger: authLogger);
        }
        
        // 添加缓存装饰器
        var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
        var cacheLogger = _serviceProvider.GetRequiredService<ILogger<CachingDecorator>>();
        client = new CachingDecorator(client, cache, TimeSpan.FromMinutes(10), logger: cacheLogger);
        
        return client;
    }
    
    // 创建负载均衡客户端
    public IApiClient CreateLoadBalancedClient(
        int instanceCount = 3,
        LoadBalancingDecorator.LoadBalancingStrategy strategy = LoadBalancingDecorator.LoadBalancingStrategy.RoundRobin)
    {
        var clients = new List<IApiClient>();
        
        for (int i = 1; i <= instanceCount; i++)
        {
            clients.Add(CreateBasicClient($"实例{i}"));
        }
        
        var logger = _serviceProvider.GetRequiredService<ILogger<LoadBalancingDecorator>>();
        return new LoadBalancingDecorator(clients, strategy, logger);
    }
}

// 12. 示例服务 - 使用装饰过的API客户端
public class WeatherService
{
    private readonly IApiClient _apiClient;
    private readonly ILogger<WeatherService> _logger;
    
    public WeatherService(IApiClient apiClient, ILogger<WeatherService> logger)
    {
        _apiClient = apiClient;
        _logger = logger;
    }
    
    public async Task<WeatherForecast> GetWeatherForecastAsync(string city)
    {
        _logger.LogInformation("获取城市天气预报: {City}", city);
        
        var request = new ApiRequest
        {
            Url = $"https://api.example.com/weather?city={Uri.EscapeDataString(city)}",
            Method = HttpMethod.Get,
            TimeoutSeconds = 5
        };
        
        var response = await _apiClient.SendRequestAsync(request);
        
        if (!response.IsSuccess)
        {
            _logger.LogWarning("获取天气预报失败: {ErrorMessage}", response.ErrorMessage);
            return null;
        }
        
        try
        {
            var forecast = response.ParseContent<WeatherForecast>();
            _logger.LogInformation("成功获取天气预报,温度: {Temperature}°C", forecast.Temperature);
            return forecast;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "解析天气预报数据出错");
            return null;
        }
    }
    
    public async Task<bool> ReportWeatherAsync(WeatherReport report)
    {
        _logger.LogInformation("上报天气情况: {City}, {Temperature}°C", report.City, report.Temperature);
        
        var request = new ApiRequest
        {
            Url = "https://api.example.com/weather/report",
            Method = HttpMethod.Post,
            Body = JsonConvert.SerializeObject(report)
        };
        
        var response = await _apiClient.SendRequestAsync(request);
        
        if (response.IsSuccess)
        {
            _logger.LogInformation("天气情况上报成功");
            return true;
        }
        else
        {
            _logger.LogWarning("天气情况上报失败: {ErrorMessage}", response.ErrorMessage);
            return false;
        }
    }
}

// 数据模型
public class WeatherForecast
{
    public string City { get; set; }
    public double Temperature { get; set; }
    public string Condition { get; set; }
    public double Humidity { get; set; }
    public DateTime ForecastTime { get; set; }
}

public class WeatherReport
{
    public string City { get; set; }
    public double Temperature { get; set; }
    public string Condition { get; set; }
    public string ReportedBy { get; set; }
    public DateTime ReportTime { get; set; }
}

// 13. 应用示例 - 注册服务和使用装饰器
public class Program
{
    public static async Task Main(string[] args)
    {
        // 设置依赖注入
        var services = new ServiceCollection();
        
        // 添加日志
        services.AddLogging(builder =>
        {
            builder.AddConsole();
            builder.SetMinimumLevel(LogLevel.Debug);
        });
        
        // 添加内存缓存
        services.AddMemoryCache();
        
        // 添加HTTP客户端工厂
        services.AddHttpClient();
        
        // 注册API客户端工厂
        services.AddSingleton<ApiClientFactory>();
        
        // 注册各种API客户端
        services.AddSingleton(provider =>
        {
            var factory = provider.GetRequiredService<ApiClientFactory>();
            return factory.CreateRestApiClient();
        });
        
        // 注册天气服务
        services.AddScoped<WeatherService>();
        
        var serviceProvider = services.BuildServiceProvider();
        
        // 创建各种类型的客户端并测试
        await TestApiClientsAsync(serviceProvider);
    }
    
    private static async Task TestApiClientsAsync(ServiceProvider serviceProvider)
    {
        var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
        var factory = serviceProvider.GetRequiredService<ApiClientFactory>();
        
        // 创建基本客户端
        logger.LogInformation("\n=== 测试基本客户端 ===");
        var basicClient = factory.CreateBasicClient();
        await TestClientAsync(basicClient, logger);
        
        // 创建带日志的客户端
        logger.LogInformation("\n=== 测试带日志的客户端 ===");
        var loggingClient = factory.CreateLoggingClient();
        await TestClientAsync(loggingClient, logger);
        
        // 创建带缓存的客户端
        logger.LogInformation("\n=== 测试带缓存的客户端 ===");
        var cachingClient = factory.CreateCachingClient();
        await TestClientAsync(cachingClient, logger);
        logger.LogInformation("再次请求(应该从缓存获取)...");
        await TestClientAsync(cachingClient, logger);
        
        // 创建企业级客户端
        logger.LogInformation("\n=== 测试企业级客户端 ===");
        
        // 模拟令牌提供程序
        async Task<string> GetTokenAsync()
        {
            await Task.Delay(10); // 模拟异步操作
            return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
        }
        
        var enterpriseClient = factory.CreateEnterpriseClient(tokenProvider: GetTokenAsync);
        await TestClientAsync(enterpriseClient, logger);
        
        // 创建负载均衡客户端
        logger.LogInformation("\n=== 测试负载均衡客户端 ===");
        var loadBalancedClient = factory.CreateLoadBalancedClient(3);
        
        for (int i = 0; i < 5; i++)
        {
            logger.LogInformation($"请求 #{i+1}:");
            await TestClientAsync(loadBalancedClient, logger);
        }
        
        // 使用天气服务
        logger.LogInformation("\n=== 测试天气服务 ===");
        var weatherService = new WeatherService(enterpriseClient, 
            serviceProvider.GetRequiredService<ILogger<WeatherService>>());
            
        var forecast = await weatherService.GetWeatherForecastAsync("Beijing");
        
        // 模拟上报天气
        var report = new WeatherReport
        {
            City = "Shanghai",
            Temperature = 25.5,
            Condition = "Sunny",
            ReportedBy = "User123",
            ReportTime = DateTime.Now
        };
        
        var reportResult = await weatherService.ReportWeatherAsync(report);
        logger.LogInformation("天气上报结果: {Result}", reportResult ? "成功" : "失败");
    }
    
    private static async Task TestClientAsync(IApiClient client, ILogger logger)
    {
        logger.LogInformation("使用客户端: {ClientName}", client.GetClientName());
        
        var request = new ApiRequest
        {
            Url = "https://httpbin.org/get",
            Method = HttpMethod.Get
        };
        
        try
        {
            var response = await client.SendRequestAsync(request);
            
            if (response.IsSuccess)
            {
                logger.LogInformation("请求成功: HTTP {StatusCode}, 耗时: {RequestTime}ms", 
                    response.StatusCode, response.RequestTime.TotalMilliseconds);
            }
            else
            {
                logger.LogWarning("请求失败: {ErrorMessage}", response.ErrorMessage);
            }
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "请求处理时出错");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984

# 10. 外观模式

原理:
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

思路:

  1. 创建一个外观类,它封装了子系统的复杂性
  2. 外观类提供一个简单的接口给客户端使用
  3. 客户端通过外观类与子系统进行交互,而不是直接与子系统的各个组件交互

前辈经验:

  • 当需要简化复杂系统并提供一个简单接口时,使用外观模式
  • 外观模式有助于降低客户端和子系统之间的耦合度
  • 外观模式不会阻止客户端直接访问子系统,它只是提供了一个便捷的入口
  • 在系统重构过程中,外观模式可以提供向后兼容的接口
  • 外观可以分层使用,创建多个外观来对系统进行分组

业务场景:
视频转换系统,需要处理视频解码、处理和编码等复杂操作,但希望为用户提供简单的接口。

简单实现:

// 子系统类 - 视频文件
public class VideoFile
{
    private string _name;
    private string _codecType;
    
    public VideoFile(string name)
    {
        _name = name;
        _codecType = name.Substring(name.LastIndexOf(".") + 1);
    }
    
    public string GetName() => _name;
    public string GetCodecType() => _codecType;
}

// 子系统类 - 编解码工厂
public class CodecFactory
{
    public string Extract(VideoFile file)
    {
        string type = file.GetCodecType();
        if (type.Equals("mp4", StringComparison.OrdinalIgnoreCase))
        {
            Console.WriteLine("CodecFactory: 提取MP4音频...");
            return "MP4";
        }
        else if (type.Equals("avi", StringComparison.OrdinalIgnoreCase))
        {
            Console.WriteLine("CodecFactory: 提取AVI音频...");
            return "AVI";
        }
        else
        {
            Console.WriteLine("CodecFactory: 提取未知格式音频...");
            return "Unknown";
        }
    }
}

// 子系统类 - 具体编解码器
public class MPEG4CompressionCodec
{
    public string Type => "mp4";
    
    public void Compress(string filename)
    {
        Console.WriteLine($"MPEG4CompressionCodec: 压缩 {filename} 为MP4格式...");
    }
}

public class OggCompressionCodec
{
    public string Type => "ogg";
    
    public void Compress(string filename)
    {
        Console.WriteLine($"OggCompressionCodec: 压缩 {filename} 为OGG格式...");
    }
}

public class AVICompressionCodec
{
    public string Type => "avi";
    
    public void Compress(string filename)
    {
        Console.WriteLine($"AVICompressionCodec: 压缩 {filename} 为AVI格式...");
    }
}

// 子系统类 - 混音器
public class AudioMixer
{
    public void Fix(string audioFile)
    {
        Console.WriteLine($"AudioMixer: 处理音频文件 {audioFile}...");
    }
    
    public string Mix(string audioFile)
    {
        Console.WriteLine($"AudioMixer: 混音处理 {audioFile}...");
        return "mixed_" + audioFile;
    }
}

// 子系统类 - 位图渲染器
public class BitrateReader
{
    public string Read(string filename, string sourceCodec)
    {
        Console.WriteLine($"BitrateReader: 读取文件 {filename} 使用编解码器 {sourceCodec}...");
        return filename;
    }
    
    public string Convert(string buffer, string destinationCodec)
    {
        Console.WriteLine($"BitrateReader: 转换比特流使用编解码器 {destinationCodec}...");
        return buffer;
    }
}

// 外观类 - 视频转换器
public class VideoConverter
{
    public string ConvertVideo(string filename, string format)
    {
        Console.WriteLine($"VideoConverter: 开始转换文件 {filename} 到 {format} 格式");
        
        // 创建视频文件
        VideoFile file = new VideoFile(filename);
        
        // 提取源编解码器
        CodecFactory factory = new CodecFactory();
        string sourceCodec = factory.Extract(file);
        
        // 根据目标格式选择编解码器
        string destinationCodec;
        if (format.Equals("mp4", StringComparison.OrdinalIgnoreCase))
        {
            destinationCodec = new MPEG4CompressionCodec().Type;
        }
        else if (format.Equals("ogg", StringComparison.OrdinalIgnoreCase))
        {
            destinationCodec = new OggCompressionCodec().Type;
        }
        else
        {
            destinationCodec = new AVICompressionCodec().Type;
        }
        
        // 读取和转换比特流
        BitrateReader reader = new BitrateReader();
        string buffer = reader.Read(file.GetName(), sourceCodec);
        string result = reader.Convert(buffer, destinationCodec);
        
        // 混音处理
        AudioMixer mixer = new AudioMixer();
        mixer.Fix(result);
        result = mixer.Mix(result);
        
        // 构建输出文件名
        string outputFilename = file.GetName().Substring(0, file.GetName().LastIndexOf(".") + 1) + format;
        Console.WriteLine($"VideoConverter: 转换完成,输出文件: {outputFilename}");
        
        return outputFilename;
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        // 创建外观
        VideoConverter converter = new VideoConverter();
        
        // 通过外观简化复杂的视频转换过程
        string mp4Result = converter.ConvertVideo("wildlife.avi", "mp4");
        Console.WriteLine($"转换结果: {mp4Result}");
        
        Console.WriteLine();
        
        string oggResult = converter.ConvertVideo("vacation.mp4", "ogg");
        Console.WriteLine($"转换结果: {oggResult}");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

复杂实现:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

// 1. 视频处理子系统

// 视频文件类
public class VideoFile
{
    public string FilePath { get; }
    public string FileName => Path.GetFileName(FilePath);
    public string Extension => Path.GetExtension(FilePath).TrimStart('.');
    public long FileSize { get; }
    public TimeSpan Duration { get; private set; }
    public VideoFormat Format { get; private set; }
    public Dictionary<string, string> Metadata { get; private set; }
    
    public VideoFile(string filePath)
    {
        FilePath = filePath;
        
        if (File.Exists(filePath))
        {
            FileSize = new FileInfo(filePath).Length;
        }
        
        Metadata = new Dictionary<string, string>();
    }
    
    public void AnalyzeFile()
    {
        Console.WriteLine($"分析视频文件 {FileName}...");
        
        // 模拟文件分析过程
        Format = GetVideoFormat();
        Duration = SimulateDuration();
        Metadata = ExtractMetadata();
        
        Console.WriteLine($"文件分析完成: 格式={Format}, 时长={Duration}");
    }
    
    private VideoFormat GetVideoFormat()
    {
        // 基于扩展名判断格式(简化)
        switch (Extension.ToLower())
        {
            case "mp4": return VideoFormat.MP4;
            case "avi": return VideoFormat.AVI;
            case "mkv": return VideoFormat.MKV;
            case "mov": return VideoFormat.MOV;
            case "wmv": return VideoFormat.WMV;
            case "webm": return VideoFormat.WebM;
            default: return VideoFormat.Unknown;
        }
    }
    
    private TimeSpan SimulateDuration()
    {
        // 模拟确定视频时长
        Random random = new Random();
        return TimeSpan.FromSeconds(random.Next(30, 600));
    }
    
    private Dictionary<string, string> ExtractMetadata()
    {
        // 模拟从视频中提取元数据
        return new Dictionary<string, string>
        {
            { "encoder", "Sample Encoder" },
            { "creation_time", DateTime.Now.AddDays(-1).ToString() },
            { "resolution", "1920x1080" }
        };
    }
}

// 视频格式枚举
public enum VideoFormat
{
    Unknown,
    MP4,
    AVI,
    MKV,
    MOV,
    WMV,
    WebM,
    OGG
}

// 编解码器接口
public interface ICodec
{
    string Name { get; }
    VideoFormat Format { get; }
    void Decode(string inputPath, string outputPath);
    void Encode(string inputPath, string outputPath, VideoEncodingSettings settings);
}

// 视频编码设置
public class VideoEncodingSettings
{
    public int Bitrate { get; set; } = 1000; // kbps
    public string Resolution { get; set; } = "1280x720";
    public int FrameRate { get; set; } = 30;
    public int Quality { get; set; } = 80; // 0-100
    public Dictionary<string, string> AdvancedSettings { get; set; } = new Dictionary<string, string>();
}

// 具体编解码器实现
public class MP4Codec : ICodec
{
    public string Name => "H.264/AAC";
    public VideoFormat Format => VideoFormat.MP4;
    
    public void Decode(string inputPath, string outputPath)
    {
        Console.WriteLine($"MP4Codec: 解码 {Path.GetFileName(inputPath)} 使用 H.264/AAC...");
        // 模拟解码过程
    }
    
    public void Encode(string inputPath, string outputPath, VideoEncodingSettings settings)
    {
        Console.WriteLine($"MP4Codec: 编码为 MP4 格式,比特率={settings.Bitrate}kbps,分辨率={settings.Resolution}...");
        // 模拟编码过程
    }
}

public class AVICodec : ICodec
{
    public string Name => "MJPEG/PCM";
    public VideoFormat Format => VideoFormat.AVI;
    
    public void Decode(string inputPath, string outputPath)
    {
        Console.WriteLine($"AVICodec: 解码 {Path.GetFileName(inputPath)} 使用 MJPEG/PCM...");
        // 模拟解码过程
    }
    
    public void Encode(string inputPath, string outputPath, VideoEncodingSettings settings)
    {
        Console.WriteLine($"AVICodec: 编码为 AVI 格式,比特率={settings.Bitrate}kbps,分辨率={settings.Resolution}...");
        // 模拟编码过程
    }
}

public class WebMCodec : ICodec
{
    public string Name => "VP9/Opus";
    public VideoFormat Format => VideoFormat.WebM;
    
    public void Decode(string inputPath, string outputPath)
    {
        Console.WriteLine($"WebMCodec: 解码 {Path.GetFileName(inputPath)} 使用 VP9/Opus...");
        // 模拟解码过程
    }
    
    public void Encode(string inputPath, string outputPath, VideoEncodingSettings settings)
    {
        Console.WriteLine($"WebMCodec: 编码为 WebM 格式,比特率={settings.Bitrate}kbps,分辨率={settings.Resolution}...");
        // 模拟编码过程
    }
}

// 编解码器工厂
public class CodecFactory
{
    private readonly Dictionary<VideoFormat, ICodec> _codecMap;
    
    public CodecFactory()
    {
        _codecMap = new Dictionary<VideoFormat, ICodec>
        {
            { VideoFormat.MP4, new MP4Codec() },
            { VideoFormat.AVI, new AVICodec() },
            { VideoFormat.WebM, new WebMCodec() }
            // 可以添加更多编解码器
        };
    }
    
    public ICodec GetCodec(VideoFormat format)
    {
        if (_codecMap.TryGetValue(format, out ICodec codec))
        {
            return codec;
        }
        
        throw new NotSupportedException($"不支持的视频格式: {format}");
    }
    
    public ICodec GetCodecForFile(VideoFile file)
    {
        return GetCodec(file.Format);
    }
}

// 2. 音频处理子系统

// 音频处理器
public class AudioProcessor
{
    public void ExtractAudio(string videoPath, string audioPath)
    {
        Console.WriteLine($"AudioProcessor: 从视频 {Path.GetFileName(videoPath)} 中提取音频...");
        // 模拟音频提取过程
    }
    
    public void ProcessAudio(string inputPath, string outputPath, AudioProcessingSettings settings)
    {
        Console.WriteLine($"AudioProcessor: 处理音频 {Path.GetFileName(inputPath)}...");
        
        if (settings.NormalizeVolume)
        {
            Console.WriteLine("AudioProcessor: 音量标准化...");
        }
        
        if (settings.RemoveNoise)
        {
            Console.WriteLine("AudioProcessor: 降噪处理...");
        }
        
        if (settings.EnhanceBass)
        {
            Console.WriteLine("AudioProcessor: 增强低音...");
        }
        
        // 模拟音频处理过程
    }
    
    public void MergeAudioVideo(string videoPath, string audioPath, string outputPath)
    {
        Console.WriteLine($"AudioProcessor: 合并视频 {Path.GetFileName(videoPath)} 和音频 {Path.GetFileName(audioPath)}...");
        // 模拟音视频合并过程
    }
}

// 音频处理设置
public class AudioProcessingSettings
{
    public bool NormalizeVolume { get; set; } = true;
    public bool RemoveNoise { get; set; } = false;
    public bool EnhanceBass { get; set; } = false;
    public int Volume { get; set; } = 100; // 百分比
}

// 3. 视频过滤器子系统

// 视频过滤器接口
public interface IVideoFilter
{
    string Name { get; }
    void Apply(string inputPath, string outputPath, Dictionary<string, object> parameters);
}

// 具体过滤器实现
public class BrightnessContrastFilter : IVideoFilter
{
    public string Name => "亮度对比度";
    
    public void Apply(string inputPath, string outputPath, Dictionary<string, object> parameters)
    {
        int brightness = GetParameter<int>(parameters, "brightness", 0);
        int contrast = GetParameter<int>(parameters, "contrast", 0);
        
        Console.WriteLine($"BrightnessContrastFilter: 调整亮度 {brightness},对比度 {contrast}...");
        // 模拟应用过滤器
    }
}

public class ColorBalanceFilter : IVideoFilter
{
    public string Name => "色彩平衡";
    
    public void Apply(string inputPath, string outputPath, Dictionary<string, object> parameters)
    {
        int red = GetParameter<int>(parameters, "red", 0);
        int green = GetParameter<int>(parameters, "green", 0);
        int blue = GetParameter<int>(parameters, "blue", 0);
        
        Console.WriteLine($"ColorBalanceFilter: 调整红色 {red},绿色 {green},蓝色 {blue}...");
        // 模拟应用过滤器
    }
}

public class StabilizationFilter : IVideoFilter
{
    public string Name => "视频稳定";
    
    public void Apply(string inputPath, string outputPath, Dictionary<string, object> parameters)
    {
        int strength = GetParameter<int>(parameters, "strength", 50);
        
        Console.WriteLine($"StabilizationFilter: 应用视频稳定,强度 {strength}%...");
        // 模拟应用过滤器
    }
}

// 辅助方法
public static class FilterExtensions
{
    public static T GetParameter<T>(this Dictionary<string, object> parameters, string key, T defaultValue)
    {
        if (parameters != null && parameters.TryGetValue(key, out object value) && value is T typedValue)
        {
            return typedValue;
        }
        
        return defaultValue;
    }
}

// 过滤器管理器
public class FilterManager
{
    private readonly List<IVideoFilter> _availableFilters;
    
    public FilterManager()
    {
        _availableFilters = new List<IVideoFilter>
        {
            new BrightnessContrastFilter(),
            new ColorBalanceFilter(),
            new StabilizationFilter()
            // 可以添加更多过滤器
        };
    }
    
    public IEnumerable<IVideoFilter> GetAvailableFilters()
    {
        return _availableFilters;
    }
    
    public IVideoFilter GetFilter(string name)
    {
        return _availableFilters.FirstOrDefault(f => f.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
    }
    
    public void ApplyFilters(string inputPath, string outputPath, List<FilterSettings> filterSettings)
    {
        Console.WriteLine($"FilterManager: 应用 {filterSettings.Count} 个过滤器到视频 {Path.GetFileName(inputPath)}...");
        
        string tempInput = inputPath;
        string tempOutput = Path.GetTempFileName();
        
        for (int i = 0; i < filterSettings.Count; i++)
        {
            var settings = filterSettings[i];
            var filter = GetFilter(settings.FilterName);
            
            if (filter == null)
            {
                Console.WriteLine($"FilterManager: 找不到过滤器 '{settings.FilterName}',跳过...");
                continue;
            }
            
            filter.Apply(tempInput, tempOutput, settings.Parameters);
            
            if (i < filterSettings.Count - 1)
            {
                tempInput = tempOutput;
                tempOutput = Path.GetTempFileName();
            }
        }
        
        // 复制最终结果到输出路径
        Console.WriteLine($"FilterManager: 所有过滤器已应用,保存结果到 {Path.GetFileName(outputPath)}");
    }
}

// 过滤器设置
public class FilterSettings
{
    public string FilterName { get; set; }
    public Dictionary<string, object> Parameters { get; set; } = new Dictionary<string, object>();
}

// 4. 外观类 - 视频转换器
public class VideoConverter
{
    private readonly CodecFactory _codecFactory;
    private readonly AudioProcessor _audioProcessor;
    private readonly FilterManager _filterManager;
    
    public VideoConverter()
    {
        _codecFactory = new CodecFactory();
        _audioProcessor = new AudioProcessor();
        _filterManager = new FilterManager();
    }
    
    // 简单转换方法
    public string ConvertVideo(string inputPath, VideoFormat targetFormat)
    {
        return ConvertVideo(inputPath, targetFormat, new VideoEncodingSettings(), null, null);
    }
    
    // 完整转换方法
    public string ConvertVideo(
        string inputPath, 
        VideoFormat targetFormat,
        VideoEncodingSettings encodingSettings,
        AudioProcessingSettings audioSettings = null,
        List<FilterSettings> filterSettings = null)
    {
        Console.WriteLine($"VideoConverter: 开始转换视频 {Path.GetFileName(inputPath)} 到 {targetFormat} 格式");
        
        // 分析输入文件
        var inputVideo = new VideoFile(inputPath);
        inputVideo.AnalyzeFile();
        
        // 创建临时文件路径
        string tempDir = Path.Combine(Path.GetTempPath(), "VideoConverter");
        Directory.CreateDirectory(tempDir);
        
        string decodedVideoPath = Path.Combine(tempDir, "decoded_video.raw");
        string processedVideoPath = Path.Combine(tempDir, "processed_video.raw");
        string extractedAudioPath = Path.Combine(tempDir, "extracted_audio.raw");
        string processedAudioPath = Path.Combine(tempDir, "processed_audio.raw");
        
        // 获取源和目标编解码器
        ICodec sourceCodec = _codecFactory.GetCodecForFile(inputVideo);
        ICodec targetCodec = _codecFactory.GetCodec(targetFormat);
        
        try
        {
            // 1. 解码视频
            Console.WriteLine($"VideoConverter: 步骤 1 - 解码视频...");
            sourceCodec.Decode(inputPath, decodedVideoPath);
            
            // 2. 提取并处理音频
            string finalVideoPath = decodedVideoPath;
            if (audioSettings != null)
            {
                Console.WriteLine($"VideoConverter: 步骤 2 - 处理音频...");
                _audioProcessor.ExtractAudio(inputPath, extractedAudioPath);
                _audioProcessor.ProcessAudio(extractedAudioPath, processedAudioPath, audioSettings);
            }
            
            // 3. 应用视频过滤器
            if (filterSettings != null && filterSettings.Any())
            {
                Console.WriteLine($"VideoConverter: 步骤 3 - 应用视频过滤器...");
                _filterManager.ApplyFilters(decodedVideoPath, processedVideoPath, filterSettings);
                finalVideoPath = processedVideoPath;
            }
            
            // 4. 编码为目标格式
            Console.WriteLine($"VideoConverter: 步骤 4 - 编码为目标格式...");
            string outputFileName = Path.GetFileNameWithoutExtension(inputPath) + "." + targetFormat.ToString().ToLower();
            string outputPath = Path.Combine(Path.GetDirectoryName(inputPath), outputFileName);
            
            targetCodec.Encode(finalVideoPath, outputPath, encodingSettings);
            
            // 5. 合并音频(如果已处理)
            if (audioSettings != null)
            {
                Console.WriteLine($"VideoConverter: 步骤 5 - 合并处理后的音频...");
                string finalOutputPath = Path.Combine(Path.GetDirectoryName(inputPath), "merged_" + outputFileName);
                _audioProcessor.MergeAudioVideo(outputPath, processedAudioPath, finalOutputPath);
                outputPath = finalOutputPath;
            }
            
            Console.WriteLine($"VideoConverter: 转换完成,输出文件: {outputPath}");
            return outputPath;
        }
        finally
        {
            // 清理临时文件
            Console.WriteLine("VideoConverter: 清理临时文件...");
            try
            {
                if (File.Exists(decodedVideoPath)) File.Delete(decodedVideoPath);
                if (File.Exists(processedVideoPath)) File.Delete(processedVideoPath);
                if (File.Exists(extractedAudioPath)) File.Delete(extractedAudioPath);
                if (File.Exists(processedAudioPath)) File.Delete(processedAudioPath);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"VideoConverter: 清理临时文件时出错: {ex.Message}");
            }
        }
    }
    
    // 异步转换方法
    public async Task<string> ConvertVideoAsync(
        string inputPath, 
        VideoFormat targetFormat,
        VideoEncodingSettings encodingSettings,
        AudioProcessingSettings audioSettings = null,
        List<FilterSettings> filterSettings = null)
    {
        // 使用Task.Run将同步方法包装为异步
        return await Task.Run(() => ConvertVideo(
            inputPath, targetFormat, encodingSettings, audioSettings, filterSettings));
    }
    
    // 获取视频信息
    public VideoInfo GetVideoInfo(string videoPath)
    {
        Console.WriteLine($"VideoConverter: 获取视频信息 {Path.GetFileName(videoPath)}");
        
        var videoFile = new VideoFile(videoPath);
        videoFile.AnalyzeFile();
        
        return new VideoInfo
        {
            FileName = videoFile.FileName,
            FilePath = videoFile.FilePath,
            FileSize = videoFile.FileSize,
            Format = videoFile.Format,
            Duration = videoFile.Duration,
            Resolution = videoFile.Metadata.GetValueOrDefault("resolution", "未知"),
            Codec = _codecFactory.GetCodecForFile(videoFile).Name,
            Metadata = videoFile.Metadata
        };
    }
    
    // 提取视频缩略图
    public string ExtractThumbnail(string videoPath, TimeSpan position, string outputPath = null)
    {
        Console.WriteLine($"VideoConverter: 从视频 {Path.GetFileName(videoPath)} 提取缩略图,位置: {position}...");
        
        if (string.IsNullOrEmpty(outputPath))
        {
            outputPath = Path.Combine(
                Path.GetDirectoryName(videoPath),
                Path.GetFileNameWithoutExtension(videoPath) + "_thumbnail.jpg");
        }
        
        // 模拟提取缩略图
        Console.WriteLine($"VideoConverter: 缩略图已保存到 {outputPath}");
        
        return outputPath;
    }
    
    // 获取支持的视频格式
    public List<VideoFormat> GetSupportedFormats()
    {
        return Enum.GetValues(typeof(VideoFormat))
            .Cast<VideoFormat>()
            .Where(f => f != VideoFormat.Unknown)
            .ToList();
    }
    
    // 获取可用的视频过滤器
    public List<string> GetAvailableFilters()
    {
        return _filterManager.GetAvailableFilters().Select(f => f.Name).ToList();
    }
    
    // 创建一组标准的视频过滤器设置
    public List<FilterSettings> CreateEnhancementFilters()
    {
        return new List<FilterSettings>
        {
            new FilterSettings
            {
                FilterName = "亮度对比度",
                Parameters = new Dictionary<string, object>
                {
                    { "brightness", 5 },
                    { "contrast", 10 }
                }
            },
            new FilterSettings
            {
                FilterName = "色彩平衡",
                Parameters = new Dictionary<string, object>
                {
                    { "red", 5 },
                    { "green", 0 },
                    { "blue", 5 }
                }
            }
        };
    }
}

// 视频信息类
public class VideoInfo
{
    public string FileName { get; set; }
    public string FilePath { get; set; }
    public long FileSize { get; set; }
    public VideoFormat Format { get; set; }
    public TimeSpan Duration { get; set; }
    public string Resolution { get; set; }
    public string Codec { get; set; }
    public Dictionary<string, string> Metadata { get; set; }
    
    public override string ToString()
    {
        return $"文件名: {FileName}\n" +
               $"大小: {FormatFileSize(FileSize)}\n" +
               $"格式: {Format}\n" +
               $"编解码器: {Codec}\n" +
               $"时长: {Duration}\n" +
               $"分辨率: {Resolution}";
    }
    
    private string FormatFileSize(long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB", "TB" };
        double len = bytes;
        int order = 0;
        
        while (len >= 1024 && order < sizes.Length - 1)
        {
            order++;
            len /= 1024;
        }
        
        return $"{len:0.##} {sizes[order]}";
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        // 创建外观对象
        var converter = new VideoConverter();
        
        // 示例1:基本转换
        Console.WriteLine("===== 示例1:基本转换 =====");
        converter.ConvertVideo("wildlife.avi", VideoFormat.MP4);
        
        Console.WriteLine();
        
        // 示例2:带自定义设置的高级转换
        Console.WriteLine("===== 示例2:高级转换 =====");
        
        // 创建编码设置
        var encodingSettings = new VideoEncodingSettings
        {
            Bitrate = 2000,
            Resolution = "1920x1080",
            FrameRate = 30,
            Quality = 90
        };
        
        // 创建音频处理设置
        var audioSettings = new AudioProcessingSettings
        {
            NormalizeVolume = true,
            RemoveNoise = true,
            Volume = 90
        };
        
        // 创建过滤器设置
        var filterSettings = new List<FilterSettings>
        {
            new FilterSettings
            {
                FilterName = "亮度对比度",
                Parameters = new Dictionary<string, object>
                {
                    { "brightness", 10 },
                    { "contrast", 15 }
                }
            },
            new FilterSettings
            {
                FilterName = "视频稳定",
                Parameters = new Dictionary<string, object>
                {
                    { "strength", 75 }
                }
            }
        };
        
        // 执行高级转换
        converter.ConvertVideo("vacation.mov", VideoFormat.WebM, encodingSettings, audioSettings, filterSettings);
        
        Console.WriteLine();
        
        // 示例3:获取视频信息
        Console.WriteLine("===== 示例3:获取视频信息 =====");
        VideoInfo info = converter.GetVideoInfo("concert.mp4");
        Console.WriteLine(info);
        
        Console.WriteLine();
        
        // 示例4:提取缩略图
        Console.WriteLine("===== 示例4:提取缩略图 =====");
        converter.ExtractThumbnail("movie.mkv", TimeSpan.FromSeconds(30));
        
        Console.WriteLine();
        
        // 示例5:显示支持的格式和过滤器
        Console.WriteLine("===== 示例5:支持的格式和过滤器 =====");
        Console.WriteLine("支持的视频格式:");
        foreach (var format in converter.GetSupportedFormats())
        {
            Console.WriteLine($"- {format}");
        }
        
        Console.WriteLine("\n可用的视频过滤器:");
        foreach (var filter in converter.GetAvailableFilters())
        {
            Console.WriteLine($"- {filter}");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705

业务场景结合:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;

// 电子商务系统外观模式示例

// 1. 订单子系统

// 订单接口
public interface IOrderService
{
    Task<Order> GetOrderAsync(string orderId);
    Task<Order> CreateOrderAsync(OrderRequest request);
    Task<bool> CancelOrderAsync(string orderId, string reason);
    Task<Order> UpdateOrderStatusAsync(string orderId, OrderStatus status);
    Task<IEnumerable<Order>> GetUserOrdersAsync(string userId, int page = 1, int pageSize = 10);
}

// 订单模型
public class Order
{
    public string OrderId { get; set; }
    public string UserId { get; set; }
    public DateTime OrderDate { get; set; }
    public OrderStatus Status { get; set; }
    public List<OrderItem> Items { get; set; } = new List<OrderItem>();
    public Address ShippingAddress { get; set; }
    public PaymentInfo Payment { get; set; }
    public decimal Subtotal { get; set; }
    public decimal Tax { get; set; }
    public decimal ShippingCost { get; set; }
    public decimal Discount { get; set; }
    public decimal Total { get; set; }
    public string TrackingNumber { get; set; }
    public string CancellationReason { get; set; }
}

public class OrderItem
{
    public string ProductId { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal Subtotal => Quantity * UnitPrice;
}

public class Address
{
    public string FullName { get; set; }
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Country { get; set; }
    public string PhoneNumber { get; set; }
}

public class PaymentInfo
{
    public string PaymentId { get; set; }
    public string Method { get; set; }
    public decimal Amount { get; set; }
    public string Status { get; set; }
    public DateTime? ProcessedDate { get; set; }
}

public enum OrderStatus
{
    Created,
    PaymentPending,
    Paid,
    Processing,
    Shipped,
    Delivered,
    Cancelled,
    Refunded
}

// 订单请求
public class OrderRequest
{
    public string UserId { get; set; }
    public List<OrderItemRequest> Items { get; set; } = new List<OrderItemRequest>();
    public Address ShippingAddress { get; set; }
    public string PaymentMethod { get; set; }
    public string CouponCode { get; set; }
}

public class OrderItemRequest
{
    public string ProductId { get; set; }
    public int Quantity { get; set; }
}

// 订单服务实现
public class OrderService : IOrderService
{
    private readonly ILogger<OrderService> _logger;
    private readonly Dictionary<string, Order> _orders = new Dictionary<string, Order>();
    
    public OrderService(ILogger<OrderService> logger)
    {
        _logger = logger;
    }
    
    public async Task<Order> GetOrderAsync(string orderId)
    {
        _logger.LogInformation($"获取订单:{orderId}");
        
        if (_orders.TryGetValue(orderId, out Order order))
        {
            return order;
        }
        
        return null;
    }
    
    public async Task<Order> CreateOrderAsync(OrderRequest request)
    {
        _logger.LogInformation($"创建订单,用户:{request.UserId},商品数:{request.Items.Count}");
        
        var order = new Order
        {
            OrderId = GenerateOrderId(),
            UserId = request.UserId,
            OrderDate = DateTime.Now,
            Status = OrderStatus.Created,
            ShippingAddress = request.ShippingAddress,
            Items = await TransformOrderItems(request.Items)
        };
        
        // 计算订单金额
        CalculateOrderTotals(order);
        
        // 存储订单
        _orders[order.OrderId] = order;
        
        _logger.LogInformation($"订单已创建:{order.OrderId},总金额:${order.Total}");
        
        return order;
    }
    
    public async Task<bool> CancelOrderAsync(string orderId, string reason)
    {
        if (!_orders.TryGetValue(orderId, out Order order))
        {
            _logger.LogWarning($"取消订单失败,订单不存在:{orderId}");
            return false;
        }
        
        if (order.Status == OrderStatus.Shipped || order.Status == OrderStatus.Delivered)
        {
            _logger.LogWarning($"取消订单失败,订单已发货:{orderId}");
            return false;
        }
        
        order.Status = OrderStatus.Cancelled;
        order.CancellationReason = reason;
        
        _logger.LogInformation($"订单已取消:{orderId},原因:{reason}");
        
        return true;
    }
    
    public async Task<Order> UpdateOrderStatusAsync(string orderId, OrderStatus status)
    {
        if (!_orders.TryGetValue(orderId, out Order order))
        {
            _logger.LogWarning($"更新订单状态失败,订单不存在:{orderId}");
            return null;
        }
        
        order.Status = status;
        _logger.LogInformation($"订单状态已更新:{orderId} -> {status}");
        
        return order;
    }
    
    public async Task<IEnumerable<Order>> GetUserOrdersAsync(string userId, int page = 1, int pageSize = 10)
    {
        _logger.LogInformation($"获取用户订单:{userId},页码:{page},每页大小:{pageSize}");
        
        return _orders.Values
            .Where(o => o.UserId == userId)
            .OrderByDescending(o => o.OrderDate)
            .Skip((page - 1) * pageSize)
            .Take(pageSize);
    }
    
    private string GenerateOrderId()
    {
        return "ORD-" + Guid.NewGuid().ToString().Substring(0, 8).ToUpper();
    }
    
    private async Task<List<OrderItem>> TransformOrderItems(List<OrderItemRequest> items)
    {
        // 在实际应用中,这里会从产品服务获取产品详情
        var result = new List<OrderItem>();
        
        foreach (var item in items)
        {
            result.Add(new OrderItem
            {
                ProductId = item.ProductId,
                ProductName = $"Product {item.ProductId}",
                Quantity = item.Quantity,
                UnitPrice = 19.99m // 示例价格
            });
        }
        
        return result;
    }
    
    private void CalculateOrderTotals(Order order)
    {
        order.Subtotal = order.Items.Sum(i => i.Subtotal);
        order.Tax = Math.Round(order.Subtotal * 0.08m, 2); // 示例税率8%
        order.ShippingCost = 5.99m; // 示例运费
        order.Discount = 0; // 示例折扣
        order.Total = order.Subtotal + order.Tax + order.ShippingCost - order.Discount;
    }
}

// 2. 支付子系统

// 支付接口
public interface IPaymentService
{
    Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request);
    Task<PaymentResult> GetPaymentStatusAsync(string paymentId);
    Task<PaymentResult> RefundPaymentAsync(string paymentId, decimal amount, string reason);
}

// 支付模型
public class PaymentRequest
{
    public string OrderId { get; set; }
    public string UserId { get; set; }
    public decimal Amount { get; set; }
    public string PaymentMethod { get; set; }
    public Dictionary<string, string> PaymentDetails { get; set; } = new Dictionary<string, string>();
}

public class PaymentResult
{
    public bool Success { get; set; }
    public string PaymentId { get; set; }
    public string Status { get; set; }
    public string ErrorMessage { get; set; }
    public DateTime ProcessedDate { get; set; }
    public Dictionary<string, string> AdditionalInfo { get; set; } = new Dictionary<string, string>();
}

// 支付服务实现
public class PaymentService : IPaymentService
{
    private readonly ILogger<PaymentService> _logger;
    private readonly Dictionary<string, PaymentResult> _payments = new Dictionary<string, PaymentResult>();
    
    public PaymentService(ILogger<PaymentService> logger)
    {
        _logger = logger;
    }
    
    public async Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request)
    {
        _logger.LogInformation($"处理支付,订单:{request.OrderId},金额:${request.Amount},方法:{request.PaymentMethod}");
        
        // 模拟处理支付过程
        var result = new PaymentResult
        {
            Success = true,
            PaymentId = "PMT-" + Guid.NewGuid().ToString().Substring(0, 8).ToUpper(),
            Status = "Completed",
            ProcessedDate = DateTime.Now
        };
        
        _payments[result.PaymentId] = result;
        
        _logger.LogInformation($"支付处理成功:{result.PaymentId}");
        
        return result;
    }
    
    public async Task<PaymentResult> GetPaymentStatusAsync(string paymentId)
    {
        _logger.LogInformation($"获取支付状态:{paymentId}");
        
        if (_payments.TryGetValue(paymentId, out PaymentResult result))
        {
            return result;
        }
        
        return new PaymentResult
        {
            Success = false,
            ErrorMessage = "Payment not found"
        };
    }
    
    public async Task<PaymentResult> RefundPaymentAsync(string paymentId, decimal amount, string reason)
    {
        _logger.LogInformation($"处理退款,支付ID:{paymentId},金额:${amount},原因:{reason}");
        
        if (!_payments.TryGetValue(paymentId, out PaymentResult payment))
        {
            _logger.LogWarning($"退款失败,支付不存在:{paymentId}");
            
            return new PaymentResult
            {
                Success = false,
                ErrorMessage = "Payment not found"
            };
        }
        
        // 模拟退款处理
        var result = new PaymentResult
        {
            Success = true,
            PaymentId = "REF-" + Guid.NewGuid().ToString().Substring(0, 8).ToUpper(),
            Status = "Refunded",
            ProcessedDate = DateTime.Now,
            AdditionalInfo = new Dictionary<string, string>
            {
                { "OriginalPaymentId", paymentId },
                { "RefundAmount", amount.ToString() },
                { "RefundReason", reason }
            }
        };
        
        _payments[result.PaymentId] = result;
        
        _logger.LogInformation($"退款处理成功:{result.PaymentId}");
        
        return result;
    }
}

// 3. 库存子系统

// 库存接口
public interface IInventoryService
{
    Task<bool> CheckStockAsync(string productId, int quantity);
    Task<bool> ReserveStockAsync(string orderId, List<OrderItem> items);
    Task<bool> ReleaseStockAsync(string orderId);
    Task<bool> ConfirmStockReleaseAsync(string orderId);
    Task<InventoryStatus> GetProductStockAsync(string productId);
}

// 库存模型
public class InventoryStatus
{
    public string ProductId { get; set; }
    public int Available { get; set; }
    public int Reserved { get; set; }
    public bool InStock => Available > 0;
    public string WarehouseLocation { get; set; }
    public DateTime LastUpdated { get; set; }
}

// 库存服务实现
public class InventoryService : IInventoryService
{
    private readonly ILogger<InventoryService> _logger;
    private readonly Dictionary<string, InventoryStatus> _inventory = new Dictionary<string, InventoryStatus>();
    private readonly Dictionary<string, List<OrderItem>> _reservations = new Dictionary<string, List<OrderItem>>();
    
    public InventoryService(ILogger<InventoryService> logger)
    {
        _logger = logger;
        InitializeInventory();
    }
    
    private void InitializeInventory()
    {
        // 初始化模拟库存数据
        for (int i = 1; i <= 10; i++)
        {
            string productId = "PROD-" + i.ToString("D3");
            _inventory[productId] = new InventoryStatus
            {
                ProductId = productId,
                Available = 100,
                Reserved = 0,
                WarehouseLocation = "WH-" + (i % 3 + 1),
                LastUpdated = DateTime.Now
            };
        }
    }
    
    public async Task<bool> CheckStockAsync(string productId, int quantity)
    {
        _logger.LogInformation($"检查库存,产品:{productId},数量:{quantity}");
        
        if (!_inventory.TryGetValue(productId, out InventoryStatus status))
        {
            _logger.LogWarning($"检查库存失败,产品不存在:{productId}");
            return false;
        }
        
        bool available = status.Available >= quantity;
        _logger.LogInformation($"库存检查结果:{(available ? "充足" : "不足")},产品:{productId},可用:{status.Available},需要:{quantity}");
        
        return available;
    }
    
    public async Task<bool> ReserveStockAsync(string orderId, List<OrderItem> items)
    {
        _logger.LogInformation($"预留库存,订单:{orderId},商品数:{items.Count}");
        
        // 首先检查所有商品的库存是否充足
        foreach (var item in items)
        {
            if (!await CheckStockAsync(item.ProductId, item.Quantity))
            {
                _logger.LogWarning($"预留库存失败,库存不足,产品:{item.ProductId}");
                return false;
            }
        }
        
        // 预留库存
        foreach (var item in items)
        {
            var status = _inventory[item.ProductId];
            status.Available -= item.Quantity;
            status.Reserved += item.Quantity;
            status.LastUpdated = DateTime.Now;
        }
        
        // 记录预留
        _reservations[orderId] = items;
        
        _logger.LogInformation($"库存已预留,订单:{orderId}");
        
        return true;
    }
    
    public async Task<bool> ReleaseStockAsync(string orderId)
    {
        _logger.LogInformation($"释放库存,订单:{orderId}");
        
        if (!_reservations.TryGetValue(orderId, out List<OrderItem> items))
        {
            _logger.LogWarning($"释放库存失败,订单不存在:{orderId}");
            return false;
        }
        
        // 释放库存
        foreach (var item in items)
        {
            if (_inventory.TryGetValue(item.ProductId, out InventoryStatus status))
            {
                status.Available += item.Quantity;
                status.Reserved -= item.Quantity;
                status.LastUpdated = DateTime.Now;
            }
        }
        
        // 删除预留记录
        _reservations.Remove(orderId);
        
        _logger.LogInformation($"库存已释放,订单:{orderId}");
        
        return true;
    }
    
    public async Task<bool> ConfirmStockReleaseAsync(string orderId)
    {
        _logger.LogInformation($"确认库存释放,订单:{orderId}");
        
        if (!_reservations.TryGetValue(orderId, out List<OrderItem> items))
        {
            _logger.LogWarning($"确认库存释放失败,订单不存在:{orderId}");
            return false;
        }
        
        // 从预留中移除,但不增加可用库存(因为商品已经出库)
        foreach (var item in items)
        {
            if (_inventory.TryGetValue(item.ProductId, out InventoryStatus status))
            {
                status.Reserved -= item.Quantity;
                status.LastUpdated = DateTime.Now;
            }
        }
        
        // 删除预留记录
        _reservations.Remove(orderId);
        
        _logger.LogInformation($"库存释放已确认,订单:{orderId}");
        
        return true;
    }
    
    public async Task<InventoryStatus> GetProductStockAsync(string productId)
    {
        _logger.LogInformation($"获取产品库存,产品:{productId}");
        
        if (_inventory.TryGetValue(productId, out InventoryStatus status))
        {
            return status;
        }
        
        return null;
    }
}

// 4. 物流子系统

// 物流接口
public interface IShippingService
{
    Task<ShippingQuote> GetShippingQuoteAsync(Address destination, List<OrderItem> items, string shippingMethod);
    Task<ShippingResult> CreateShippingLabelAsync(string orderId, Address destination, List<OrderItem> items);
    Task<ShipmentStatus> GetShipmentStatusAsync(string trackingNumber);
}

// 物流模型
public class ShippingQuote
{
    public decimal Cost { get; set; }
    public string Method { get; set; }
    public TimeSpan EstimatedDeliveryTime { get; set; }
    public bool Available { get; set; }
    public string Carrier { get; set; }
}

public class ShippingResult
{
    public bool Success { get; set; }
    public string TrackingNumber { get; set; }
    public string ShippingLabel { get; set; }
    public DateTime ShippingDate { get; set; }
    public DateTime EstimatedDeliveryDate { get; set; }
    public string Carrier { get; set; }
    public string ErrorMessage { get; set; }
}

public class ShipmentStatus
{
    public string TrackingNumber { get; set; }
    public string Status { get; set; }
    public string CurrentLocation { get; set; }
    public DateTime LastUpdate { get; set; }
    public List<ShipmentEvent> Events { get; set; } = new List<ShipmentEvent>();
}

public class ShipmentEvent
{
    public string Description { get; set; }
    public string Location { get; set; }
    public DateTime Timestamp { get; set; }
}

// 物流服务实现
public class ShippingService : IShippingService
{
    private readonly ILogger<ShippingService> _logger;
    private readonly Dictionary<string, ShipmentStatus> _shipments = new Dictionary<string, ShipmentStatus>();
    
    public ShippingService(ILogger<ShippingService> logger)
    {
        _logger = logger;
    }
    
    public async Task<ShippingQuote> GetShippingQuoteAsync(Address destination, List<OrderItem> items, string shippingMethod)
    {
        _logger.LogInformation($"获取运费报价,配送方式:{shippingMethod},目的地:{destination.City}, {destination.State}");
        
        // 根据配送方式设置不同的价格和时间
        decimal baseCost;
        TimeSpan deliveryTime;
        string carrier;
        
        switch (shippingMethod.ToLower())
        {
            case "standard":
                baseCost = 5.99m;
                deliveryTime = TimeSpan.FromDays(5);
                carrier = "PostalService";
                break;
            case "express":
                baseCost = 12.99m;
                deliveryTime = TimeSpan.FromDays(2);
                carrier = "FedEx";
                break;
            case "overnight":
                baseCost = 24.99m;
                deliveryTime = TimeSpan.FromDays(1);
                carrier = "UPS";
                break;
            default:
                baseCost = 5.99m;
                deliveryTime = TimeSpan.FromDays(5);
                carrier = "PostalService";
                break;
        }
        
        // 根据物品数量和重量调整价格(简化)
        int totalItems = items.Sum(i => i.Quantity);
        decimal additionalCost = totalItems > 5 ? (totalItems - 5) * 0.5m : 0;
        
        return new ShippingQuote
        {
            Cost = baseCost + additionalCost,
            Method = shippingMethod,
            EstimatedDeliveryTime = deliveryTime,
            Available = true,
            Carrier = carrier
        };
    }
    
    public async Task<ShippingResult> CreateShippingLabelAsync(string orderId, Address destination, List<OrderItem> items)
    {
        _logger.LogInformation($"创建配送标签,订单:{orderId},目的地:{destination.City}, {destination.State}");
        
        // 生成跟踪号
        string trackingNumber = "TRK-" + Guid.NewGuid().ToString().Substring(0, 8).ToUpper();
        
        // 创建配送结果
        var result = new ShippingResult
        {
            Success = true,
            TrackingNumber = trackingNumber,
            ShippingLabel = $"LABEL-{orderId}-{trackingNumber}",
            ShippingDate = DateTime.Now,
            EstimatedDeliveryDate = DateTime.Now.AddDays(3),
            Carrier = "FedEx"
        };
        
        // 创建初始配送状态
        var status = new ShipmentStatus
        {
            TrackingNumber = trackingNumber,
            Status = "Created",
            CurrentLocation = "Sorting Facility",
            LastUpdate = DateTime.Now,
            Events = new List<ShipmentEvent>
            {
                new ShipmentEvent
                {
                    Description = "Shipping label created",
                    Location = "Sorting Facility",
                    Timestamp = DateTime.Now
                }
            }
        };
        
        _shipments[trackingNumber] = status;
        
        _logger.LogInformation($"配送标签已创建,订单:{orderId},跟踪号:{trackingNumber}");
        
        return result;
    }
    
    public async Task<ShipmentStatus> GetShipmentStatusAsync(string trackingNumber)
    {
        _logger.LogInformation($"获取配送状态,跟踪号:{trackingNumber}");
        
        if (_shipments.TryGetValue(trackingNumber, out ShipmentStatus status))
        {
            return status;
        }
        
        return new ShipmentStatus
        {
            TrackingNumber = trackingNumber,
            Status = "Not Found",
            LastUpdate = DateTime.Now
        };
    }
}

// 5. 通知子系统

// 通知接口
public interface INotificationService
{
    Task SendOrderConfirmationAsync(Order order);
    Task SendShippingUpdateAsync(string orderId, string trackingNumber, string status);
    Task SendPaymentConfirmationAsync(string orderId, PaymentResult payment);
    Task SendOrderCancellationAsync(string orderId, string reason);
}

// 通知模型
public class NotificationRequest
{
    public string UserId { get; set; }
    public string Subject { get; set; }
    public string Message { get; set; }
    public string NotificationType { get; set; }
    public Dictionary<string, string> Data { get; set; } = new Dictionary<string, string>();
}

// 通知服务实现
public class NotificationService : INotificationService
{
    private readonly ILogger<NotificationService> _logger;
    
    public NotificationService(ILogger<NotificationService> logger)
    {
        _logger = logger;
    }
    
    public async Task SendOrderConfirmationAsync(Order order)
    {
        _logger.LogInformation($"发送订单确认通知,订单:{order.OrderId},用户:{order.UserId}");
        
        var request = new NotificationRequest
        {
            UserId = order.UserId,
            Subject = $"订单确认 #{order.OrderId}",
            Message = $"您的订单 #{order.OrderId} 已确认,总金额:${order.Total}。感谢您的购买!",
            NotificationType = "OrderConfirmation",
            Data = new Dictionary<string, string>
            {
                { "OrderId", order.OrderId },
                { "OrderDate", order.OrderDate.ToString() },
                { "Total", order.Total.ToString() }
            }
        };
        
        await SendNotificationAsync(request);
    }
    
    public async Task SendShippingUpdateAsync(string orderId, string trackingNumber, string status)
    {
        _logger.LogInformation($"发送配送更新通知,订单:{orderId},状态:{status}");
        
        var request = new NotificationRequest
        {
            // 在实际场景中,会根据订单ID查询用户ID
            UserId = "USER-001",
            Subject = $"配送更新:订单 #{orderId}",
            Message = $"您的订单 #{orderId} 的配送状态已更新为 {status}。跟踪号:{trackingNumber}",
            NotificationType = "ShippingUpdate",
            Data = new Dictionary<string, string>
            {
                { "OrderId", orderId },
                { "TrackingNumber", trackingNumber },
                { "Status", status }
            }
        };
        
        await SendNotificationAsync(request);
    }
    
    public async Task SendPaymentConfirmationAsync(string orderId, PaymentResult payment)
    {
        _logger.LogInformation($"发送支付确认通知,订单:{orderId},支付ID:{payment.PaymentId}");
        
        var request = new NotificationRequest
        {
            // 在实际场景中,会根据订单ID查询用户ID
            UserId = "USER-001",
            Subject = $"支付确认:订单 #{orderId}",
            Message = $"您对订单 #{orderId} 的支付已确认。支付ID:{payment.PaymentId}",
            NotificationType = "PaymentConfirmation",
            Data = new Dictionary<string, string>
            {
                { "OrderId", orderId },
                { "PaymentId", payment.PaymentId },
                { "Status", payment.Status },
                { "Date", payment.ProcessedDate.ToString() }
            }
        };
        
        await SendNotificationAsync(request);
    }
    
    public async Task SendOrderCancellationAsync(string orderId, string reason)
    {
        _logger.LogInformation($"发送订单取消通知,订单:{orderId},原因:{reason}");
        
        var request = new NotificationRequest
        {
            // 在实际场景中,会根据订单ID查询用户ID
            UserId = "USER-001",
            Subject = $"订单取消:#{orderId}",
            Message = $"您的订单 #{orderId} 已被取消。原因:{reason}",
            NotificationType = "OrderCancellation",
            Data = new Dictionary<string, string>
            {
                { "OrderId", orderId },
                { "Reason", reason },
                { "Date", DateTime.Now.ToString() }
            }
        };
        
        await SendNotificationAsync(request);
    }
    
    private async Task SendNotificationAsync(NotificationRequest request)
    {
        // 在实际场景中,这里会根据用户偏好选择通知渠道(邮件、短信、推送等)
        _logger.LogInformation($"发送通知:{request.NotificationType},用户:{request.UserId},主题:{request.Subject}");
        
        // 模拟发送通知的延迟
        await Task.Delay(100);
        
        _logger.LogInformation($"通知已发送:{request.NotificationType},用户:{request.UserId}");
    }
}

// 6. 外观类 - 电子商务服务
public class ECommerceService
{
    private readonly IOrderService _orderService;
    private readonly IPaymentService _paymentService;
    private readonly IInventoryService _inventoryService;
    private readonly IShippingService _shippingService;
    private readonly INotificationService _notificationService;
    private readonly ILogger<ECommerceService> _logger;
    
    public ECommerceService(
        IOrderService orderService,
        IPaymentService paymentService,
        IInventoryService inventoryService,
        IShippingService shippingService,
        INotificationService notificationService,
        ILogger<ECommerceService> logger)
    {
        _orderService = orderService;
        _paymentService = paymentService;
        _inventoryService = inventoryService;
        _shippingService = shippingService;
        _notificationService = notificationService;
        _logger = logger;
    }
    
    // 简化的下单流程
    public async Task<OrderResult> PlaceOrderAsync(OrderRequest request)
    {
        _logger.LogInformation($"开始下单流程,用户:{request.UserId}");
        
        try
        {
            // 1. 检查库存
            foreach (var item in request.Items)
            {
                if (!await _inventoryService.CheckStockAsync(item.ProductId, item.Quantity))
                {
                    return new OrderResult
                    {
                        Success = false,
                        ErrorMessage = $"产品 {item.ProductId} 库存不足"
                    };
                }
            }
            
            // 2. 创建订单
            var order = await _orderService.CreateOrderAsync(request);
            
            // 3. 预留库存
            bool stockReserved = await _inventoryService.ReserveStockAsync(order.OrderId, order.Items);
            if (!stockReserved)
            {
                return new OrderResult
                {
                    Success = false,
                    ErrorMessage = "无法预留库存"
                };
            }
            
            // 4. 处理支付
            var paymentRequest = new PaymentRequest
            {
                OrderId = order.OrderId,
                UserId = order.UserId,
                Amount = order.Total,
                PaymentMethod = request.PaymentMethod
            };
            
            var paymentResult = await _paymentService.ProcessPaymentAsync(paymentRequest);
            if (!paymentResult.Success)
            {
                // 支付失败,释放库存
                await _inventoryService.ReleaseStockAsync(order.OrderId);
                
                return new OrderResult
                {
                    Success = false,
                    ErrorMessage = $"支付失败:{paymentResult.ErrorMessage}"
                };
            }
            
            // 5. 更新订单状态为已支付
            order.Payment = new PaymentInfo
            {
                PaymentId = paymentResult.PaymentId,
                Method = request.PaymentMethod,
                Amount = order.Total,
                Status = paymentResult.Status,
                ProcessedDate = paymentResult.ProcessedDate
            };
            
            order = await _orderService.UpdateOrderStatusAsync(order.OrderId, OrderStatus.Paid);
            
            // 6. 发送订单确认通知
            await _notificationService.SendOrderConfirmationAsync(order);
            
            // 7. 发送支付确认通知
            await _notificationService.SendPaymentConfirmationAsync(order.OrderId, paymentResult);
            
            return new OrderResult
            {
                Success = true,
                OrderId = order.OrderId,
                Total = order.Total
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"下单过程中出错:{ex.Message}");
            
            return new OrderResult
            {
                Success = false,
                ErrorMessage = $"处理订单时出错:{ex.Message}"
            };
        }
    }
    
    // 发货流程
    public async Task<ShippingResult> ShipOrderAsync(string orderId)
    {
        _logger.LogInformation($"开始发货流程,订单:{orderId}");
        
        try
        {
            // 1. 获取订单信息
            var order = await _orderService.GetOrderAsync(orderId);
            if (order == null)
            {
                _logger.LogWarning($"发货失败,订单不存在:{orderId}");
                return new ShippingResult { Success = false, ErrorMessage = "订单不存在" };
            }
            
            if (order.Status != OrderStatus.Paid && order.Status != OrderStatus.Processing)
            {
                _logger.LogWarning($"发货失败,订单状态不正确:{order.Status}");
                return new ShippingResult { Success = false, ErrorMessage = $"订单状态 {order.Status} 不允许发货" };
            }
            
            // 2. 确认库存释放
            await _inventoryService.ConfirmStockReleaseAsync(orderId);
            
            // 3. 创建物流标签
            var shippingResult = await _shippingService.CreateShippingLabelAsync(
                orderId, order.ShippingAddress, order.Items);
            
            if (!shippingResult.Success)
            {
                return shippingResult;
            }
            
            // 4. 更新订单状态和跟踪号
            order.TrackingNumber = shippingResult.TrackingNumber;
            await _orderService.UpdateOrderStatusAsync(orderId, OrderStatus.Shipped);
            
            // 5. 发送配送更新通知
            await _notificationService.SendShippingUpdateAsync(
                orderId, shippingResult.TrackingNumber, "Shipped");
            
            return shippingResult;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"发货过程中出错:{ex.Message}");
            
            return new ShippingResult
            {
                Success = false,
                ErrorMessage = $"处理发货时出错:{ex.Message}"
            };
        }
    }
    
    // 取消订单流程
    public async Task<bool> CancelOrderAsync(string orderId, string reason)
    {
        _logger.LogInformation($"开始取消订单流程,订单:{orderId},原因:{reason}");
        
        try
        {
            // 1. 获取订单信息
            var order = await _orderService.GetOrderAsync(orderId);
            if (order == null)
            {
                _logger.LogWarning($"取消订单失败,订单不存在:{orderId}");
                return false;
            }
            
            // 2. 检查订单是否可以取消
            if (order.Status == OrderStatus.Shipped || order.Status == OrderStatus.Delivered)
            {
                _logger.LogWarning($"取消订单失败,订单已发货:{orderId}");
                return false;
            }
            
            // 3. 释放库存
            await _inventoryService.ReleaseStockAsync(orderId);
            
            // 4. 如果已支付,则处理退款
            if (order.Status == OrderStatus.Paid || order.Status == OrderStatus.Processing)
            {
                await _paymentService.RefundPaymentAsync(
                    order.Payment.PaymentId, order.Total, reason);
                
                await _orderService.UpdateOrderStatusAsync(orderId, OrderStatus.Refunded);
            }
            else
            {
                // 5. 更新订单状态为已取消
                await _orderService.CancelOrderAsync(orderId, reason);
            }
            
            // 6. 发送订单取消通知
            await _notificationService.SendOrderCancellationAsync(orderId, reason);
            
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"取消订单过程中出错:{ex.Message}");
            return false;
        }
    }
    
    // 查询订单状态 - 包括订单、支付和配送信息
    public async Task<OrderStatusInfo> GetOrderStatusAsync(string orderId)
    {
        _logger.LogInformation($"获取订单状态,订单:{orderId}");
        
        var statusInfo = new OrderStatusInfo { OrderId = orderId };
        
        try
        {
            // 1. 获取订单信息
            var order = await _orderService.GetOrderAsync(orderId);
            if (order == null)
            {
                statusInfo.Status = "NotFound";
                return statusInfo;
            }
            
            statusInfo.Order = order;
            statusInfo.Status = order.Status.ToString();
            
            // 2. 获取支付信息
            if (order.Payment != null)
            {
                statusInfo.PaymentStatus = order.Payment.Status;
            }
            
            // 3. 获取配送信息
            if (!string.IsNullOrEmpty(order.TrackingNumber))
            {
                var shipmentStatus = await _shippingService.GetShipmentStatusAsync(order.TrackingNumber);
                statusInfo.ShipmentStatus = shipmentStatus;
            }
            
            return statusInfo;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"获取订单状态时出错:{ex.Message}");
            
            statusInfo.Status = "Error";
            statusInfo.ErrorMessage = $"获取订单状态时出错:{ex.Message}";
            
            return statusInfo;
        }
    }
    
    // 获取用户订单历史
    public async Task<List<Order>> GetUserOrderHistoryAsync(string userId, int page = 1, int pageSize = 10)
    {
        _logger.LogInformation($"获取用户订单历史,用户:{userId},页码:{page}");
        
        try
        {
            var orders = await _orderService.GetUserOrdersAsync(userId, page, pageSize);
            return orders.ToList();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"获取用户订单历史时出错:{ex.Message}");
            return new List<Order>();
        }
    }
    
    // 获取商品库存状态
    public async Task<InventoryStatus> GetProductStockAsync(string productId)
    {
        _logger.LogInformation($"获取商品库存状态,商品:{productId}");
        
        try
        {
            return await _inventoryService.GetProductStockAsync(productId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"获取商品库存状态时出错:{ex.Message}");
            return null;
        }
    }
    
    // 获取运费报价
    public async Task<ShippingQuote> GetShippingQuoteAsync(string userId, List<OrderItemRequest> items, Address destination, string shippingMethod)
    {
        _logger.LogInformation($"获取运费报价,用户:{userId},配送方式:{shippingMethod}");
        
        try
        {
            // 转换订单项格式
            var orderItems = new List<OrderItem>();
            foreach (var item in items)
            {
                orderItems.Add(new OrderItem
                {
                    ProductId = item.ProductId,
                    Quantity = item.Quantity,
                    ProductName = $"Product {item.ProductId}",
                    UnitPrice = 19.99m // 示例价格
                });
            }
            
            return await _shippingService.GetShippingQuoteAsync(destination, orderItems, shippingMethod);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"获取运费报价时出错:{ex.Message}");
            
            return new ShippingQuote
            {
                Available = false,
                Method = shippingMethod
            };
        }
    }
}

// 订单结果模型
public class OrderResult
{
    public bool Success { get; set; }
    public string OrderId { get; set; }
    public decimal Total { get; set; }
    public string ErrorMessage { get; set; }
}

// 订单状态信息
public class OrderStatusInfo
{
    public string OrderId { get; set; }
    public string Status { get; set; }
    public Order Order { get; set; }
    public string PaymentStatus { get; set; }
    public ShipmentStatus ShipmentStatus { get; set; }
    public string ErrorMessage { get; set; }
}

// 7. 控制器 - API端点
public class ECommerceController
{
    private readonly ECommerceService _ecommerceService;
    private readonly ILogger<ECommerceController> _logger;
    
    public ECommerceController(ECommerceService ecommerceService, ILogger<ECommerceController> logger)
    {
        _ecommerceService = ecommerceService;
        _logger = logger;
    }
    
    public async Task<OrderResult> PlaceOrder(OrderRequest request)
    {
        _logger.LogInformation($"API调用:下单,用户:{request.UserId}");
        return await _ecommerceService.PlaceOrderAsync(request);
    }
    
    public async Task<ShippingResult> ShipOrder(string orderId)
    {
        _logger.LogInformation($"API调用:发货,订单:{orderId}");
        return await _ecommerceService.ShipOrderAsync(orderId);
    }
    
    public async Task<bool> CancelOrder(string orderId, string reason)
    {
        _logger.LogInformation($"API调用:取消订单,订单:{orderId}");
        return await _ecommerceService.CancelOrderAsync(orderId, reason);
    }
    
    public async Task<OrderStatusInfo> GetOrderStatus(string orderId)
    {
        _logger.LogInformation($"API调用:获取订单状态,订单:{orderId}");
        return await _ecommerceService.GetOrderStatusAsync(orderId);
    }
    
    public async Task<List<Order>> GetUserOrderHistory(string userId, int page = 1, int pageSize = 10)
    {
        _logger.LogInformation($"API调用:获取用户订单历史,用户:{userId}");
        return await _ecommerceService.GetUserOrderHistoryAsync(userId, page, pageSize);
    }
    
    public async Task<InventoryStatus> GetProductStock(string productId)
    {
        _logger.LogInformation($"API调用:获取商品库存,商品:{productId}");
        return await _ecommerceService.GetProductStockAsync(productId);
    }
    
    public async Task<ShippingQuote> GetShippingQuote(string userId, List<OrderItemRequest> items, Address destination, string shippingMethod)
    {
        _logger.LogInformation($"API调用:获取运费报价,用户:{userId}");
        return await _ecommerceService.GetShippingQuoteAsync(userId, items, destination, shippingMethod);
    }
}

// 8. 客户端程序
public class Program
{
    public static async Task Main(string[] args)
    {
        // 设置依赖注入
        var services = new ServiceCollection();
        
        // 添加日志
        services.AddLogging(builder =>
        {
            builder.AddConsole();
            builder.SetMinimumLevel(LogLevel.Information);
        });
        
        // 注册服务
        services.AddSingleton<IOrderService, OrderService>();
        services.AddSingleton<IPaymentService, PaymentService>();
        services.AddSingleton<IInventoryService, InventoryService>();
        services.AddSingleton<IShippingService, ShippingService>();
        services.AddSingleton<INotificationService, NotificationService>();
        services.AddSingleton<ECommerceService>();
        services.AddSingleton<ECommerceController>();
        
        var serviceProvider = services.BuildServiceProvider();
        
        // 创建控制器
        var controller = serviceProvider.GetRequiredService<ECommerceController>();
        var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
        
        // 演示电子商务系统
        await DemoECommerceSystem(controller, logger);
    }
    
    private static async Task DemoECommerceSystem(ECommerceController controller, ILogger logger)
    {
        try
        {
            // 1. 创建示例订单
            logger.LogInformation("=== 下单演示 ===");
            
            var address = new Address
            {
                FullName = "John Doe",
                Street = "123 Main St",
                City = "New York",
                State = "NY",
                ZipCode = "10001",
                Country = "USA",
                PhoneNumber = "555-123-4567"
            };
            
            var orderRequest = new OrderRequest
            {
                UserId = "USER-001",
                Items = new List<OrderItemRequest>
                {
                    new OrderItemRequest { ProductId = "PROD-001", Quantity = 2 },
                    new OrderItemRequest { ProductId = "PROD-002", Quantity = 1 }
                },
                ShippingAddress = address,
                PaymentMethod = "CreditCard",
                CouponCode = "WELCOME10"
            };
            
            var orderResult = await controller.PlaceOrder(orderRequest);
            
            if (orderResult.Success)
            {
                logger.LogInformation($"订单创建成功:{orderResult.OrderId},总金额:${orderResult.Total}");
                
                // 2. 获取订单状态
                logger.LogInformation("\n=== 查询订单状态 ===");
                var statusInfo = await controller.GetOrderStatus(orderResult.OrderId);
                logger.LogInformation($"订单状态:{statusInfo.Status},支付状态:{statusInfo.PaymentStatus}");
                
                // 3. 发货订单
                logger.LogInformation("\n=== 发货订单 ===");
                var shippingResult = await controller.ShipOrder(orderResult.OrderId);
                
                if (shippingResult.Success)
                {
                    logger.LogInformation($"订单发货成功,跟踪号:{shippingResult.TrackingNumber}");
                    
                    // 4. 再次查询订单状态
                    logger.LogInformation("\n=== 再次查询订单状态 ===");
                    statusInfo = await controller.GetOrderStatus(orderResult.OrderId);
                    logger.LogInformation($"订单状态:{statusInfo.Status}");
                    logger.LogInformation($"配送状态:{statusInfo.ShipmentStatus?.Status},位置:{statusInfo.ShipmentStatus?.CurrentLocation}");
                }
                else
                {
                    logger.LogError($"订单发货失败:{shippingResult.ErrorMessage}");
                }
                
                // 5. 创建第二个订单并取消
                logger.LogInformation("\n=== 创建并取消订单 ===");
                var orderRequest2 = new OrderRequest
                {
                    UserId = "USER-001",
                    Items = new List<OrderItemRequest>
                    {
                        new OrderItemRequest { ProductId = "PROD-003", Quantity = 1 }
                    },
                    ShippingAddress = address,
                    PaymentMethod = "PayPal"
                };
                
                var orderResult2 = await controller.PlaceOrder(orderRequest2);
                
                if (orderResult2.Success)
                {
                    logger.LogInformation($"第二个订单创建成功:{orderResult2.OrderId}");
                    
                    // 取消订单
                    bool cancelled = await controller.CancelOrder(orderResult2.OrderId, "客户要求取消");
                    
                    if (cancelled)
                    {
                        logger.LogInformation($"订单 {orderResult2.OrderId} 已成功取消");
                        
                        // 查询已取消订单的状态
                        var cancelledStatus = await controller.GetOrderStatus(orderResult2.OrderId);
                        logger.LogInformation($"已取消订单状态:{cancelledStatus.Status}");
                    }
                    else
                    {
                        logger.LogError($"取消订单 {orderResult2.OrderId} 失败");
                    }
                }
                
                // 6. 获取用户订单历史
                logger.LogInformation("\n=== 获取用户订单历史 ===");
                var orders = await controller.GetUserOrderHistory("USER-001");
                logger.LogInformation($"用户有 {orders.Count} 个订单");
                
                foreach (var order in orders)
                {
                    logger.LogInformation($"- 订单 {order.OrderId},状态:{order.Status},金额:${order.Total}");
                }
                
                // 7. 获取运费报价
                logger.LogInformation("\n=== 获取运费报价 ===");
                var quoteItems = new List<OrderItemRequest>
                {
                    new OrderItemRequest { ProductId = "PROD-001", Quantity = 3 }
                };
                
                var standardQuote = await controller.GetShippingQuote("USER-001", quoteItems, address, "Standard");
                var expressQuote = await controller.GetShippingQuote("USER-001", quoteItems, address, "Express");
                
                logger.LogInformation($"标准配送:${standardQuote.Cost},预计 {standardQuote.EstimatedDeliveryTime.Days} 天");
                logger.LogInformation($"快速配送:${expressQuote.Cost},预计 {expressQuote.EstimatedDeliveryTime.Days} 天");
            }
            else
            {
                logger.LogError($"订单创建失败:{orderResult.ErrorMessage}");
            }
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "演示过程中出错");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392

# 11. 享元模式

原理:
享元模式通过共享技术有效地支持大量细粒度的对象。它通过识别对象中可共享的部分,将这些部分提取出来作为享元对象,然后在多个场景中重用这些享元对象,从而减少内存使用。

思路:

  1. 将对象划分为内部状态(可共享)和外部状态(不可共享)
  2. 创建享元工厂,管理享元对象池
  3. 客户端通过工厂获取享元对象,并提供外部状态

前辈经验:

  • 当系统中存在大量相似对象,导致内存占用过高时,使用享元模式
  • 享元对象的内部状态应该是不可变的,确保多个上下文可以安全地共享它们
  • 享元模式的效果取决于共享的程度,如果外部状态占主导,效果可能不明显
  • 识别内部状态和外部状态是享元模式设计的关键挑战
  • 享元模式通常与组合模式一起使用,形成更复杂的结构

业务场景:
文本编辑器中的字符渲染系统,需要处理大量字符但每种字体和大小的字符可以共享相同的渲染信息。

简单实现:

// 享元接口
public interface ICharacter
{
    void Display(int size, string fontFamily, ConsoleColor color, int x, int y);
}

// 具体享元类
public class Character : ICharacter
{
    private char _symbol;
    
    public Character(char symbol)
    {
        _symbol = symbol;
        // 模拟加载字符资源(耗时操作)
        Console.WriteLine($"创建字符 '{_symbol}' 的渲染资源");
    }
    
    public void Display(int size, string fontFamily, ConsoleColor color, int x, int y)
    {
        // 这里使用外部状态(size, fontFamily, color, x, y)和内部状态(symbol)
        Console.ForegroundColor = color;
        Console.WriteLine($"在位置({x},{y})绘制字符 '{_symbol}',字体: {fontFamily},大小: {size}");
        Console.ResetColor();
    }
}

// 享元工厂
public class CharacterFactory
{
    private readonly Dictionary<char, ICharacter> _characters = new Dictionary<char, ICharacter>();
    
    public ICharacter GetCharacter(char symbol)
    {
        // 如果字符已存在,返回缓存的实例,否则创建新实例
        if (!_characters.ContainsKey(symbol))
        {
            _characters[symbol] = new Character(symbol);
            Console.WriteLine($"创建并缓存字符 '{symbol}'");
        }
        else
        {
            Console.WriteLine($"重用已缓存的字符 '{symbol}'");
        }
        
        return _characters[symbol];
    }
    
    public int CharacterCount => _characters.Count;
}

// 客户端
public class TextEditor
{
    private readonly CharacterFactory _factory;
    
    public TextEditor()
    {
        _factory = new CharacterFactory();
    }
    
    public void RenderText(string text, int size, string fontFamily, ConsoleColor color)
    {
        Console.WriteLine($"渲染文本: \"{text}\" (字体: {fontFamily}, 大小: {size})");
        
        int x = 0, y = 0;
        foreach (char c in text)
        {
            if (c == '\n')
            {
                y++;
                x = 0;
                continue;
            }
            
            ICharacter character = _factory.GetCharacter(c);
            character.Display(size, fontFamily, color, x, y);
            x++;
        }
        
        Console.WriteLine($"使用了 {_factory.CharacterCount} 个字符对象(而不是 {text.Length} 个)");
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        TextEditor editor = new TextEditor();
        
        // 渲染第一段文本
        editor.RenderText("Hello, World!", 12, "Arial", ConsoleColor.Blue);
        
        Console.WriteLine();
        
        // 渲染第二段文本(重用一些相同的字符)
        editor.RenderText("Hello, Flyweight Pattern!", 14, "Times New Roman", ConsoleColor.Green);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

复杂实现:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Linq;

// 1. 定义享元接口
public interface ITextFormatting
{
    void Render(char character, Point position, Color color, float opacity);
    Size GetSize();
    bool SupportsStyle(FontStyle style);
}

// 2. 内部状态 - 字体信息(可共享)
public class FontData
{
    public string FontFamily { get; }
    public int Size { get; }
    public FontStyle Style { get; }
    public bool IsCached { get; }
    
    private readonly Dictionary<char, FontMetrics> _metricsCache = new Dictionary<char, FontMetrics>();
    
    public FontData(string fontFamily, int size, FontStyle style)
    {
        FontFamily = fontFamily;
        Size = size;
        Style = style;
        IsCached = true;
        
        // 模拟加载字体资源(耗时操作)
        Console.WriteLine($"加载字体: {fontFamily}, 大小: {size}, 样式: {style}");
        Thread.Sleep(50); // 模拟加载延迟
    }
    
    public FontMetrics GetMetricsForCharacter(char c)
    {
        if (!_metricsCache.TryGetValue(c, out var metrics))
        {
            // 模拟计算字符度量信息(耗时操作)
            metrics = GenerateMetrics(c);
            _metricsCache[c] = metrics;
        }
        
        return metrics;
    }
    
    private FontMetrics GenerateMetrics(char c)
    {
        // 模拟为每个字符生成度量信息
        Random random = new Random(c.GetHashCode());
        return new FontMetrics
        {
            Width = Size / 2 + random.Next(Size / 4),
            Height = Size,
            Baseline = Size * 0.8f,
            LeftBearing = -Size * 0.05f,
            RightBearing = Size * 0.05f
        };
    }
}

// 字符度量信息
public class FontMetrics
{
    public int Width { get; set; }
    public int Height { get; set; }
    public float Baseline { get; set; }
    public float LeftBearing { get; set; }
    public float RightBearing { get; set; }
}

// 3. 具体享元类 - 字体渲染器
public class FontRenderer : ITextFormatting
{
    private readonly FontData _fontData;
    private readonly byte[] _renderingData; // 模拟渲染数据
    
    public FontRenderer(string fontFamily, int size, FontStyle style)
    {
        _fontData = new FontData(fontFamily, size, style);
        
        // 模拟创建渲染数据
        _renderingData = new byte[size * 100]; // 假设的数据大小
        new Random().NextBytes(_renderingData);
        
        Console.WriteLine($"创建字体渲染器: {fontFamily}, 大小: {size}, 样式: {style}");
    }
    
    public void Render(char character, Point position, Color color, float opacity)
    {
        // 获取字符的度量信息
        var metrics = _fontData.GetMetricsForCharacter(character);
        
        // 模拟渲染过程
        Console.WriteLine($"渲染字符 '{character}' 在位置({position.X},{position.Y})," +
                          $"颜色: {color.Name},透明度: {opacity:P}," +
                          $"使用字体: {_fontData.FontFamily}, 大小: {_fontData.Size}");
    }
    
    public Size GetSize()
    {
        return new Size(_fontData.Size, _fontData.Size);
    }
    
    public bool SupportsStyle(FontStyle style)
    {
        return _fontData.Style.HasFlag(style);
    }
    
    public FontData GetFontData()
    {
        return _fontData;
    }
}

// 4. 外部状态 - 字符渲染上下文
public class CharacterContext
{
    public char Character { get; set; }
    public Point Position { get; set; }
    public Color Color { get; set; }
    public float Opacity { get; set; }
}

// 5. 享元工厂
public class TextFormattingFactory
{
    private readonly Dictionary<string, ITextFormatting> _formatters = new Dictionary<string, ITextFormatting>();
    
    public ITextFormatting GetTextFormatting(string fontFamily, int size, FontStyle style)
    {
        // 创建键以标识唯一的字体配置
        string key = $"{fontFamily}_{size}_{style}";
        
        if (!_formatters.TryGetValue(key, out var formatter))
        {
            formatter = new FontRenderer(fontFamily, size, style);
            _formatters[key] = formatter;
            Console.WriteLine($"创建并缓存新的字体格式: {key}");
        }
        else
        {
            Console.WriteLine($"重用已缓存的字体格式: {key}");
        }
        
        return formatter;
    }
    
    public int FormatterCount => _formatters.Count;
    
    public IEnumerable<KeyValuePair<string, ITextFormatting>> GetAllFormatters()
    {
        return _formatters.ToList();
    }
}

// 6. 文本布局引擎
public class TextLayoutEngine
{
    private readonly TextFormattingFactory _formattingFactory;
    
    public TextLayoutEngine()
    {
        _formattingFactory = new TextFormattingFactory();
    }
    
    public void RenderParagraph(string text, TextStyle style, Rectangle bounds)
    {
        Console.WriteLine($"渲染段落: \"{text}\"");
        Console.WriteLine($"边界: ({bounds.X},{bounds.Y},{bounds.Width},{bounds.Height})");
        
        // 获取字体格式化器
        var formatter = _formattingFactory.GetTextFormatting(
            style.FontFamily, style.FontSize, style.FontStyle);
        
        // 计算布局
        int x = bounds.X;
        int y = bounds.Y;
        int lineHeight = formatter.GetSize().Height;
        
        // 逐字符渲染
        foreach (char c in text)
        {
            if (c == '\n' || x > bounds.Right)
            {
                y += lineHeight;
                x = bounds.X;
                
                if (c == '\n')
                    continue;
            }
            
            // 创建字符上下文(外部状态)
            var context = new CharacterContext
            {
                Character = c,
                Position = new Point(x, y),
                Color = style.TextColor,
                Opacity = style.Opacity
            };
            
            // 渲染字符
            formatter.Render(context.Character, context.Position, context.Color, context.Opacity);
            
            // 更新位置
            x += formatter.GetSize().Width / 2; // 简化的宽度计算
        }
        
        Console.WriteLine($"使用了 {_formattingFactory.FormatterCount} 个字体格式化器");
    }
    
    public void RenderFormattedText(FormattedText formattedText, Rectangle bounds)
    {
        Console.WriteLine($"渲染格式化文本,包含 {formattedText.Spans.Count} 个格式化片段");
        
        int x = bounds.X;
        int y = bounds.Y;
        int maxLineHeight = 0;
        
        foreach (var span in formattedText.Spans)
        {
            // 获取字体格式化器
            var formatter = _formattingFactory.GetTextFormatting(
                span.Style.FontFamily, span.Style.FontSize, span.Style.FontStyle);
            
            // 检查行高
            int spanHeight = formatter.GetSize().Height;
            maxLineHeight = Math.Max(maxLineHeight, spanHeight);
            
            // 逐字符渲染
            foreach (char c in span.Text)
            {
                if (c == '\n' || x > bounds.Right)
                {
                    y += maxLineHeight;
                    x = bounds.X;
                    maxLineHeight = spanHeight;
                    
                    if (c == '\n')
                        continue;
                }
                
                // 创建字符上下文
                var context = new CharacterContext
                {
                    Character = c,
                    Position = new Point(x, y),
                    Color = span.Style.TextColor,
                    Opacity = span.Style.Opacity
                };
                
                // 渲染字符
                formatter.Render(context.Character, context.Position, context.Color, context.Opacity);
                
                // 更新位置
                x += formatter.GetSize().Width / 2;
            }
        }
    }
    
    public TextMetrics CalculateTextMetrics(string text, TextStyle style)
    {
        var formatter = _formattingFactory.GetTextFormatting(
            style.FontFamily, style.FontSize, style.FontStyle);
        
        // 计算文本度量信息
        int width = 0;
        int height = formatter.GetSize().Height;
        int lines = 1;
        
        foreach (char c in text)
        {
            if (c == '\n')
            {
                lines++;
                continue;
            }
            
            width += formatter.GetSize().Width / 2;
        }
        
        return new TextMetrics
        {
            Width = width,
            Height = height * lines,
            Lines = lines
        };
    }
    
    public void PrintCacheStatistics()
    {
        Console.WriteLine("\n--- 缓存统计 ---");
        Console.WriteLine($"缓存的字体格式化器: {_formattingFactory.FormatterCount}");
        
        foreach (var entry in _formattingFactory.GetAllFormatters())
        {
            Console.WriteLine($"- {entry.Key}");
        }
    }
}

// 7. 文本样式类
public class TextStyle
{
    public string FontFamily { get; set; } = "Arial";
    public int FontSize { get; set; } = 12;
    public FontStyle FontStyle { get; set; } = FontStyle.Regular;
    public Color TextColor { get; set; } = Color.Black;
    public float Opacity { get; set; } = 1.0f;
}

// 8. 格式化文本类
public class FormattedText
{
    public List<TextSpan> Spans { get; } = new List<TextSpan>();
    
    public void AddSpan(string text, TextStyle style)
    {
        Spans.Add(new TextSpan { Text = text, Style = style });
    }
}

public class TextSpan
{
    public string Text { get; set; }
    public TextStyle Style { get; set; }
}

// 9. 文本度量信息
public class TextMetrics
{
    public int Width { get; set; }
    public int Height { get; set; }
    public int Lines { get; set; }
}

// 10. 客户端代码
public class RichTextEditor
{
    private TextLayoutEngine _layoutEngine;
    
    public RichTextEditor()
    {
        _layoutEngine = new TextLayoutEngine();
    }
    
    public void RenderSampleDocument()
    {
        Console.WriteLine("=== 渲染样例文档 ===\n");
        
        // 样例1:基本段落
        var normalStyle = new TextStyle
        {
            FontFamily = "Arial",
            FontSize = 12,
            TextColor = Color.Black
        };
        
        _layoutEngine.RenderParagraph(
            "这是一个使用享元模式的文本编辑器示例。该模式通过共享重复的字体渲染资源来节省内存。",
            normalStyle,
            new Rectangle(10, 10, 400, 200));
        
        Console.WriteLine();
        
        // 样例2:包含相同字符的文本
        var headingStyle = new TextStyle
        {
            FontFamily = "Times New Roman",
            FontSize = 18,
            FontStyle = FontStyle.Bold,
            TextColor = Color.DarkBlue
        };
        
        _layoutEngine.RenderParagraph(
            "享元模式 - Flyweight Pattern Example",
            headingStyle,
            new Rectangle(10, 60, 400, 200));
        
        Console.WriteLine();
        
        // 样例3:混合格式文本
        var formattedText = new FormattedText();
        
        formattedText.AddSpan("这是", normalStyle);
        
        var emphasizedStyle = new TextStyle
        {
            FontFamily = "Arial",
            FontSize = 12,
            FontStyle = FontStyle.Italic,
            TextColor = Color.Red
        };
        
        formattedText.AddSpan("强调的", emphasizedStyle);
        
        var boldStyle = new TextStyle
        {
            FontFamily = "Arial",
            FontSize = 12,
            FontStyle = FontStyle.Bold,
            TextColor = Color.Black
        };
        
        formattedText.AddSpan("文本", boldStyle);
        
        _layoutEngine.RenderFormattedText(formattedText, new Rectangle(10, 100, 400, 200));
        
        // 显示缓存统计
        _layoutEngine.PrintCacheStatistics();
    }
    
    public void RenderLargeText()
    {
        Console.WriteLine("\n=== 渲染大量文本 ===\n");
        
        // 创建一个包含重复字符的大文本
        Random random = new Random();
        char[] characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
        int textLength = 1000;
        
        StringBuilder sb = new StringBuilder(textLength);
        for (int i = 0; i < textLength; i++)
        {
            char c = characters[random.Next(characters.Length)];
            sb.Append(c);
            
            // 每50个字符添加换行
            if ((i + 1) % 50 == 0)
                sb.Append('\n');
        }
        
        string largeText = sb.ToString();
        
        // 创建多种样式
        var styles = new[]
        {
            new TextStyle { FontFamily = "Arial", FontSize = 10, TextColor = Color.Black },
            new TextStyle { FontFamily = "Times New Roman", FontSize = 10, TextColor = Color.Blue },
            new TextStyle { FontFamily = "Courier New", FontSize = 10, TextColor = Color.Green }
        };
        
        // 按段落渲染大文本
        int startIndex = 0;
        int styleIndex = 0;
        
        while (startIndex < largeText.Length)
        {
            int length = Math.Min(100, largeText.Length - startIndex);
            string paragraph = largeText.Substring(startIndex, length);
            
            _layoutEngine.RenderParagraph(
                paragraph,
                styles[styleIndex % styles.Length],
                new Rectangle(10, 10 + styleIndex * 20, 400, 200));
                
            startIndex += length;
            styleIndex++;
            
            // 限制输出数量
            if (styleIndex >= 3)
                break;
        }
        
        Console.WriteLine("\n(输出被截断...)");
        
        // 显示缓存统计
        _layoutEngine.PrintCacheStatistics();
        
        // 计算内存节省
        int totalCharacters = largeText.Length;
        int uniqueCharacters = largeText.Distinct().Count();
        
        Console.WriteLine($"\n总字符数: {totalCharacters}");
        Console.WriteLine($"不同字符数: {uniqueCharacters}");
        Console.WriteLine($"理论内存节省: {((1.0 - (double)uniqueCharacters / totalCharacters) * 100):F2}%");
    }
    
    public void CalculateTextMetrics()
    {
        Console.WriteLine("\n=== 计算文本度量 ===\n");
        
        var normalStyle = new TextStyle { FontFamily = "Arial", FontSize = 12 };
        var headingStyle = new TextStyle { FontFamily = "Arial", FontSize = 20, FontStyle = FontStyle.Bold };
        
        var normalText = "这是一个普通段落文本示例。";
        var headingText = "这是标题文本";
        var multilineText = "这是多行文本示例,\n包含换行符,\n共三行。";
        
        var normalMetrics = _layoutEngine.CalculateTextMetrics(normalText, normalStyle);
        var headingMetrics = _layoutEngine.CalculateTextMetrics(headingText, headingStyle);
        var multilineMetrics = _layoutEngine.CalculateTextMetrics(multilineText, normalStyle);
        
        Console.WriteLine($"普通文本: 宽度={normalMetrics.Width}, 高度={normalMetrics.Height}, 行数={normalMetrics.Lines}");
        Console.WriteLine($"标题文本: 宽度={headingMetrics.Width}, 高度={headingMetrics.Height}, 行数={headingMetrics.Lines}");
        Console.WriteLine($"多行文本: 宽度={multilineMetrics.Width}, 高度={multilineMetrics.Height}, 行数={multilineMetrics.Lines}");
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        RichTextEditor editor = new RichTextEditor();
        
        // 渲染样例文档
        editor.RenderSampleDocument();
        
        // 渲染大量文本
        editor.RenderLargeText();
        
        // 计算文本度量
        editor.CalculateTextMetrics();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518

业务场景结合:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;

// 地图渲染系统 - 使用享元模式处理大量地图图块

// 1. 地图图块内部状态(可共享)
public class TerrainType
{
    public string Name { get; }
    public string TextureFile { get; }
    public float MovementCost { get; }
    public bool IsWalkable { get; }
    public bool IsWater { get; }
    public byte[] TextureData { get; } // 模拟纹理数据
    
    public TerrainType(string name, string textureFile, float movementCost, bool isWalkable, bool isWater)
    {
        Name = name;
        TextureFile = textureFile;
        MovementCost = movementCost;
        IsWalkable = isWalkable;
        IsWater = isWater;
        
        // 模拟加载纹理数据
        TextureData = new byte[1024 * 16]; // 假设每个纹理约16KB
        new Random().NextBytes(TextureData);
        
        Console.WriteLine($"加载地形纹理: {name} ({TextureFile}) - 大小: {TextureData.Length / 1024}KB");
    }
}

// 2. 图块享元接口
public interface IMapTile
{
    void Render(int x, int y, float scale, float brightness);
    bool CanMoveThrough(string unitType);
    TerrainType GetTerrainType();
    string GetDebugInfo();
}

// 3. 具体享元 - 地图图块
public class MapTile : IMapTile
{
    private readonly TerrainType _terrainType;
    
    public MapTile(TerrainType terrainType)
    {
        _terrainType = terrainType;
    }
    
    public void Render(int x, int y, float scale, float brightness)
    {
        // 使用内部状态(terrainType)和外部状态(x, y, scale, brightness)渲染图块
        Console.WriteLine($"渲染 {_terrainType.Name} 在位置({x},{y}),缩放: {scale:F1},亮度: {brightness:F1}");
    }
    
    public bool CanMoveThrough(string unitType)
    {
        if (!_terrainType.IsWalkable)
            return false;
            
        // 根据单位类型和地形判断是否可通过
        switch (unitType)
        {
            case "Infantry":
                return true;
            case "Vehicle":
                return !_terrainType.IsWater;
            case "Ship":
                return _terrainType.IsWater;
            case "Aircraft":
                return true;
            default:
                return _terrainType.IsWalkable;
        }
    }
    
    public TerrainType GetTerrainType()
    {
        return _terrainType;
    }
    
    public string GetDebugInfo()
    {
        return $"{_terrainType.Name} (移动成本: {_terrainType.MovementCost}, 可通行: {_terrainType.IsWalkable})";
    }
}

// 4. 享元工厂 - 地形工厂
public class TerrainFactory
{
    private readonly Dictionary<string, TerrainType> _terrainTypes = new Dictionary<string, TerrainType>();
    private readonly Dictionary<string, IMapTile> _tiles = new Dictionary<string, IMapTile>();
    private readonly ILogger<TerrainFactory> _logger;
    
    public TerrainFactory(ILogger<TerrainFactory> logger = null)
    {
        _logger = logger;
        InitializeTerrainTypes();
    }
    
    private void InitializeTerrainTypes()
    {
        // 预定义常见地形类型
        AddTerrainType("grass", "textures/grass.png", 1.0f, true, false);
        AddTerrainType("water", "textures/water.png", 2.5f, false, true);
        AddTerrainType("mountain", "textures/mountain.png", 3.0f, false, false);
        AddTerrainType("road", "textures/road.png", 0.8f, true, false);
        AddTerrainType("forest", "textures/forest.png", 1.5f, true, false);
        AddTerrainType("desert", "textures/desert.png", 1.2f, true, false);
        AddTerrainType("snow", "textures/snow.png", 1.4f, true, false);
        AddTerrainType("swamp", "textures/swamp.png", 2.0f, true, false);
    }
    
    private void AddTerrainType(string name, string textureFile, float movementCost, bool isWalkable, bool isWater)
    {
        _terrainTypes[name] = new TerrainType(name, textureFile, movementCost, isWalkable, isWater);
    }
    
    public IMapTile GetTile(string terrainName)
    {
        if (!_tiles.TryGetValue(terrainName, out var tile))
        {
            if (!_terrainTypes.TryGetValue(terrainName, out var terrainType))
            {
                _logger?.LogWarning($"未知地形类型: {terrainName},使用默认草地");
                terrainType = _terrainTypes["grass"];
            }
            
            tile = new MapTile(terrainType);
            _tiles[terrainName] = tile;
            _logger?.LogDebug($"创建并缓存新的地形图块: {terrainName}");
        }
        else
        {
            _logger?.LogTrace($"重用已缓存的地形图块: {terrainName}");
        }
        
        return tile;
    }
    
    public int TileTypesCount => _tiles.Count;
    
    public IEnumerable<string> GetAvailableTerrainTypes()
    {
        return _terrainTypes.Keys;
    }
    
    public TerrainType GetTerrainTypeInfo(string name)
    {
        if (_terrainTypes.TryGetValue(name, out var terrainType))
        {
            return terrainType;
        }
        
        return null;
    }
    
    public long EstimateMemorySaved()
    {
        // 每个独立图块的假设内存成本
        const int individualTileSize = 16 * 1024; // 16KB
        
        // 如果不使用享元模式,每个图块都会有自己的纹理数据
        long estimatedMapTilesSize = _usedTilesCount * individualTileSize;
        
        // 使用享元模式后的大小
        long actualSize = _tiles.Count * individualTileSize;
        
        return estimatedMapTilesSize - actualSize;
    }
    
    // 跟踪实际使用的图块数量
    private int _usedTilesCount = 0;
    
    public void RegisterTileUsage()
    {
        _usedTilesCount++;
    }
    
    public int GetUsedTilesCount()
    {
        return _usedTilesCount;
    }
}

// 5. 外部状态 - 地图单元格
public class MapCell
{
    public int X { get; set; }
    public int Y { get; set; }
    public string TerrainType { get; set; }
    public float Elevation { get; set; }
    public float Moisture { get; set; }
    public float Temperature { get; set; }
    public string Decoration { get; set; } // 如"树"、"岩石"等
    public Dictionary<string, object> Properties { get; } = new Dictionary<string, object>();
}

// 6. 地图管理器
public class MapManager
{
    private readonly TerrainFactory _terrainFactory;
    private readonly MapCell[,] _mapCells;
    private readonly int _width;
    private readonly int _height;
    private readonly ILogger<MapManager> _logger;
    
    public MapManager(int width, int height, TerrainFactory terrainFactory, ILogger<MapManager> logger = null)
    {
        _width = width;
        _height = height;
        _terrainFactory = terrainFactory;
        _logger = logger;
        
        _mapCells = new MapCell[width, height];
        
        // 初始化所有单元格
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                _mapCells[x, y] = new MapCell { X = x, Y = y };
            }
        }
    }
    
    public void GenerateRandomMap(string seed = null)
    {
        _logger?.LogInformation($"生成随机地图 ({_width}x{_height})...");
        
        // 使用种子初始化随机数生成器以获得可重复的结果
        Random random = seed != null ? new Random(seed.GetHashCode()) : new Random();
        
        var availableTerrains = _terrainFactory.GetAvailableTerrainTypes().ToArray();
        
        for (int x = 0; x < _width; x++)
        {
            for (int y = 0; y < _height; y++)
            {
                // 为每个单元格分配随机地形
                string terrainType = availableTerrains[random.Next(availableTerrains.Length)];
                
                _mapCells[x, y].TerrainType = terrainType;
                _mapCells[x, y].Elevation = (float)random.NextDouble();
                _mapCells[x, y].Moisture = (float)random.NextDouble();
                _mapCells[x, y].Temperature = (float)(random.NextDouble() * 30 + 5); // 5°C to 35°C
                
                // 注册图块使用
                _terrainFactory.RegisterTileUsage();
            }
        }
        
        _logger?.LogInformation($"地图生成完成,使用了 {_terrainFactory.TileTypesCount} 种地形类型");
    }
    
    public void GeneratePerlinNoiseMap()
    {
        _logger?.LogInformation($"使用柏林噪声生成地形地图 ({_width}x{_height})...");
        
        // 简化的柏林噪声实现
        SimplexNoise noise = new SimplexNoise();
        
        for (int x = 0; x < _width; x++)
        {
            for (int y = 0; y < _height; y++)
            {
                // 生成噪声值
                float scale = 0.1f;
                float elevation = (float)noise.Noise(x * scale, y * scale);
                float moisture = (float)noise.Noise(x * scale + 1000, y * scale + 1000);
                
                // 基于高度和湿度确定地形类型
                string terrainType = DetermineTerrainType(elevation, moisture);
                
                _mapCells[x, y].TerrainType = terrainType;
                _mapCells[x, y].Elevation = elevation;
                _mapCells[x, y].Moisture = moisture;
                
                // 注册图块使用
                _terrainFactory.RegisterTileUsage();
            }
        }
        
        _logger?.LogInformation($"柏林噪声地图生成完成,使用了 {_terrainFactory.TileTypesCount} 种地形类型");
    }
    
    private string DetermineTerrainType(float elevation, float moisture)
    {
        // 将噪声值转换为范围 [0,1]
        elevation = (elevation + 1) / 2;
        moisture = (moisture + 1) / 2;
        
        // 基于高度和湿度确定地形
        if (elevation < 0.3f)
        {
            return "water";
        }
        else if (elevation < 0.4f)
        {
            return "grass";
        }
        else if (elevation < 0.5f)
        {
            if (moisture > 0.6f)
                return "forest";
            else
                return "grass";
        }
        else if (elevation < 0.7f)
        {
            if (moisture < 0.3f)
                return "desert";
            else
                return "forest";
        }
        else if (elevation < 0.9f)
        {
            if (moisture > 0.5f)
                return "snow";
            else
                return "mountain";
        }
        else
        {
            return "mountain";
        }
    }
    
    public void RenderMap(float scale = 1.0f, float brightness = 1.0f)
    {
        _logger?.LogInformation($"渲染地图 ({_width}x{_height}),缩放: {scale},亮度: {brightness}");
        
        // 限制输出的地图尺寸,避免过多的控制台输出
        int displayWidth = Math.Min(_width, 10);
        int displayHeight = Math.Min(_height, 10);
        
        Console.WriteLine($"渲染地图 (显示 {displayWidth}x{displayHeight} 部分):");
        
        for (int y = 0; y < displayHeight; y++)
        {
            for (int x = 0; x < displayWidth; x++)
            {
                MapCell cell = _mapCells[x, y];
                IMapTile tile = _terrainFactory.GetTile(cell.TerrainType);
                
                // 调整亮度基于海拔
                float cellBrightness = brightness * (0.8f + cell.Elevation * 0.4f);
                
                // 渲染图块
                tile.Render(x, y, scale, cellBrightness);
            }
        }
        
        Console.WriteLine("(地图太大,仅显示一部分)");
    }
    
    public bool CheckPathExists(int startX, int startY, int endX, int endY, string unitType)
    {
        // 简化的路径查找
        if (startX < 0 || startX >= _width || startY < 0 || startY >= _height ||
            endX < 0 || endX >= _width || endY < 0 || endY >= _height)
        {
            return false;
        }
        
        // 检查起点和终点是否可通过
        IMapTile startTile = _terrainFactory.GetTile(_mapCells[startX, startY].TerrainType);
        IMapTile endTile = _terrainFactory.GetTile(_mapCells[endX, endY].TerrainType);
        
        if (!startTile.CanMoveThrough(unitType) || !endTile.CanMoveThrough(unitType))
        {
            return false;
        }
        
        // 简化:如果起点和终点都可通过,假设路径存在
        // 实际游戏中会使用A*或其他寻路算法
        return true;
    }
    
    public void PrintMapStatistics()
    {
        int totalCells = _width * _height;
        int usedTiles = _terrainFactory.GetUsedTilesCount();
        int uniqueTiles = _terrainFactory.TileTypesCount;
        long memorySaved = _terrainFactory.EstimateMemorySaved() / 1024; // KB
        
        Console.WriteLine("\n=== 地图统计 ===");
        Console.WriteLine($"地图尺寸: {_width}x{_height} ({totalCells} 个单元格)");
        Console.WriteLine($"使用的图块实例数: {usedTiles}");
        Console.WriteLine($"唯一地形类型数: {uniqueTiles}");
        Console.WriteLine($"内存节省估算: {memorySaved} KB");
        Console.WriteLine($"共享率: {(double)uniqueTiles / usedTiles:P2} (值越小表示共享率越高)");
        
        // 显示地形类型分布
        Dictionary<string, int> terrainCounts = new Dictionary<string, int>();
        
        for (int x = 0; x < _width; x++)
        {
            for (int y = 0; y < _height; y++)
            {
                string terrainType = _mapCells[x, y].TerrainType;
                
                if (!terrainCounts.ContainsKey(terrainType))
                {
                    terrainCounts[terrainType] = 0;
                }
                
                terrainCounts[terrainType]++;
            }
        }
        
        Console.WriteLine("\n地形分布:");
        foreach (var kvp in terrainCounts.OrderByDescending(k => k.Value))
        {
            double percentage = (double)kvp.Value / totalCells * 100;
            Console.WriteLine($"- {kvp.Key}: {kvp.Value} 个单元格 ({percentage:F1}%)");
        }
    }
}

// 7. 简化的柏林噪声实现
public class SimplexNoise
{
    private const int GradientSizeTable = 256;
    private readonly Random _random;
    private readonly double[] _gradients = new double[GradientSizeTable * 3];
    private readonly byte[] _perm = new byte[GradientSizeTable * 2];
    
    public SimplexNoise(int seed = 0)
    {
        _random = new Random(seed);
        InitGradients();
    }
    
    private void InitGradients()
    {
        for (int i = 0; i < GradientSizeTable; i++)
        {
            double z = 1f - 2f * _random.NextDouble();
            double r = Math.Sqrt(1f - z * z);
            double theta = 2 * Math.PI * _random.NextDouble();
            _gradients[i * 3] = r * Math.Cos(theta);
            _gradients[i * 3 + 1] = r * Math.Sin(theta);
            _gradients[i * 3 + 2] = z;
        }
        
        for (int i = 0; i < GradientSizeTable; i++)
        {
            _perm[i] = (byte)i;
        }
        
        for (int i = 0; i < GradientSizeTable; i++)
        {
            int j = _random.Next(GradientSizeTable);
            byte temp = _perm[i];
            _perm[i] = _perm[j];
            _perm[j] = temp;
        }
        
        for (int i = 0; i < GradientSizeTable; i++)
        {
            _perm[GradientSizeTable + i] = _perm[i];
        }
    }
    
    // 简化的2D噪声实现
    public double Noise(double x, double y)
    {
        const double F2 = 0.366025403f; // (sqrt(3) - 1) / 2
        const double G2 = 0.211324865f; // (3 - sqrt(3)) / 6
        
        double s = (x + y) * F2;
        int i = FastFloor(x + s);
        int j = FastFloor(y + s);
        
        double t = (i + j) * G2;
        double X0 = i - t;
        double Y0 = j - t;
        double x0 = x - X0;
        double y0 = y - Y0;
        
        int i1, j1;
        if (x0 > y0)
        {
            i1 = 1;
            j1 = 0;
        }
        else
        {
            i1 = 0;
            j1 = 1;
        }
        
        double x1 = x0 - i1 + G2;
        double y1 = y0 - j1 + G2;
        double x2 = x0 - 1.0 + 2.0 * G2;
        double y2 = y0 - 1.0 + 2.0 * G2;
        
        int ii = i & 255;
        int jj = j & 255;
        
        double n0, n1, n2;
        
        double t0 = 0.5 - x0 * x0 - y0 * y0;
        if (t0 < 0)
            n0 = 0.0;
        else
        {
            t0 *= t0;
            n0 = t0 * t0 * Grad(ii + _perm[jj], x0, y0);
        }
        
        double t1 = 0.5 - x1 * x1 - y1 * y1;
        if (t1 < 0)
            n1 = 0.0;
        else
        {
            t1 *= t1;
            n1 = t1 * t1 * Grad(ii + i1 + _perm[jj + j1], x1, y1);
        }
        
        double t2 = 0.5 - x2 * x2 - y2 * y2;
        if (t2 < 0)
            n2 = 0.0;
        else
        {
            t2 *= t2;
            n2 = t2 * t2 * Grad(ii + 1 + _perm[jj + 1], x2, y2);
        }
        
        return 40.0 * (n0 + n1 + n2);
    }
    
    private int FastFloor(double x)
    {
        return x > 0 ? (int)x : (int)x - 1;
    }
    
    private double Grad(int hash, double x, double y)
    {
        int h = hash & 15;
        double u = h < 8 ? x : y;
        double v = h < 4 ? y : (h == 12 || h == 14 ? x : 0);
        return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
    }
}

// 8. 地图工具
public class MapTools
{
    private readonly MapManager _mapManager;
    private readonly TerrainFactory _terrainFactory;
    private readonly ILogger<MapTools> _logger;
    
    public MapTools(MapManager mapManager, TerrainFactory terrainFactory, ILogger<MapTools> logger = null)
    {
        _mapManager = mapManager;
        _terrainFactory = terrainFactory;
        _logger = logger;
    }
    
    public void PrintTerrainInfo()
    {
        Console.WriteLine("\n=== 地形信息 ===");
        
        foreach (string terrainName in _terrainFactory.GetAvailableTerrainTypes())
        {
            TerrainType terrain = _terrainFactory.GetTerrainTypeInfo(terrainName);
            
            if (terrain != null)
            {
                Console.WriteLine($"地形: {terrain.Name}");
                Console.WriteLine($"  纹理: {terrain.TextureFile}");
                Console.WriteLine($"  移动成本: {terrain.MovementCost}");
                Console.WriteLine($"  可通行: {terrain.IsWalkable}");
                Console.WriteLine($"  是水域: {terrain.IsWater}");
                Console.WriteLine($"  纹理数据大小: {terrain.TextureData.Length / 1024}KB");
                Console.WriteLine();
            }
        }
    }
    
    public void SimulateUnitMovement()
    {
        Console.WriteLine("\n=== 单位移动模拟 ===");
        
        string[] unitTypes = { "Infantry", "Vehicle", "Ship", "Aircraft" };
        
        foreach (string unitType in unitTypes)
        {
            Console.WriteLine($"\n{unitType} 单位可通过的地形:");
            
            foreach (string terrainName in _terrainFactory.GetAvailableTerrainTypes())
            {
                IMapTile tile = _terrainFactory.GetTile(terrainName);
                bool canPass = tile.CanMoveThrough(unitType);
                
                Console.WriteLine($"- {terrainName}: {(canPass ? "可通过" : "不可通过")}");
            }
        }
    }
    
    public void BenchmarkMapRendering()
    {
        Console.WriteLine("\n=== 地图渲染性能测试 ===");
        
        var stopwatch = new System.Diagnostics.Stopwatch();
        stopwatch.Start();
        
        // 模拟多次渲染以测试性能
        for (int i = 0; i < 5; i++)
        {
            // 仅记录,不实际输出
            _logger?.LogInformation($"渲染地图第 {i+1} 次");
        }
        
        stopwatch.Stop();
        Console.WriteLine($"渲染5次地图耗时: {stopwatch.ElapsedMilliseconds}ms");
        
        // 测试内存使用
        GC.Collect();
        long memoryBefore = GC.GetTotalMemory(true);
        
        // 创建大量图块但只使用几种类型
        for (int i = 0; i < 1000; i++)
        {
            string terrainType = "grass";
            if (i % 5 == 0) terrainType = "water";
            if (i % 7 == 0) terrainType = "mountain";
            
            _terrainFactory.GetTile(terrainType);
        }
        
        GC.Collect();
        long memoryAfter = GC.GetTotalMemory(true);
        
        Console.WriteLine($"创建1000个图块后内存增加: {(memoryAfter - memoryBefore) / 1024}KB");
        Console.WriteLine($"如果不使用享元模式,估计内存使用: {1000 * 16}KB");
    }
}

// 9. 演示应用
public class MapEditorDemo
{
    private readonly IServiceProvider _serviceProvider;
    
    public MapEditorDemo(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
    
    public void Run()
    {
        Console.WriteLine("===== 地图编辑器演示 - 享元模式 =====\n");
        
        var logger = _serviceProvider.GetRequiredService<ILogger<MapEditorDemo>>();
        var terrainFactory = _serviceProvider.GetRequiredService<TerrainFactory>();
        
        // 创建小地图进行演示
        logger.LogInformation("创建演示地图 (20x15)");
        var smallMap = _serviceProvider.GetRequiredService<MapManager>();
        
        // 随机生成地图
        smallMap.GenerateRandomMap("demo-seed");
        
        // 渲染地图
        smallMap.RenderMap(1.0f, 1.0f);
        
        // 显示地图统计
        smallMap.PrintMapStatistics();
        
        // 测试柏林噪声地图生成
        logger.LogInformation("\n使用柏林噪声创建较大地图 (100x100)");
        
        var largeMapManager = new MapManager(100, 100, terrainFactory, 
            _serviceProvider.GetRequiredService<ILogger<MapManager>>());
            
        largeMapManager.GeneratePerlinNoiseMap();
        
        // 渲染大地图的一部分
        largeMapManager.RenderMap(0.8f, 1.2f);
        
        // 显示大地图统计
        largeMapManager.PrintMapStatistics();
        
        // 使用地图工具
        var mapTools = new MapTools(smallMap, terrainFactory, 
            _serviceProvider.GetRequiredService<ILogger<MapTools>>());
            
        mapTools.PrintTerrainInfo();
        mapTools.SimulateUnitMovement();
        mapTools.BenchmarkMapRendering();
        
        Console.WriteLine("\n===== 享元模式演示结束 =====");
    }
}

// 10. 程序入口
public class Program
{
    public static void Main()
    {
        // 设置依赖注入
        var services = new ServiceCollection();
        
        // 添加日志
        services.AddLogging(builder =>
        {
            builder.AddConsole();
            builder.SetMinimumLevel(LogLevel.Information);
        });
        
        // 注册服务
        services.AddSingleton<TerrainFactory>();
        services.AddSingleton<MapManager>(provider => 
            new MapManager(20, 15, provider.GetRequiredService<TerrainFactory>(), 
                provider.GetRequiredService<ILogger<MapManager>>()));
                
        services.AddSingleton<MapEditorDemo>();
        
        var serviceProvider = services.BuildServiceProvider();
        
        // 运行演示
        var demo = serviceProvider.GetRequiredService<MapEditorDemo>();
        demo.Run();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732

# 12. 代理模式

原理:
代理模式为另一个对象提供替代或占位符,以控制对这个对象的访问。代理对象充当客户端和目标对象之间的中介,可以在不改变目标对象接口的情况下添加额外的功能。

思路:

  1. 创建一个接口,定义目标对象和代理对象共同实现的方法
  2. 实现目标对象,提供实际功能
  3. 实现代理对象,包含对目标对象的引用,并在调用目标对象前后添加额外处理

前辈经验:

  • 当需要控制对敏感对象的访问时,使用代理模式
  • 代理可以延迟初始化(虚拟代理)、访问控制(保护代理)、添加功能(智能引用)
  • 代理应该保持与目标对象相同的接口,对客户端透明
  • 远程代理可以隐藏网络通信的复杂性,使远程对象表现得像本地对象
  • 在.NET中,使用System.Runtime.Remoting或WCF可以方便地实现远程代理

业务场景:
图像加载系统,需要延迟加载大图像直到真正需要显示时,以节省内存和提高应用启动速度。

简单实现:

// 图像接口
public interface IImage
{
    void Display();
    string GetFileName();
    int GetWidth();
    int GetHeight();
}

// 真实图像类
public class RealImage : IImage
{
    private string _fileName;
    private int _width;
    private int _height;
    
    public RealImage(string fileName)
    {
        _fileName = fileName;
        LoadImageFromDisk();
    }
    
    private void LoadImageFromDisk()
    {
        Console.WriteLine($"加载图像: {_fileName}");
        // 模拟加载耗时
        Thread.Sleep(1000);
        
        // 模拟图像尺寸
        Random rand = new Random();
        _width = rand.Next(800, 1600);
        _height = rand.Next(600, 1200);
        
        Console.WriteLine($"图像加载完成: {_fileName} ({_width}x{_height})");
    }
    
    public void Display()
    {
        Console.WriteLine($"显示图像: {_fileName}");
    }
    
    public string GetFileName()
    {
        return _fileName;
    }
    
    public int GetWidth()
    {
        return _width;
    }
    
    public int GetHeight()
    {
        return _height;
    }
}

// 图像代理
public class ImageProxy : IImage
{
    private RealImage _realImage;
    private string _fileName;
    
    public ImageProxy(string fileName)
    {
        _fileName = fileName;
    }
    
    public void Display()
    {
        // 延迟初始化,只在真正需要显示图像时才加载
        if (_realImage == null)
        {
            _realImage = new RealImage(_fileName);
        }
        
        _realImage.Display();
    }
    
    public string GetFileName()
    {
        return _fileName;
    }
    
    public int GetWidth()
    {
        // 如果已经加载了图像,则返回真实宽度
        if (_realImage != null)
        {
            return _realImage.GetWidth();
        }
        
        // 否则返回默认值或从元数据中获取
        Console.WriteLine($"获取图像宽度(不加载图像): {_fileName}");
        return 0; // 实际应用中可能会读取图像元数据
    }
    
    public int GetHeight()
    {
        // 如果已经加载了图像,则返回真实高度
        if (_realImage != null)
        {
            return _realImage.GetHeight();
        }
        
        // 否则返回默认值或从元数据中获取
        Console.WriteLine($"获取图像高度(不加载图像): {_fileName}");
        return 0; // 实际应用中可能会读取图像元数据
    }
}

// 图像库
public class ImageGallery
{
    private List<IImage> _images = new List<IImage>();
    
    public void AddImage(IImage image)
    {
        _images.Add(image);
    }
    
    public void ShowGallery()
    {
        Console.WriteLine("显示图库:");
        foreach (var image in _images)
        {
            Console.WriteLine($"- {image.GetFileName()}");
        }
    }
    
    public void DisplayImage(int index)
    {
        if (index >= 0 && index < _images.Count)
        {
            _images[index].Display();
        }
        else
        {
            Console.WriteLine("无效的图像索引!");
        }
    }
}

// 客户端代码
public class Client
{
    public static void Main()
    {
        ImageGallery gallery = new ImageGallery();
        
        // 使用代理添加图像,不会立即加载
        Console.WriteLine("初始化图库...");
        gallery.AddImage(new ImageProxy("image1.jpg"));
        gallery.AddImage(new ImageProxy("image2.jpg"));
        gallery.AddImage(new ImageProxy("image3.jpg"));
        
        // 显示图库(只显示文件名,不加载图像)
        gallery.ShowGallery();
        
        // 用户选择查看图像,此时才会加载
        Console.WriteLine("\n用户选择查看图像 0:");
        gallery.DisplayImage(0);
        
        Console.WriteLine("\n用户选择查看图像 2:");
        gallery.DisplayImage(2);
        
        // 再次查看已加载的图像,不会重新加载
        Console.WriteLine("\n用户再次查看图像 0:");
        gallery.DisplayImage(0);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

复杂实现:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

// 1. 图像接口
public interface IImage
{
    Task DisplayAsync();
    Task<byte[]> GetImageDataAsync();
    string GetFileName();
    Task<ImageMetadata> GetMetadataAsync();
    bool IsLoaded();
}

// 2. 图像元数据类
public class ImageMetadata
{
    public int Width { get; set; }
    public int Height { get; set; }
    public string Format { get; set; }
    public long FileSize { get; set; }
    public DateTime CreationDate { get; set; }
    public Dictionary<string, string> ExifData { get; set; } = new Dictionary<string, string>();
    
    public override string ToString()
    {
        return $"尺寸: {Width}x{Height}, 格式: {Format}, 大小: {FormatFileSize(FileSize)}";
    }
    
    private string FormatFileSize(long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB" };
        double len = bytes;
        int order = 0;
        
        while (len >= 1024 && order < sizes.Length - 1)
        {
            order++;
            len /= 1024;
        }
        
        return $"{len:0.##} {sizes[order]}";
    }
}

// 3. 图像加载异常
public class ImageLoadException : Exception
{
    public string ImagePath { get; }
    
    public ImageLoadException(string message, string imagePath, Exception innerException = null)
        : base(message, innerException)
    {
        ImagePath = imagePath;
    }
}

// 4. 真实图像类
public class RealImage : IImage
{
    private string _fileName;
    private byte[] _imageData;
    private ImageMetadata _metadata;
    private bool _isLoaded = false;
    
    public RealImage(string fileName)
    {
        _fileName = fileName;
    }
    
    private async Task LoadImageFromDiskAsync()
    {
        Console.WriteLine($"加载图像: {_fileName}");
        
        try
        {
            // 模拟图像加载耗时
            await Task.Delay(500);
            
            if (File.Exists(_fileName))
            {
                // 实际应用中,这里应该加载真正的图像文件
                _imageData = await File.ReadAllBytesAsync(_fileName);
            }
            else if (_fileName.StartsWith("http://") || _fileName.StartsWith("https://"))
            {
                // 处理网络图像
                await LoadImageFromUrlAsync(_fileName);
            }
            else
            {
                // 生成模拟数据
                _imageData = new byte[1024 * 1024]; // 1MB 的假数据
                new Random().NextBytes(_imageData);
            }
            
            // 提取或生成元数据
            await ExtractMetadataAsync();
            
            _isLoaded = true;
            Console.WriteLine($"图像加载完成: {_fileName} ({_metadata.Width}x{_metadata.Height})");
        }
        catch (Exception ex)
        {
            throw new ImageLoadException($"无法加载图像 {_fileName}", _fileName, ex);
        }
    }
    
    private async Task LoadImageFromUrlAsync(string url)
    {
        try
        {
            using (HttpClient client = new HttpClient())
            {
                Console.WriteLine($"从URL加载图像: {url}");
                _imageData = await client.GetByteArrayAsync(url);
            }
        }
        catch (Exception ex)
        {
            throw new ImageLoadException($"无法从URL加载图像 {url}", url, ex);
        }
    }
    
    private async Task ExtractMetadataAsync()
    {
        // 在实际应用中,这里应该解析图像文件提取真实元数据
        // 这里我们只是模拟
        await Task.Delay(100);
        
        Random rand = new Random();
        _metadata = new ImageMetadata
        {
            Width = rand.Next(800, 3840),
            Height = rand.Next(600, 2160),
            Format = Path.GetExtension(_fileName).ToLowerInvariant() switch
            {
                ".jpg" or ".jpeg" => "JPEG",
                ".png" => "PNG",
                ".gif" => "GIF",
                ".bmp" => "BMP",
                _ => "JPEG"
            },
            FileSize = _imageData?.Length ?? 0,
            CreationDate = DateTime.Now.AddDays(-rand.Next(1, 365))
        };
        
        // 添加一些模拟的EXIF数据
        _metadata.ExifData["Camera"] = "Canon EOS 5D Mark IV";
        _metadata.ExifData["Exposure"] = "1/125";
        _metadata.ExifData["Aperture"] = "f/8";
        _metadata.ExifData["ISO"] = "100";
        _metadata.ExifData["Focal Length"] = "50mm";
    }
    
    public async Task DisplayAsync()
    {
        if (!_isLoaded)
        {
            await LoadImageFromDiskAsync();
        }
        
        Console.WriteLine($"显示图像: {_fileName} ({_metadata.Width}x{_metadata.Height})");
        // 实际应用中,这里会渲染图像到屏幕
    }
    
    public async Task<byte[]> GetImageDataAsync()
    {
        if (!_isLoaded)
        {
            await LoadImageFromDiskAsync();
        }
        
        return _imageData;
    }
    
    public string GetFileName()
    {
        return _fileName;
    }
    
    public async Task<ImageMetadata> GetMetadataAsync()
    {
        if (!_isLoaded)
        {
            await LoadImageFromDiskAsync();
        }
        
        return _metadata;
    }
    
    public bool IsLoaded()
    {
        return _isLoaded;
    }
}

// 5. 虚拟代理 - 延迟加载图像
public class VirtualProxyImage : IImage
{
    private readonly string _fileName;
    private RealImage _realImage;
    private ImageMetadata _cachedMetadata;
    
    public VirtualProxyImage(string fileName)
    {
        _fileName = fileName;
    }
    
    public async Task DisplayAsync()
    {
        // 延迟初始化,只在真正需要显示图像时才加载
        await GetRealImageAsync();
        await _realImage.DisplayAsync();
    }
    
    public async Task<byte[]> GetImageDataAsync()
    {
        await GetRealImageAsync();
        return await _realImage.GetImageDataAsync();
    }
    
    public string GetFileName()
    {
        return _fileName;
    }
    
    public async Task<ImageMetadata> GetMetadataAsync()
    {
        // 如果已经有缓存的元数据,直接返回
        if (_cachedMetadata != null)
        {
            return _cachedMetadata;
        }
        
        // 如果已经加载了图像,从图像获取元数据
        if (_realImage != null)
        {
            _cachedMetadata = await _realImage.GetMetadataAsync();
            return _cachedMetadata;
        }
        
        // 尝试快速获取元数据(不加载整个图像)
        try
        {
            Console.WriteLine($"快速提取图像元数据: {_fileName}");
            
            // 在实际应用中,这里可以只读取图像文件头来提取元数据
            // 这里我们模拟一下
            await Task.Delay(50);
            
            Random rand = new Random();
            _cachedMetadata = new ImageMetadata
            {
                Width = rand.Next(800, 3840),
                Height = rand.Next(600, 2160),
                Format = Path.GetExtension(_fileName).ToLowerInvariant() switch
                {
                    ".jpg" or ".jpeg" => "JPEG",
                    ".png" => "PNG",
                    ".gif" => "GIF",
                    ".bmp" => "BMP",
                    _ => "JPEG"
                },
                FileSize = rand.Next(50000, 5000000),
                CreationDate = DateTime.Now.AddDays(-rand.Next(1, 365))
            };
            
            return _cachedMetadata;
        }
        catch
        {
            // 如果快速提取失败,回退到完整加载
            await GetRealImageAsync();
            _cachedMetadata = await _realImage.GetMetadataAsync();
            return _cachedMetadata;
        }
    }
    
    public bool IsLoaded()
    {
        return _realImage != null && _realImage.IsLoaded();
    }
    
    private async Task GetRealImageAsync()
    {
        if (_realImage == null)
        {
            _realImage = new RealImage(_fileName);
        }
        
        if (!_realImage.IsLoaded())
        {
            await _realImage.GetImageDataAsync();
        }
    }
}

// 6. 保护代理 - 增加访问控制
public class ProtectionProxyImage : IImage
{
    private readonly IImage _realImage;
    private readonly IAuthenticationService _authService;
    private readonly string _requiredPermission;
    
    public ProtectionProxyImage(IImage realImage, IAuthenticationService authService, string requiredPermission)
    {
        _realImage = realImage;
        _authService = authService;
        _requiredPermission = requiredPermission;
    }
    
    public async Task DisplayAsync()
    {
        if (!_authService.HasPermission(_requiredPermission))
        {
            Console.WriteLine($"访问拒绝: 缺少权限 '{_requiredPermission}' 来显示图像 {_realImage.GetFileName()}");
            throw new UnauthorizedAccessException($"没有查看图像的权限: {_requiredPermission}");
        }
        
        await _realImage.DisplayAsync();
    }
    
    public async Task<byte[]> GetImageDataAsync()
    {
        if (!_authService.HasPermission(_requiredPermission))
        {
            Console.WriteLine($"访问拒绝: 缺少权限 '{_requiredPermission}' 来访问图像数据 {_realImage.GetFileName()}");
            throw new UnauthorizedAccessException($"没有访问图像数据的权限: {_requiredPermission}");
        }
        
        return await _realImage.GetImageDataAsync();
    }
    
    public string GetFileName()
    {
        // 文件名通常可以无需权限查看
        return _realImage.GetFileName();
    }
    
    public async Task<ImageMetadata> GetMetadataAsync()
    {
        // 元数据可能需要较低级别的权限
        if (!_authService.HasPermission(_requiredPermission.Replace("View", "ReadMetadata")))
        {
            Console.WriteLine($"访问拒绝: 缺少权限来读取图像元数据 {_realImage.GetFileName()}");
            throw new UnauthorizedAccessException("没有读取图像元数据的权限");
        }
        
        return await _realImage.GetMetadataAsync();
    }
    
    public bool IsLoaded()
    {
        return _realImage.IsLoaded();
    }
}

// 7. 缓存代理 - 缓存图像数据和结果
public class CachingProxyImage : IImage
{
    private readonly IImage _realImage;
    private readonly string _cacheKey;
    private readonly IImageCache _cache;
    
    public CachingProxyImage(IImage realImage, IImageCache cache)
    {
        _realImage = realImage;
        _cache = cache;
        _cacheKey = GenerateCacheKey(_realImage.GetFileName());
    }
    
    public async Task DisplayAsync()
    {
        // 首先检查缓存中是否有图像数据
        if (_cache.HasImageData(_cacheKey))
        {
            Console.WriteLine($"从缓存中显示图像: {_realImage.GetFileName()}");
            // 在实际应用中,这里会使用缓存的数据进行显示
        }
        else
        {
            // 如果缓存中没有,则通过实际图像加载
            await _realImage.DisplayAsync();
            
            // 缓存图像数据以供将来使用
            byte[] imageData = await _realImage.GetImageDataAsync();
            _cache.CacheImageData(_cacheKey, imageData);
        }
    }
    
    public async Task<byte[]> GetImageDataAsync()
    {
        // 检查是否有缓存的图像数据
        if (_cache.HasImageData(_cacheKey))
        {
            Console.WriteLine($"从缓存获取图像数据: {_realImage.GetFileName()}");
            return _cache.GetImageData(_cacheKey);
        }
        
        // 如果没有缓存,则从实际图像获取
        byte[] imageData = await _realImage.GetImageDataAsync();
        
        // 缓存数据
        _cache.CacheImageData(_cacheKey, imageData);
        
        return imageData;
    }
    
    public string GetFileName()
    {
        return _realImage.GetFileName();
    }
    
    public async Task<ImageMetadata> GetMetadataAsync()
    {
        // 检查是否有缓存的元数据
        if (_cache.HasMetadata(_cacheKey))
        {
            Console.WriteLine($"从缓存获取图像元数据: {_realImage.GetFileName()}");
            return _cache.GetMetadata(_cacheKey);
        }
        
        // 如果没有缓存,则从实际图像获取
        ImageMetadata metadata = await _realImage.GetMetadataAsync();
        
        // 缓存元数据
        _cache.CacheMetadata(_cacheKey, metadata);
        
        return metadata;
    }
    
    public bool IsLoaded()
    {
        return _cache.HasImageData(_cacheKey) || _realImage.IsLoaded();
    }
    
    private string GenerateCacheKey(string fileName)
    {
        // 使用文件名的哈希作为缓存键
        using (SHA256 sha256 = SHA256.Create())
        {
            byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(fileName));
            return Convert.ToBase64String(hashBytes).Substring(0, 20);
        }
    }
}

// 8. 日志代理 - 记录图像操作
public class LoggingProxyImage : IImage
{
    private readonly IImage _realImage;
    private readonly ILogger _logger;
    
    public LoggingProxyImage(IImage realImage, ILogger logger)
    {
        _realImage = realImage;
        _logger = logger;
    }
    
    public async Task DisplayAsync()
    {
        _logger.Log($"开始显示图像: {_realImage.GetFileName()}");
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        
        try
        {
            await _realImage.DisplayAsync();
            stopwatch.Stop();
            _logger.Log($"图像显示完成: {_realImage.GetFileName()}, 耗时: {stopwatch.ElapsedMilliseconds}ms");
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.Log($"图像显示失败: {_realImage.GetFileName()}, 错误: {ex.Message}, 耗时: {stopwatch.ElapsedMilliseconds}ms");
            throw;
        }
    }
    
    public async Task<byte[]> GetImageDataAsync()
    {
        _logger.Log($"获取图像数据: {_realImage.GetFileName()}");
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        
        try
        {
            byte[] data = await _realImage.GetImageDataAsync();
            stopwatch.Stop();
            _logger.Log($"获取图像数据完成: {_realImage.GetFileName()}, 大小: {data.Length} 字节, 耗时: {stopwatch.ElapsedMilliseconds}ms");
            return data;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.Log($"获取图像数据失败: {_realImage.GetFileName()}, 错误: {ex.Message}, 耗时: {stopwatch.ElapsedMilliseconds}ms");
            throw;
        }
    }
    
    public string GetFileName()
    {
        return _realImage.GetFileName();
    }
    
    public async Task<ImageMetadata> GetMetadataAsync()
    {
        _logger.Log($"获取图像元数据: {_realImage.GetFileName()}");
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        
        try
        {
            ImageMetadata metadata = await _realImage.GetMetadataAsync();
            stopwatch.Stop();
            _logger.Log($"获取图像元数据完成: {_realImage.GetFileName()}, 尺寸: {metadata.Width}x{metadata.Height}, 耗时: {stopwatch.ElapsedMilliseconds}ms");
            return metadata;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.Log($"获取图像元数据失败: {_realImage.GetFileName()}, 错误: {ex.Message}, 耗时: {stopwatch.ElapsedMilliseconds}ms");
            throw;
        }
    }
    
    public bool IsLoaded()
    {
        bool loaded = _realImage.IsLoaded();
        _logger.Log($"检查图像是否已加载: {_realImage.GetFileName()}, 结果: {loaded}");
        return loaded;
    }
}

// 9. 辅助接口

// 认证服务接口
public interface IAuthenticationService
{
    bool HasPermission(string permission);
    string GetCurrentUser();
}

// 简单认证服务实现
public class SimpleAuthenticationService : IAuthenticationService
{
    private readonly string _currentUser;
    private readonly HashSet<string> _userPermissions;
    
    public SimpleAuthenticationService(string currentUser, IEnumerable<string> permissions)
    {
        _currentUser = currentUser;
        _userPermissions = new HashSet<string>(permissions);
    }
    
    public bool HasPermission(string permission)
    {
        return _userPermissions.Contains(permission) || _userPermissions.Contains("Admin");
    }
    
    public string GetCurrentUser()
    {
        return _currentUser;
    }
}

// 图像缓存接口
public interface IImageCache
{
    bool HasImageData(string key);
    byte[] GetImageData(string key);
    void CacheImageData(string key, byte[] imageData);
    
    bool HasMetadata(string key);
    ImageMetadata GetMetadata(string key);
    void CacheMetadata(string key, ImageMetadata metadata);
    
    void ClearCache();
}

// 简单内存缓存实现
public class SimpleImageCache : IImageCache
{
    private readonly Dictionary<string, byte[]> _imageDataCache = new Dictionary<string, byte[]>();
    private readonly Dictionary<string, ImageMetadata> _metadataCache = new Dictionary<string, ImageMetadata>();
    
    public bool HasImageData(string key)
    {
        return _imageDataCache.ContainsKey(key);
    }
    
    public byte[] GetImageData(string key)
    {
        if (_imageDataCache.TryGetValue(key, out byte[] data))
        {
            return data;
        }
        return null;
    }
    
    public void CacheImageData(string key, byte[] imageData)
    {
        _imageDataCache[key] = imageData;
        Console.WriteLine($"缓存图像数据: {key}, 大小: {imageData.Length} 字节");
    }
    
    public bool HasMetadata(string key)
    {
        return _metadataCache.ContainsKey(key);
    }
    
    public ImageMetadata GetMetadata(string key)
    {
        if (_metadataCache.TryGetValue(key, out ImageMetadata metadata))
        {
            return metadata;
        }
        return null;
    }
    
    public void CacheMetadata(string key, ImageMetadata metadata)
    {
        _metadataCache[key] = metadata;
        Console.WriteLine($"缓存图像元数据: {key}, 尺寸: {metadata.Width}x{metadata.Height}");
    }
    
    public void ClearCache()
    {
        _imageDataCache.Clear();
        _metadataCache.Clear();
        Console.WriteLine("图像缓存已清空");
    }
}

// 日志接口
public interface ILogger
{
    void Log(string message);
}

// 控制台日志实现
public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}");
    }
}

// 10. 图像库类
public class ImageGallery
{
    private readonly List<IImage> _images = new List<IImage>();
    private readonly ILogger _logger;
    
    public ImageGallery(ILogger logger = null)
    {
        _logger = logger ?? new ConsoleLogger();
    }
    
    public void AddImage(IImage image)
    {
        _images.Add(image);
        _logger.Log($"添加图像到图库: {image.GetFileName()}");
    }
    
    public async Task ShowGalleryAsync()
    {
        _logger.Log("显示图库:");
        
        for (int i = 0; i < _images.Count; i++)
        {
            IImage image = _images[i];
            try
            {
                ImageMetadata metadata = await image.GetMetadataAsync();
                Console.WriteLine($"{i}: {image.GetFileName()} - {metadata}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"{i}: {image.GetFileName()} - 无法获取元数据: {ex.Message}");
            }
        }
    }
    
    public async Task DisplayImageAsync(int index)
    {
        if (index >= 0 && index < _images.Count)
        {
            _logger.Log($"请求显示图像 {index}: {_images[index].GetFileName()}");
            
            try
            {
                await _images[index].DisplayAsync();
            }
            catch (Exception ex)
            {
                _logger.Log($"显示图像失败: {ex.Message}");
                Console.WriteLine($"无法显示图像: {ex.Message}");
            }
        }
        else
        {
            _logger.Log($"无效的图像索引: {index}");
            Console.WriteLine("无效的图像索引!");
        }
    }
    
    public async Task<ImageMetadata> GetImageMetadataAsync(int index)
    {
        if (index >= 0 && index < _images.Count)
        {
            _logger.Log($"请求图像 {index} 的元数据: {_images[index].GetFileName()}");
            return await _images[index].GetMetadataAsync();
        }
        
        throw new IndexOutOfRangeException("无效的图像索引");
    }
    
    public int ImageCount => _images.Count;
}

// 11. 图像代理工厂
public class ImageProxyFactory
{
    private readonly IImageCache _cache;
    private readonly IAuthenticationService _authService;
    private readonly ILogger _logger;
    
    public ImageProxyFactory(IImageCache cache, IAuthenticationService authService, ILogger logger)
    {
        _cache = cache;
        _authService = authService;
        _logger = logger;
    }
    
    public IImage CreateImage(string fileName, bool enableVirtualProxy = true, bool enableCaching = true,
                            bool enableLogging = true, bool enableProtection = false, string requiredPermission = "ViewImages")
    {
        // 创建基础图像对象
        IImage image = new RealImage(fileName);
        
        // 按需应用各种代理
        if (enableVirtualProxy)
        {
            image = new VirtualProxyImage(fileName);
        }
        
        if (enableProtection)
        {
            image = new ProtectionProxyImage(image, _authService, requiredPermission);
        }
        
        if (enableCaching)
        {
            image = new CachingProxyImage(image, _cache);
        }
        
        if (enableLogging)
        {
            image = new LoggingProxyImage(image, _logger);
        }
        
        return image;
    }
}

// 12. 客户端代码
public class Client
{
    private static async Task Main()
    {
        Console.WriteLine("=== 图像代理模式演示 ===\n");
        
        // 创建辅助服务
        ILogger logger = new ConsoleLogger();
        IImageCache cache = new SimpleImageCache();
        IAuthenticationService authService = new SimpleAuthenticationService("User", new[] { "ViewImages" });
        
        // 创建代理工厂
        ImageProxyFactory proxyFactory = new ImageProxyFactory(cache, authService, logger);
        
        // 创建图库
        ImageGallery gallery = new ImageGallery(logger);
        
        // 添加不同类型的图像代理
        gallery.AddImage(proxyFactory.CreateImage("image1.jpg"));
        gallery.AddImage(proxyFactory.CreateImage("image2.png", enableCaching: false));
        gallery.AddImage(proxyFactory.CreateImage("image3.gif", enableLogging: false));
        gallery.AddImage(proxyFactory.CreateImage("http://example.com/image4.jpg"));
        gallery.AddImage(proxyFactory.CreateImage("restricted.jpg", enableProtection: true, requiredPermission: "ViewRestrictedImages"));
        
        // 显示图库
        await gallery.ShowGalleryAsync();
        
        // 用户选择查看图像
        Console.WriteLine("\n用户选择查看图像 0:");
        await gallery.DisplayImageAsync(0);
        
        Console.WriteLine("\n用户选择查看图像 3 (网络图像):");
        await gallery.DisplayImageAsync(3);
        
        // 尝试访问受限图像
        Console.WriteLine("\n尝试访问受限图像:");
        try
        {
            await gallery.DisplayImageAsync(4);
        }
        catch (UnauthorizedAccessException ex)
        {
            Console.WriteLine($"访问拒绝: {ex.Message}");
        }
        
        // 再次查看已加载的图像,应该从缓存获取
        Console.WriteLine("\n再次查看图像 0 (应该使用缓存):");
        await gallery.DisplayImageAsync(0);
        
        // 高级用例:演示多重代理的组合使用
        Console.WriteLine("\n=== 多重代理组合演示 ===");
        
        // 创建一个使用所有代理类型的复杂图像
        IImage complexImage = new LoggingProxyImage(
            new CachingProxyImage(
                new ProtectionProxyImage(
                    new VirtualProxyImage("complex_image.jpg"),
                    authService,
                    "ViewImages"
                ),
                cache
            ),
            logger
        );
        
        Console.WriteLine("\n访问复杂图像元数据:");
        var metadata = await complexImage.GetMetadataAsync();
        Console.WriteLine($"图像元数据: {metadata}");
        
        Console.WriteLine("\n显示复杂图像:");
        await complexImage.DisplayAsync();
        
        Console.WriteLine("\n再次显示复杂图像 (应该使用缓存):");
        await complexImage.DisplayAsync();
        
        // 演示代理如何处理错误情况
        Console.WriteLine("\n=== 错误处理演示 ===");
        
        IImage nonExistentImage = proxyFactory.CreateImage("non_existent.jpg");
        
        try
        {
            Console.WriteLine("\n尝试访问不存在的图像:");
            await nonExistentImage.DisplayAsync();
        }
        catch (ImageLoadException ex)
        {
            Console.WriteLine($"加载错误: {ex.Message}, 图像路径: {ex.ImagePath}");
        }
        
        Console.WriteLine("\n=== 代理模式演示结束 ===");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864

业务场景结合:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;

// 远程API访问场景 - 使用代理模式增强API客户端

// 1. API服务接口
public interface IWeatherService
{
    Task<WeatherData> GetCurrentWeatherAsync(string city);
    Task<List<WeatherData>> GetForecastAsync(string city, int days);
    Task<WeatherStats> GetHistoricalDataAsync(string city, DateTime startDate, DateTime endDate);
}

// 2. API响应模型
public class WeatherData
{
    public string City { get; set; }
    public DateTime Date { get; set; }
    public double Temperature { get; set; }
    public double FeelsLike { get; set; }
    public int Humidity { get; set; }
    public string Condition { get; set; }
    public double WindSpeed { get; set; }
    public string WindDirection { get; set; }
    public double Precipitation { get; set; }
    public int UvIndex { get; set; }
    
    public override string ToString()
    {
        return $"{City}: {Temperature:F1}°C, {Condition}, 湿度: {Humidity}%, 风速: {WindSpeed}km/h";
    }
}

public class WeatherStats
{
    public string City { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public double AverageTemperature { get; set; }
    public double MaxTemperature { get; set; }
    public double MinTemperature { get; set; }
    public double AveragePrecipitation { get; set; }
    public int RainyDays { get; set; }
    
    public override string ToString()
    {
        return $"{City} ({StartDate:yyyy-MM-dd} 至 {EndDate:yyyy-MM-dd}): " +
               $"平均气温: {AverageTemperature:F1}°C, 最高: {MaxTemperature:F1}°C, 最低: {MinTemperature:F1}°C, " +
               $"平均降水: {AveragePrecipitation:F1}mm, 雨天: {RainyDays}天";
    }
}

// 3. 真实服务实现 - 调用远程API
public class RemoteWeatherService : IWeatherService
{
    private readonly HttpClient _httpClient;
    private readonly string _apiKey;
    private readonly string _baseUrl;
    
    public RemoteWeatherService(HttpClient httpClient, string apiKey, string baseUrl)
    {
        _httpClient = httpClient;
        _apiKey = apiKey;
        _baseUrl = baseUrl;
    }
    
    public async Task<WeatherData> GetCurrentWeatherAsync(string city)
    {
        string url = $"{_baseUrl}/current?city={Uri.EscapeDataString(city)}&apikey={_apiKey}";
        
        Console.WriteLine($"调用远程API: GET {MaskApiKey(url)}");
        
        try
        {
            // 模拟网络延迟
            await Task.Delay(600);
            
            // 在实际应用中,这里会发送HTTP请求
            // var response = await _httpClient.GetAsync(url);
            // response.EnsureSuccessStatusCode();
            // var content = await response.Content.ReadAsStringAsync();
            // return JsonSerializer.Deserialize<WeatherData>(content);
            
            // 生成模拟数据
            return GenerateMockWeatherData(city);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"API调用失败: {ex.Message}");
            throw new WeatherServiceException("获取当前天气失败", ex)
            {
                City = city
            };
        }
    }
    
    public async Task<List<WeatherData>> GetForecastAsync(string city, int days)
    {
        string url = $"{_baseUrl}/forecast?city={Uri.EscapeDataString(city)}&days={days}&apikey={_apiKey}";
        
        Console.WriteLine($"调用远程API: GET {MaskApiKey(url)}");
        
        try
        {
            // 模拟网络延迟
            await Task.Delay(800);
            
            // 在实际应用中,这里会发送HTTP请求
            // var response = await _httpClient.GetAsync(url);
            // response.EnsureSuccessStatusCode();
            // var content = await response.Content.ReadAsStringAsync();
            // return JsonSerializer.Deserialize<List<WeatherData>>(content);
            
            // 生成模拟数据
            var forecast = new List<WeatherData>();
            var random = new Random();
            
            for (int i = 0; i < days; i++)
            {
                var weather = GenerateMockWeatherData(city);
                weather.Date = DateTime.Now.AddDays(i);
                weather.Temperature = Math.Round(20 + random.NextDouble() * 10 - i * 0.5, 1);
                forecast.Add(weather);
            }
            
            return forecast;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"API调用失败: {ex.Message}");
            throw new WeatherServiceException("获取天气预报失败", ex)
            {
                City = city
            };
        }
    }
    
    public async Task<WeatherStats> GetHistoricalDataAsync(string city, DateTime startDate, DateTime endDate)
    {
        string url = $"{_baseUrl}/history?city={Uri.EscapeDataString(city)}" +
                    $"&start={startDate:yyyy-MM-dd}&end={endDate:yyyy-MM-dd}&apikey={_apiKey}";
        
        Console.WriteLine($"调用远程API: GET {MaskApiKey(url)}");
        
        try
        {
            // 模拟网络延迟 - 历史数据请求通常较慢
            await Task.Delay(1200);
            
            // 在实际应用中,这里会发送HTTP请求
            // var response = await _httpClient.GetAsync(url);
            // response.EnsureSuccessStatusCode();
            // var content = await response.Content.ReadAsStringAsync();
            // return JsonSerializer.Deserialize<WeatherStats>(content);
            
            // 生成模拟数据
            var random = new Random();
            double baseTemp = 15 + random.NextDouble() * 10;
            
            return new WeatherStats
            {
                City = city,
                StartDate = startDate,
                EndDate = endDate,
                AverageTemperature = Math.Round(baseTemp, 1),
                MaxTemperature = Math.Round(baseTemp + 5 + random.NextDouble() * 5, 1),
                MinTemperature = Math.Round(baseTemp - 5 - random.NextDouble() * 5, 1),
                AveragePrecipitation = Math.Round(random.NextDouble() * 10, 1),
                RainyDays = random.Next(1, 10)
            };
        }
        catch (Exception ex)
        {
            Console.WriteLine($"API调用失败: {ex.Message}");
            throw new WeatherServiceException("获取历史天气数据失败", ex)
            {
                City = city
            };
        }
    }
    
    private WeatherData GenerateMockWeatherData(string city)
    {
        var random = new Random();
        string[] conditions = { "晴", "多云", "阴", "小雨", "中雨", "大雨", "雷阵雨", "小雪", "中雪" };
        string[] directions = { "北", "东北", "东", "东南", "南", "西南", "西", "西北" };
        
        return new WeatherData
        {
            City = city,
            Date = DateTime.Now,
            Temperature = Math.Round(10 + random.NextDouble() * 25, 1),
            FeelsLike = Math.Round(10 + random.NextDouble() * 25, 1),
            Humidity = random.Next(30, 95),
            Condition = conditions[random.Next(conditions.Length)],
            WindSpeed = Math.Round(random.NextDouble() * 30, 1),
            WindDirection = directions[random.Next(directions.Length)],
            Precipitation = Math.Round(random.NextDouble() * 15, 1),
            UvIndex = random.Next(0, 11)
        };
    }
    
    private string MaskApiKey(string url)
    {
        // 掩盖API密钥,用于日志记录
        return url.Replace(_apiKey, "API_KEY_HIDDEN");
    }
}

// 4. 自定义异常
public class WeatherServiceException : Exception
{
    public string City { get; set; }
    
    public WeatherServiceException(string message, Exception innerException = null)
        : base(message, innerException)
    {
    }
}

// 5. 缓存代理 - 缓存API响应
public class CachingWeatherServiceProxy : IWeatherService
{
    private readonly IWeatherService _realService;
    private readonly IMemoryCache _cache;
    private readonly TimeSpan _currentWeatherCacheDuration;
    private readonly TimeSpan _forecastCacheDuration;
    private readonly TimeSpan _historicalDataCacheDuration;
    
    public CachingWeatherServiceProxy(
        IWeatherService realService,
        IMemoryCache cache,
        TimeSpan? currentWeatherCacheDuration = null,
        TimeSpan? forecastCacheDuration = null,
        TimeSpan? historicalDataCacheDuration = null)
    {
        _realService = realService;
        _cache = cache;
        _currentWeatherCacheDuration = currentWeatherCacheDuration ?? TimeSpan.FromMinutes(10);
        _forecastCacheDuration = forecastCacheDuration ?? TimeSpan.FromHours(1);
        _historicalDataCacheDuration = historicalDataCacheDuration ?? TimeSpan.FromDays(1);
    }
    
    public async Task<WeatherData> GetCurrentWeatherAsync(string city)
    {
        string cacheKey = $"weather:current:{city}";
        
        if (_cache.TryGetValue(cacheKey, out WeatherData cachedData))
        {
            Console.WriteLine($"从缓存中获取 {city} 的当前天气");
            return cachedData;
        }
        
        Console.WriteLine($"缓存未命中,从服务获取 {city} 的当前天气");
        var weatherData = await _realService.GetCurrentWeatherAsync(city);
        
        _cache.Set(cacheKey, weatherData, _currentWeatherCacheDuration);
        Console.WriteLine($"已缓存 {city} 的当前天气,过期时间: {_currentWeatherCacheDuration.TotalMinutes} 分钟");
        
        return weatherData;
    }
    
    public async Task<List<WeatherData>> GetForecastAsync(string city, int days)
    {
        string cacheKey = $"weather:forecast:{city}:{days}";
        
        if (_cache.TryGetValue(cacheKey, out List<WeatherData> cachedData))
        {
            Console.WriteLine($"从缓存中获取 {city} 的 {days} 天天气预报");
            return cachedData;
        }
        
        Console.WriteLine($"缓存未命中,从服务获取 {city} 的 {days} 天天气预报");
        var forecast = await _realService.GetForecastAsync(city, days);
        
        _cache.Set(cacheKey, forecast, _forecastCacheDuration);
        Console.WriteLine($"已缓存 {city} 的 {days} 天天气预报,过期时间: {_forecastCacheDuration.TotalHours} 小时");
        
        return forecast;
    }
    
    public async Task<WeatherStats> GetHistoricalDataAsync(string city, DateTime startDate, DateTime endDate)
    {
        string cacheKey = $"weather:history:{city}:{startDate:yyyy-MM-dd}:{endDate:yyyy-MM-dd}";
        
        if (_cache.TryGetValue(cacheKey, out WeatherStats cachedData))
        {
            Console.WriteLine($"从缓存中获取 {city} 的历史天气数据");
            return cachedData;
        }
        
        Console.WriteLine($"缓存未命中,从服务获取 {city} 的历史天气数据");
        var stats = await _realService.GetHistoricalDataAsync(city, startDate, endDate);
        
        _cache.Set(cacheKey, stats, _historicalDataCacheDuration);
        Console.WriteLine($"已缓存 {city} 的历史天气数据,过期时间: {_historicalDataCacheDuration.TotalHours} 小时");
        
        return stats;
    }
}

// 6. 日志代理 - 记录API调用
public class LoggingWeatherServiceProxy : IWeatherService
{
    private readonly IWeatherService _realService;
    private readonly ILogger _logger;
    
    public LoggingWeatherServiceProxy(IWeatherService realService, ILogger logger)
    {
        _realService = realService;
        _logger = logger;
    }
    
    public async Task<WeatherData> GetCurrentWeatherAsync(string city)
    {
        _logger.LogInformation("获取城市 {City} 的当前天气", city);
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        
        try
        {
            var result = await _realService.GetCurrentWeatherAsync(city);
            stopwatch.Stop();
            
            _logger.LogInformation("成功获取 {City} 的当前天气,温度: {Temperature}°C,耗时: {ElapsedMs}ms",
                city, result.Temperature, stopwatch.ElapsedMilliseconds);
                
            return result;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.LogError(ex, "获取 {City} 的当前天气失败,耗时: {ElapsedMs}ms",
                city, stopwatch.ElapsedMilliseconds);
                
            throw;
        }
    }
    
    public async Task<List<WeatherData>> GetForecastAsync(string city, int days)
    {
        _logger.LogInformation("获取城市 {City} 的 {Days} 天天气预报", city, days);
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        
        try
        {
            var result = await _realService.GetForecastAsync(city, days);
            stopwatch.Stop();
            
            _logger.LogInformation("成功获取 {City} 的 {Days} 天天气预报,条目数: {Count},耗时: {ElapsedMs}ms",
                city, days, result.Count, stopwatch.ElapsedMilliseconds);
                
            return result;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.LogError(ex, "获取 {City} 的 {Days} 天天气预报失败,耗时: {ElapsedMs}ms",
                city, days, stopwatch.ElapsedMilliseconds);
                
            throw;
        }
    }
    
    public async Task<WeatherStats> GetHistoricalDataAsync(string city, DateTime startDate, DateTime endDate)
    {
        _logger.LogInformation("获取城市 {City} 的历史天气数据,时间范围: {StartDate} 至 {EndDate}",
            city, startDate.ToString("yyyy-MM-dd"), endDate.ToString("yyyy-MM-dd"));
            
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        
        try
        {
            var result = await _realService.GetHistoricalDataAsync(city, startDate, endDate);
            stopwatch.Stop();
            
            _logger.LogInformation("成功获取 {City} 的历史天气数据,平均温度: {AvgTemp}°C,耗时: {ElapsedMs}ms",
                city, result.AverageTemperature, stopwatch.ElapsedMilliseconds);
                
            return result;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.LogError(ex, "获取 {City} 的历史天气数据失败,耗时: {ElapsedMs}ms",
                city, stopwatch.ElapsedMilliseconds);
                
            throw;
        }
    }
}

// 7. 重试代理 - 处理临时错误
public class RetryWeatherServiceProxy : IWeatherService
{
    private readonly IWeatherService _realService;
    private readonly int _maxRetries;
    private readonly TimeSpan _delay;
    private readonly ILogger _logger;
    
    public RetryWeatherServiceProxy(
        IWeatherService realService,
        int maxRetries = 3,
        TimeSpan? delay = null,
        ILogger logger = null)
    {
        _realService = realService;
        _maxRetries = maxRetries;
        _delay = delay ?? TimeSpan.FromSeconds(2);
        _logger = logger;
    }
    
    public async Task<WeatherData> GetCurrentWeatherAsync(string city)
    {
        return await ExecuteWithRetryAsync(() => _realService.GetCurrentWeatherAsync(city),
            $"获取 {city} 的当前天气");
    }
    
    public async Task<List<WeatherData>> GetForecastAsync(string city, int days)
    {
        return await ExecuteWithRetryAsync(() => _realService.GetForecastAsync(city, days),
            $"获取 {city} 的 {days} 天天气预报");
    }
    
    public async Task<WeatherStats> GetHistoricalDataAsync(string city, DateTime startDate, DateTime endDate)
    {
        return await ExecuteWithRetryAsync(
            () => _realService.GetHistoricalDataAsync(city, startDate, endDate),
            $"获取 {city} 的历史天气数据 ({startDate:yyyy-MM-dd} 至 {endDate:yyyy-MM-dd})");
    }
    
    private async Task<T> ExecuteWithRetryAsync<T>(Func<Task<T>> action, string operationName)
    {
        int retryCount = 0;
        
        while (true)
        {
            try
            {
                return await action();
            }
            catch (Exception ex)
            {
                retryCount++;
                
                if (retryCount > _maxRetries)
                {
                    _logger?.LogError(ex, "操作 {Operation} 在 {RetryCount} 次尝试后失败",
                        operationName, retryCount);
                        
                    throw;
                }
                
                _logger?.LogWarning(ex, "操作 {Operation} 失败,将在 {Delay}ms 后进行第 {RetryCount} 次重试",
                    operationName, _delay.TotalMilliseconds, retryCount);
                    
                Console.WriteLine($"操作 {operationName} 失败,{_delay.TotalSeconds}秒后重试 ({retryCount}/{_maxRetries})");
                
                await Task.Delay(_delay);
            }
        }
    }
}

// 8. 限流代理 - 控制API调用频率
public class ThrottlingWeatherServiceProxy : IWeatherService
{
    private readonly IWeatherService _realService;
    private readonly int _maxRequestsPerMinute;
    private readonly Queue<DateTime> _requestTimestamps = new Queue<DateTime>();
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
    private readonly ILogger _logger;
    
    public ThrottlingWeatherServiceProxy(
        IWeatherService realService,
        int maxRequestsPerMinute = 60,
        ILogger logger = null)
    {
        _realService = realService;
        _maxRequestsPerMinute = maxRequestsPerMinute;
        _logger = logger;
    }
    
    public async Task<WeatherData> GetCurrentWeatherAsync(string city)
    {
        await ThrottleRequestAsync();
        return await _realService.GetCurrentWeatherAsync(city);
    }
    
    public async Task<List<WeatherData>> GetForecastAsync(string city, int days)
    {
        await ThrottleRequestAsync();
        return await _realService.GetForecastAsync(city, days);
    }
    
    public async Task<WeatherStats> GetHistoricalDataAsync(string city, DateTime startDate, DateTime endDate)
    {
        await ThrottleRequestAsync();
        return await _realService.GetHistoricalDataAsync(city, startDate, endDate);
    }
    
    private async Task ThrottleRequestAsync()
    {
        await _semaphore.WaitAsync();
        
        try
        {
            // 清除超过1分钟的请求记录
            DateTime oneMinuteAgo = DateTime.Now.AddMinutes(-1);
            while (_requestTimestamps.Count > 0 && _requestTimestamps.Peek() < oneMinuteAgo)
            {
                _requestTimestamps.Dequeue();
            }
            
            // 检查是否超出限制
            if (_requestTimestamps.Count >= _maxRequestsPerMinute)
            {
                // 计算需要等待的时间
                DateTime oldestRequest = _requestTimestamps.Peek();
                TimeSpan timeToWait = oneMinuteAgo - oldestRequest;
                
                if (timeToWait.TotalMilliseconds > 0)
                {
                    _logger?.LogWarning("已达到速率限制 ({MaxRequests}/分钟),等待 {Delay}ms",
                        _maxRequestsPerMinute, timeToWait.TotalMilliseconds);
                        
                    Console.WriteLine($"已达到API请求限制,等待 {timeToWait.TotalSeconds:F1} 秒...");
                    await Task.Delay(timeToWait);
                }
            }
            
            // 记录当前请求
            _requestTimestamps.Enqueue(DateTime.Now);
        }
        finally
        {
            _semaphore.Release();
        }
    }
}

// 9. 故障转移代理 - 在主服务失败时使用备用服务
public class FailoverWeatherServiceProxy : IWeatherService
{
    private readonly IWeatherService _primaryService;
    private readonly IWeatherService _backupService;
    private readonly ILogger _logger;
    
    public FailoverWeatherServiceProxy(
        IWeatherService primaryService,
        IWeatherService backupService,
        ILogger logger = null)
    {
        _primaryService = primaryService;
        _backupService = backupService;
        _logger = logger;
    }
    
    public async Task<WeatherData> GetCurrentWeatherAsync(string city)
    {
        try
        {
            return await _primaryService.GetCurrentWeatherAsync(city);
        }
        catch (Exception ex)
        {
            _logger?.LogWarning(ex, "主服务获取 {City} 的当前天气失败,切换到备用服务", city);
            Console.WriteLine($"主服务失败,切换到备用服务获取 {city} 的当前天气");
            return await _backupService.GetCurrentWeatherAsync(city);
        }
    }
    
    public async Task<List<WeatherData>> GetForecastAsync(string city, int days)
    {
        try
        {
            return await _primaryService.GetForecastAsync(city, days);
        }
        catch (Exception ex)
        {
            _logger?.LogWarning(ex, "主服务获取 {City} 的天气预报失败,切换到备用服务", city);
            Console.WriteLine($"主服务失败,切换到备用服务获取 {city} 的天气预报");
            return await _backupService.GetForecastAsync(city, days);
        }
    }
    
    public async Task<WeatherStats> GetHistoricalDataAsync(string city, DateTime startDate, DateTime endDate)
    {
        try
        {
            return await _primaryService.GetHistoricalDataAsync(city, startDate, endDate);
        }
        catch (Exception ex)
        {
            _logger?.LogWarning(ex, "主服务获取 {City} 的历史天气数据失败,切换到备用服务", city);
            Console.WriteLine($"主服务失败,切换到备用服务获取 {city} 的历史天气数据");
            return await _backupService.GetHistoricalDataAsync(city, startDate, endDate);
        }
    }
}

// 10. 简化代理 - 提供简化接口
public class SimplifiedWeatherServiceProxy : ISimplifiedWeatherService
{
    private readonly IWeatherService _weatherService;
    
    public SimplifiedWeatherServiceProxy(IWeatherService weatherService)
    {
        _weatherService = weatherService;
    }
    
    public async Task<string> GetWeatherSummaryAsync(string city)
    {
        try
        {
            var weather = await _weatherService.GetCurrentWeatherAsync(city);
            return $"{city}当前天气: {weather.Temperature}°C, {weather.Condition}";
        }
        catch (Exception)
        {
            return $"无法获取{city}的天气信息";
        }
    }
    
    public async Task<WeatherSummary> GetDetailedSummaryAsync(string city)
    {
        try
        {
            var current = await _weatherService.GetCurrentWeatherAsync(city);
            var forecast = await _weatherService.GetForecastAsync(city, 3);
            
            return new WeatherSummary
            {
                City = city,
                CurrentTemperature = current.Temperature,
                CurrentCondition = current.Condition,
                TomorrowForecast = forecast.Count > 1 ? forecast[1].Condition : "未知",
                TomorrowTemperature = forecast.Count > 1 ? forecast[1].Temperature : 0
            };
        }
        catch (Exception)
        {
            return new WeatherSummary
            {
                City = city,
                CurrentCondition = "数据获取失败"
            };
        }
    }
}

// 简化接口
public interface ISimplifiedWeatherService
{
    Task<string> GetWeatherSummaryAsync(string city);
    Task<WeatherSummary> GetDetailedSummaryAsync(string city);
}

public class WeatherSummary
{
    public string City { get; set; }
    public double CurrentTemperature { get; set; }
    public string CurrentCondition { get; set; }
    public string TomorrowForecast { get; set; }
    public double TomorrowTemperature { get; set; }
    
    public override string ToString()
    {
        return $"{City}: 现在 {CurrentTemperature}°C, {CurrentCondition}; 明天 {TomorrowTemperature}°C, {TomorrowForecast}";
    }
}

// 11. 天气服务工厂 - 创建代理链
public class WeatherServiceFactory
{
    private readonly IServiceProvider _serviceProvider;
    
    public WeatherServiceFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
    
    public IWeatherService CreateDefaultWeatherService()
    {
        // 创建基础服务
        var httpClient = _serviceProvider.GetRequiredService<IHttpClientFactory>().CreateClient();
        var baseService = new RemoteWeatherService(
            httpClient,
            "your-api-key-12345",
            "https://api.example.com/weather");
            
        // 创建日志记录器
        var logger = _serviceProvider.GetRequiredService<ILogger<LoggingWeatherServiceProxy>>();
        
        // 应用代理,从内到外构建
        IWeatherService service = baseService;
        
        // 添加重试
        service = new RetryWeatherServiceProxy(service, 3, TimeSpan.FromSeconds(2), logger);
        
        // 添加速率限制
        service = new ThrottlingWeatherServiceProxy(service, 30, logger);
        
        // 添加缓存
        var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
        service = new CachingWeatherServiceProxy(service, cache);
        
        // 最外层添加日志
        service = new LoggingWeatherServiceProxy(service, logger);
        
        return service;
    }
    
    public IWeatherService CreateResilientWeatherService()
    {
        // 创建主服务
        var primaryService = CreateDefaultWeatherService();
        
        // 创建备用服务
        var httpClient = _serviceProvider.GetRequiredService<IHttpClientFactory>().CreateClient();
        var backupService = new RemoteWeatherService(
            httpClient,
            "backup-api-key-67890",
            "https://backup-api.example.com/weather");
            
        var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
        backupService = new CachingWeatherServiceProxy(backupService, cache);
        
        // 创建故障转移代理
        var logger = _serviceProvider.GetRequiredService<ILogger<FailoverWeatherServiceProxy>>();
        return new FailoverWeatherServiceProxy(primaryService, backupService, logger);
    }
    
    public ISimplifiedWeatherService CreateSimplifiedService()
    {
        var weatherService = CreateDefaultWeatherService();
        return new SimplifiedWeatherServiceProxy(weatherService);
    }
}

// 12. 天气应用 - 使用代理服务
public class WeatherApp
{
    private readonly IWeatherService _weatherService;
    private readonly ISimplifiedWeatherService _simplifiedService;
    private readonly ILogger<WeatherApp> _logger;
    
    public WeatherApp(
        IWeatherService weatherService,
        ISimplifiedWeatherService simplifiedService,
        ILogger<WeatherApp> logger)
    {
        _weatherService = weatherService;
        _simplifiedService = simplifiedService;
        _logger = logger;
    }
    
    public async Task RunAsync()
    {
        Console.WriteLine("=== 天气应用启动 ===\n");
        
        try
        {
            // 查询当前天气
            await ShowCurrentWeatherAsync();
            
            // 查询天气预报
            await ShowForecastAsync();
            
            // 查询历史数据
            await ShowHistoricalDataAsync();
            
            // 使用简化服务
            await ShowSimplifiedWeatherAsync();
            
            // 连续请求测试
            await TestMultipleRequestsAsync();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "应用运行时出错");
            Console.WriteLine($"应用错误: {ex.Message}");
        }
    }
    
    private async Task ShowCurrentWeatherAsync()
    {
        Console.WriteLine("=== 当前天气 ===");
        
        string[] cities = { "北京", "上海", "广州", "深圳" };
        
        foreach (string city in cities)
        {
            try
            {
                var weather = await _weatherService.GetCurrentWeatherAsync(city);
                Console.WriteLine($"{city}: {weather.Temperature}°C, {weather.Condition}, 湿度: {weather.Humidity}%, 风速: {weather.WindSpeed}km/h");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"{city}: 获取天气失败 - {ex.Message}");
            }
        }
        
        Console.WriteLine();
    }
    
    private async Task ShowForecastAsync()
    {
        Console.WriteLine("=== 三天天气预报 ===");
        
        try
        {
            var forecast = await _weatherService.GetForecastAsync("北京", 3);
            
            foreach (var day in forecast)
            {
                Console.WriteLine($"{day.Date:MM-dd}: {day.Temperature}°C, {day.Condition}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取天气预报失败 - {ex.Message}");
        }
        
        Console.WriteLine();
    }
    
    private async Task ShowHistoricalDataAsync()
    {
        Console.WriteLine("=== 历史天气数据 ===");
        
        try
        {
            var startDate = DateTime.Now.AddMonths(-1);
            var endDate = DateTime.Now.AddDays(-1);
            
            var stats = await _weatherService.GetHistoricalDataAsync("上海", startDate, endDate);
            Console.WriteLine(stats);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取历史天气数据失败 - {ex.Message}");
        }
        
        Console.WriteLine();
    }
    
    private async Task ShowSimplifiedWeatherAsync()
    {
        Console.WriteLine("=== 简化天气信息 ===");
        
        string[] cities = { "成都", "武汉", "杭州" };
        
        foreach (string city in cities)
        {
            // 简单摘要
            string summary = await _simplifiedService.GetWeatherSummaryAsync(city);
            Console.WriteLine(summary);
            
            // 详细摘要
            WeatherSummary detailed = await _simplifiedService.GetDetailedSummaryAsync(city);
            Console.WriteLine(detailed);
        }
        
        Console.WriteLine();
    }
    
    private async Task TestMultipleRequestsAsync()
    {
        Console.WriteLine("=== 连续请求测试 (速率限制演示) ===");
        
        // 创建多个请求以测试速率限制
        var tasks = new List<Task>();
        
        for (int i = 0; i < 10; i++)
        {
            int index = i;
            tasks.Add(Task.Run(async () =>
            {
                try
                {
                    Console.WriteLine($"请求 {index} 开始...");
                    var weather = await _weatherService.GetCurrentWeatherAsync("北京");
                    Console.WriteLine($"请求 {index} 完成: {weather.Temperature}°C");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"请求 {index} 失败: {ex.Message}");
                }
            }));
        }
        
        await Task.WhenAll(tasks);
        
        Console.WriteLine("连续请求测试完成");
        Console.WriteLine();
    }
}

// 13. 程序入口
public class Program
{
    public static async Task Main()
    {
        // 设置依赖注入
        var services = new ServiceCollection();
        
        // 添加日志
        services.AddLogging(builder =>
        {
            builder.AddConsole();
            builder.SetMinimumLevel(LogLevel.Information);
        });
        
        // 添加HttpClient工厂
        services.AddHttpClient();
        
        // 添加内存缓存
        services.AddMemoryCache();
        
        // 注册服务工厂
        services.AddSingleton<WeatherServiceFactory>();
        
        // 注册服务
        services.AddSingleton<IWeatherService>(provider =>
            provider.GetRequiredService<WeatherServiceFactory>().CreateDefaultWeatherService());
            
        services.AddSingleton<ISimplifiedWeatherService>(provider =>
            provider.GetRequiredService<WeatherServiceFactory>().CreateSimplifiedService());
            
        services.AddSingleton<WeatherApp>();
        
        // 构建服务提供者
        var serviceProvider = services.BuildServiceProvider();
        
        // 运行应用
        var app = serviceProvider.GetRequiredService<WeatherApp>();
        await app.RunAsync();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
编辑 (opens new window)
#pattern
上次更新: 2026/03/11, 07:20:31
创建型
行为型一

← 创建型 行为型一→

最近更新
01
鉴权服务中心
03-11
02
聚合根
03-11
03
补充
02-06
更多文章>
Theme by Vdoing | Copyright © 2019-2026 moklgy's blog
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式