电子商务网站建设与管理王生春/惠城网站设计

电子商务网站建设与管理王生春,惠城网站设计,公司宣传网站怎么做,网站备案号不存在目录 一、策略模式概述二、策略模式的实现2.1 策略接口2.2 具体策略类2.3 上下文类2.4 客户端代码2.5 UML类图2.6 UML时序图 三、优缺点3.1 ✅优点3.2 ❌ 缺点 四、最佳实践场景4.1 适合场景描述4.2 具体场景 五、扩展5.1 继承复用机制和复合策略5.2 对象管理:优化策…

目录

  • 一、策略模式概述
  • 二、策略模式的实现
    • 2.1 策略接口
    • 2.2 具体策略类
    • 2.3 上下文类
    • 2.4 客户端代码
    • 2.5 UML类图
    • 2.6 UML时序图
  • 三、优缺点
    • 3.1 ✅优点
    • 3.2 ❌ 缺点
  • 四、最佳实践场景
    • 4.1 适合场景描述
    • 4.2 具体场景
  • 五、扩展
    • 5.1 继承复用机制和复合策略
    • 5.2 对象管理:优化策略类数量增加问题优化
      • 5.2.1 策略对象数量优化:将无状态策略设计为共享对象(使用 Flyweight 模式)
      • 5.2.2 上下文负责维护策略执行所需状态
      • 5.2.3 轻量级策略推荐单例实现,重型策略考虑对象池
    • 5.3 策略与上下文的通信成本优化
      • 5.3.1 参数封装
      • 5.3.2 适配器模式
    • 5.4 客户端与策略解耦优化
  • 六、使用建议

参考:
设计模式:可复用面向对象软件的基础(典藏版) - 5.9 Strategy(策略)——对象行为型模式 - 埃里克·伽玛 - 微信读书

项目地址:(https://github.com/Nita121388/NitasDemo/tree/main/10DesignPatterns/DesignPatterns/StrategyPattern)[策略模式]

相关标签:行为型设计模式、算法封装、切换、享元模式、工厂模式、

一、策略模式概述

策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列算法,将每个算法封装起来,并使它们可以互换使用。策略模式让算法的变化独立于使用算法的客户。

核心思想:通过将算法封装为独立对象,实现运行时的算法选择。

  • 动机

    以开发一个文本编辑器为例,其中需要实现自动换行功能。这个功能可能有多种实现方式:简单换行(按字符数强制分割)、连字符优化换行等

    现实开发中的痛点

    • 扩展性差:混杂各种换行逻辑,核心功能被算法细节淹没。当新增加新功能时,需要冒着风险修改经过测试的编辑器核心类
    • 灵活性不足:当不同文档类型需要不同换行策略时,需要复杂的条件判断
    • 复用性低:当需要为移动端定制换行策略时,不得不创建大量重复代码
      策略模式如何解决问题?
      通过将换行算法抽象为独立模块:
    1. 解耦核心逻辑:文本编辑器只需关注文本处理,不关心具体换行实现
    2. 动态切换策略:根据文档类型、设备类型或用户设置,在运行时自由切换算法
    3. 安全扩展:新增算法只需添加新类,无需修改现有代码(符合开闭原则)
    4. 清晰复用:其他需要换行功能的模块可以直接调用策略集合
  • 核心概念/角色

    • 📜策略接口(Strategy):定义了所有支持算法的公共接口,上下文(Context)使用这个接口来调用具体的策略类。
    • 具体策略类(Concrete Strategy):实现了策略接口,提供具体的算法实现。
    • 🔄上下文(Context):持有一个策略接口的引用,用于调用策略类的方法。上下文可以动态地改变其引用的策略对象。
  • 策略模式核心价值

    • 将算法封装为独立对象
    • 实现运行时的灵活切换
    • 提高系统的扩展性和维护性

    关键洞察:策略模式不是简单地封装不同实现,而是通过建立清晰的算法供应链,让业务逻辑与具体算法实现形成「松耦合,高内聚」的协作关系。

二、策略模式的实现

2.1 策略接口

策略接口定义了所有策略类的公共方法,客户端通过这个接口与具体的策略类交互。

public interface IStrategy
{void Execute(int a, int b);
}

2.2 具体策略类

每个具体策略类都实现了策略接口,并提供了具体的算法实现。

public class AddStrategy : IStrategy
{public void Execute(int a, int b){Console.WriteLine($"Add: {a} + {b} = {a + b}");}
}public class SubtractStrategy : IStrategy
{public void Execute(int a, int b){Console.WriteLine($"Subtract: {a} - {b} = {a - b}");}
}public class MultiplyStrategy : IStrategy
{public void Execute(int a, int b){Console.WriteLine($"Multiply: {a} * {b} = {a * b}");}
}

2.3 上下文类

上下文类持有一个策略接口的引用,并通过这个引用调用具体的策略方法。上下文可以根据需要动态地更换策略。

public class Context
{private IStrategy _strategy;public Context(IStrategy strategy){_strategy = strategy;}public void SetStrategy(IStrategy strategy){_strategy = strategy;}public void ExecuteStrategy(int a, int b){_strategy.Execute(a, b);}
}

2.4 客户端代码

客户端通过上下文类调用具体的策略方法,并可以在运行时动态更换策略。

class Program
{static void Main(string[] args){// 创建具体策略IStrategy addStrategy = new AddStrategy();IStrategy subtractStrategy = new SubtractStrategy();IStrategy multiplyStrategy = new MultiplyStrategy();// 设置初始策略Context context = new Context(addStrategy);context.ExecuteStrategy(10, 5);// 更改策略context.SetStrategy(subtractStrategy);context.ExecuteStrategy(10, 5);// 更改策略context.SetStrategy(multiplyStrategy);context.ExecuteStrategy(10, 5);}
}

2.5 UML类图

implements
implements
implements
_strategy
«interface»
IStrategy
+Execute(int a, int b) : void
AddStrategy
+Execute(int a, int b) : void
SubtractStrategy
+Execute(int a, int b) : void
MultiplyStrategy
+Execute(int a, int b) : void
Context
-_strategy: IStrategy
+Context(IStrategy strategy)
+SetStrategy(IStrategy strategy) : void
+ExecuteStrategy(int a, int b) : void

2.6 UML时序图

Client Context AddStrategy SubtractStrategy MultiplyStrategy 创建 new AddStrategy() 创建 new SubtractStrategy() 创建 new MultiplyStrategy() 创建 new Context(addStrategy) ExecuteStrategy(10,5) Execute(10,5) 输出结果 完成 SetStrategy(subtractStrategy) 策略已切换 ExecuteStrategy(10,5) Execute(10,5) 输出结果 完成 SetStrategy(multiplyStrategy) 策略已切换 ExecuteStrategy(10,5) Execute(10,5) 输出结果 完成 Client Context AddStrategy SubtractStrategy MultiplyStrategy

三、优缺点

3.1 ✅优点

  1. 算法的独立性:每个算法封装在独立的类中,便于维护和单元测试。
  2. 消除条件分支:替代了传统方式中繁琐的条件判断(如if-elseswitch-case结构),每个策略类封装独立行为逻辑,使代码更简洁、易读。
  3. 符合开闭原则:新增算法时只需添加新的策略类,无需修改现有的代码结构,系统对扩展开放、对修改关闭。
  4. 动态切换能力:运行时可灵活切换不同的策略实现,无需重新编译,系统更灵活。
  5. 代码清晰与可维护性:通过上下文(Context)与策略解耦,消除算法硬编码,使业务逻辑更清晰,减少维护成本。

3.2 ❌ 缺点

  1. 类的数量增加 : 每种策略需要一个独立的类,可能导致类的数量过多。

  2. 客户端需要了解所有策略 :客户端需要知道不同策略的具体实现,以便选择合适的策略。

  3. 可能导致过度设计 :对于简单的场景,使用策略模式可能显得过于复杂。

  4. 维护策略的上下文 :上下文需要维护与策略相关的状态,可能增加复杂性。

    在策略模式中,上下文需要知道当前使用的是哪个策略,并且在一些情况下,上下文还需要保存一些与策略相关的状态。

    举个例子:

    一个订单处理系统,有不同的折扣策略,比如会员折扣、节日折扣等。这些策略可能会根据订单金额来计算折扣。

    1. 上下文的角色
      • 上下文类需要知道当前的折扣策略是什么(比如是会员折扣还是节日折扣)。
      • 它还需要保存订单金额这个状态,以便在计算折扣时使用。
    2. 复杂性问题
      • 上下文需要管理这些状态信息,确保在切换策略时状态是正确的。
      • 如果策略比较多,或者策略之间的状态依赖关系复杂,上下文的代码就会变得复杂,增加了理解和维护的难度。

四、最佳实践场景

4.1 适合场景描述

  • 需要多种算法变体时 🧮
  • 需要运行时切换算法 🔄
  • 需要隔离算法逻辑与业务逻辑📦
  • 消除多个条件判断语句 🚮

4.2 具体场景

  1. 算法变体密集场景
    • 如加密算法(AES、DES)需根据不同安全级别灵活切换。
    • 支付网关:银联、支付宝、微信等支付策略。
  2. 业务规则波动频繁
    • 促销活动规则(满减、折扣、赠品等)
    • 物流配送策略(标准、特快、无人机)
  3. 复杂算法隔离需求
    • 机器学习模型(决策树、神经网络、线性回归)
    • 数据处理流程(批处理、流处理、实时处理)
  4. 多种验证方式
    • 不同用户身份验证(人脸识别、指纹识别、短信验证码等)

五、扩展

5.1 继承复用机制和复合策略

  1. 继承复用机制:可以通过共同的接口或抽象类提取公共逻辑,减少重复代码,支持策略族的复用,促进算法演进。
  2. 复合策略扩展:支持组合多个策略应对复杂场景,如组合风险评估和税务优化策略,增强系统可扩展性。

以下是一个结合继承复用复合策略扩展的C#策略模式示例,以投资决策系统场景为例:

  • 策略接口(抽象策略)

    // 策略接口(抽象策略)
    public interface IInvestmentStrategy
    {void Execute(Portfolio portfolio);
    }
    
  • 抽象策略基类(继承复用)

    • 封装公共验证逻辑ValidatePortfolio
    • 强制子类实现核心算法Execute
    • 支持统一添加日志、监控等横切关注点
    • 典型应用:所有具体策略继承公共验证和日志逻辑
    // 抽象策略基类(继承复用)
    public abstract class CommonStrategy : IInvestmentStrategy
    {// 公共验证方法protected void ValidatePortfolio(Portfolio portfolio){if (portfolio.TotalValue <= 0)throw new ArgumentException("Invalid portfolio value");}// 抽象方法要求子类必须实现public abstract void Execute(Portfolio portfolio);
    }
    
  • 具体策略

    • 具体策略1:风险评估策略(继承复用公共逻辑)

      // 具体策略1:风险评估策略(继承复用公共逻辑)
      public class RiskAssessmentStrategy : CommonStrategy
      {public override void Execute(Portfolio portfolio){ValidatePortfolio(portfolio); // 复用基类验证// 具体风险计算逻辑portfolio.RiskLevel = CalculateRisk(portfolio.Assets);Console.WriteLine($"风险评估完成,当前风险等级:{portfolio.RiskLevel}");}private RiskLevel CalculateRisk(IEnumerable<Asset> assets){// 实际风险计算逻辑return RiskLevel.Moderate;}
      }
    • 具体策略2:税务优化策略(继承复用公共逻辑)

      
      // 具体策略2:税务优化策略(继承复用公共逻辑)
      public class TaxOptimizationStrategy : CommonStrategy
      {public override void Execute(Portfolio portfolio){ValidatePortfolio(portfolio); // 复用基类验证// 具体税务优化逻辑portfolio.TaxBurden = OptimizeTax(portfolio.Investments);Console.WriteLine($"税务优化完成,税务负担减少:{portfolio.TaxBurden}%");}private decimal OptimizeTax(IEnumerable<Investment> investments){// 实际税务优化逻辑return 15.5m;}
      }
      
    • 具体策略3:流动性分析策略(继承复用公共逻辑)

      #region - 具体策略3:流动性分析策略(继承复用公共逻辑)
      public class LiquidityAnalysisStrategy : CommonStrategy
      {public override void Execute(Portfolio portfolio){ValidatePortfolio(portfolio); // 复用基类验证// 具体流动性分析逻辑portfolio.LiquidityScore = CalculateLiquidity(portfolio.Assets);Console.WriteLine($"流动性分析完成,流动性得分:{portfolio.LiquidityScore}");}private decimal CalculateLiquidity(IEnumerable<Asset> assets){// 示例流动性计算逻辑:假设流动性得分基于资产价值的加权平均decimal totalValue = assets.Sum(a => a.Value);decimal liquidityScore = assets.Sum(a => a.Value * a.LiquidityFactor) / totalValue;return liquidityScore;}
      }
      #endregion
      
  • 复合策略(策略扩展)

    • 动态组合多个策略(如风险+税务+流动性分析)
    • 支持策略执行顺序控制(通过添加顺序)
    • 允许运行时动态调整策略组合
    • 典型应用:构建投资策略流水线
    // 复合策略(策略扩展)
    public class CompositeStrategy : IInvestmentStrategy
    {private readonly List _strategies = new();public void AddStrategy(IInvestmentStrategy strategy){_strategies.Add(strategy);}public void Execute(Portfolio portfolio){foreach (var strategy in _strategies){strategy.Execute(portfolio);}}
    }
    
  • 上下文类

    // 上下文类
    public class PortfolioManager
    {private IInvestmentStrategy _strategy;public void SetStrategy(IInvestmentStrategy strategy){_strategy = strategy;}public void ExecuteStrategy(Portfolio portfolio){_strategy?.Execute(portfolio);}
    }
  • Client Code 、使用示例

    
    // 使用示例
    var portfolio = new Portfolio();
    var manager = new PortfolioManager();// 使用单一策略
    manager.SetStrategy(new RiskAssessmentStrategy());
    manager.ExecuteStrategy(portfolio);// 使用复合策略
    var composite = new CompositeStrategy();
    composite.AddStrategy(new RiskAssessmentStrategy());
    composite.AddStrategy(new TaxOptimizationStrategy());
    composite.AddStrategy(new LiquidityAnalysisStrategy()); // 新增策略manager.SetStrategy(composite);
    manager.ExecuteStrategy(portfolio);

    输出

    风险评估完成,当前风险等级:Moderate
    风险评估完成,当前风险等级:Moderate
    税务优化完成,税务负担减少:15.5%
    流动性分析完成,流动性得分:0.8666666666666666666666666667
  • 关键设计说明

    • 策略族的统一管理(通过接口和抽象类)
    • 算法实现的隔离变化(具体策略独立演进)
    • 复杂业务场景的灵活组合(复合策略)
    • 公共能力的集中维护(验证、日志等)
    • 符合开闭原则
      • 新增策略只需实现IInvestmentStrategy
      • 策略演进不影响客户端代码
      • 复合策略可以嵌套其他复合策略
      • 支持策略优先级配置(通过修改复合策略实现)

5.2 对象管理:优化策略类数量增加问题优化

5.2.1 策略对象数量优化:将无状态策略设计为共享对象(使用 Flyweight 模式)

场景:假设有一个图像处理系统,支持多种图像滤镜(如黑白滤镜、模糊滤镜、锐化滤镜等)。这些滤镜是无状态的,即它们的行为不依赖于任何内部状态。

优化方式:使用 Flyweight 模式将无状态策略设计为共享对象。

  • 定义策略接口

    // 定义策略接口
    public interface IFilterStrategy
    {void ApplyFilter(string image);
    }
    
  • 具体策略类:黑白滤镜

    // 具体策略类:黑白滤镜
    public class BlackAndWhiteFilter : IFilterStrategy
    {public void ApplyFilter(string image){Console.WriteLine($"Applying Black and White filter to {image}");}
    }
    
  • 具体策略类:模糊滤镜

    // 具体策略类:模糊滤镜
    public class BlurFilter : IFilterStrategy
    {public void ApplyFilter(string image){Console.WriteLine($"Applying Blur filter to {image}");}
    }
    
  • 策略工厂类(Flyweight 模式)

    1. Flyweight 模式的核心:通过一个静态字典_filters来存储已经创建的策略对象。这样可以避免重复创建相同类型的策略对象。
    2. 单例模式的应用:由于_filters是静态的,FilterFactory类在整个程序中只会维护一份策略对象的映射关系。
    3. 策略对象的复用:当客户端请求某个类型的滤镜时,GetFilter方法会先检查_filters是否已经存在该类型的策略对象。如果不存在,则创建一个新的策略对象并存储在字典中;如果已经存在,则直接返回已有的对象。
    4. 优化效果:通过这种方式,系统中每种类型的策略对象只会被创建一次,大大减少了对象的实例化数量,节省了内存。
    // 策略工厂类(Flyweight 模式)
    public class FilterFactory
    {private static readonly Dictionary<string, IFilterStrategy> _filters = new Dictionary<string, IFilterStrategy>();public static IFilterStrategy GetFilter(string filterType){if (!_filters.ContainsKey(filterType)){switch (filterType){case "BlackAndWhite":_filters[filterType] = new BlackAndWhiteFilter();break;case "Blur":_filters[filterType] = new BlurFilter();break;default:throw new ArgumentException("Invalid filter type");}}return _filters[filterType];}
    }
    
  • 上下文类

    // 上下文类
    public class ImageProcessor
    {private IFilterStrategy _filterStrategy;public void SetFilterStrategy(IFilterStrategy filterStrategy){_filterStrategy = filterStrategy;}public void ProcessImage(string image){_filterStrategy.ApplyFilter(image);}
    }
  • Client Code

    using System;// 客户端代码
    public class Program
    {public static void Main(){var processor = new ImageProcessor();// 使用共享的黑白滤镜策略对象processor.SetFilterStrategy(FilterFactory.GetFilter("BlackAndWhite"));processor.ProcessImage("image1.jpg");// 使用共享的模糊滤镜策略对象processor.SetFilterStrategy(FilterFactory.GetFilter("Blur"));processor.ProcessImage("image2.jpg");}
    }
    

    结果

    Applying Black and White filter to image1.jpg
    Applying Blur filter to image2.jpg

5.2.2 上下文负责维护策略执行所需状态

场景:假设我们有一个订单处理系统,支持不同的折扣策略(如会员折扣、节日折扣等)。这些策略可能需要访问上下文中的状态(如订单金额)。

优化方式:上下文负责维护策略执行所需的状态。

  • 定义策略接口

    // 定义策略接口
    public interface IDiscountStrategy
    {decimal ApplyDiscount(decimal orderAmount);
    }
    
  • 具体策略类:会员折扣 和 具体策略类:节日折扣

    // 具体策略类:会员折扣
    public class MemberDiscount : IDiscountStrategy
    {public decimal ApplyDiscount(decimal orderAmount){return orderAmount * 0.9m; // 10% 折扣}
    }// 具体策略类:节日折扣
    public class HolidayDiscount : IDiscountStrategy
    {public decimal ApplyDiscount(decimal orderAmount){return orderAmount * 0.8m; // 20% 折扣}
    }
    
  • 上下文类

    public class OrderProcessor
    {private IDiscountStrategy _discountStrategy; // 当前使用的折扣策略private decimal _orderAmount;                // 订单金额,策略执行所需的状态public OrderProcessor(decimal orderAmount){_orderAmount = orderAmount; // 初始化订单金额}public void SetDiscountStrategy(IDiscountStrategy discountStrategy){_discountStrategy = discountStrategy; // 设置当前的折扣策略}public decimal ProcessOrder(){return _discountStrategy.ApplyDiscount(_orderAmount); // 调用策略对象的 ApplyDiscount 方法}
    }
    

    OrderProcessor 类是上下文类,它负责维护订单金额 _orderAmount,并提供一个方法来设置折扣策略 _discountStrategy。它的主要职责是:

    • 维护状态:保存订单金额 _orderAmount,这是策略执行时需要使用的状态。
    • 策略切换:通过 SetDiscountStrategy 方法动态设置不同的折扣策略。
    • 执行策略:在 ProcessOrder 方法中调用当前设置的折扣策略的 ApplyDiscount 方法,并将订单金额传递给策略对象。
  • Client

    var order = new OrderProcessor(100m);// 使用会员折扣策略order.SetDiscountStrategy(new MemberDiscount());Console.WriteLine($"Member Discount: {order.ProcessOrder()}");// 使用节日折扣策略order.SetDiscountStrategy(new HolidayDiscount());Console.WriteLine($"Holiday Discount: {order.ProcessOrder()}");
    

解释OrderProcessor 上下文类负责维护订单金额,并将其传递给策略对象。这样,策略对象不需要自己维护状态,减少了类的复杂性。

5.2.3 轻量级策略推荐单例实现,重型策略考虑对象池

场景:假设我们有一个日志系统,支持不同的日志输出策略(如控制台输出、文件输出等)。控制台输出策略是轻量级的,而文件输出策略是资源密集型的。

优化方式:轻量级策略使用单例模式,重型策略使用对象池。

  • 策略接口定义

    public interface ILogStrategy
    {void Log(string message);
    }
    
  • 具体策略类:控制台输出策略(单例模式)

    说明

    • 实现了ILogStrategy接口,用于将日志输出到控制台。
    • 使用了单例模式,确保整个程序中只有一个ConsoleLogStrategy实例。
    • Log方法将日志信息以控制台输出的形式展示。
    public class ConsoleLogStrategy : ILogStrategy
    {private static readonly ConsoleLogStrategy _instance = new ConsoleLogStrategy();private ConsoleLogStrategy() { }public static ConsoleLogStrategy Instance => _instance;public void Log(string message){Console.WriteLine($"Console Log: {message}");}
    }
    
  • 具体策略类:文件输出策略

    public class FileLogStrategy : ILogStrategy
    {public void Log(string message){Console.WriteLine($"File Log: {message}");}
    }
    
  • 对象池管理文件输出策略

    说明

    • 使用对象池模式管理FileLogStrategy实例。
    • 静态构造函数初始化了对象池,预先创建了5个FileLogStrategy实例。
    • Acquire方法用于从池中获取一个实例,如果池为空,则创建新的实例。
    • Release方法将使用完毕的实例放回对象池,以便复用。
    public class FileLogStrategyPool
    {private static readonly Queue _pool = new Queue();static FileLogStrategyPool(){for (int i = 0; i < 5; i++){_pool.Enqueue(new FileLogStrategy());}}public static FileLogStrategy Acquire(){if (_pool.Count > 0){return _pool.Dequeue();}return new FileLogStrategy();}public static void Release(FileLogStrategy strategy){_pool.Enqueue(strategy);}
    }
    
  • 上下文类:日志记录器

    说明

    • Logger类是策略模式的上下文类,用于封装日志记录的逻辑。
    • 客户端可以通过SetLogStrategy方法动态设置日志策略。
    • Log方法调用当前策略的Log方法,实现日志记录。
    public class Logger
    {private ILogStrategy _logStrategy;public void SetLogStrategy(ILogStrategy logStrategy){_logStrategy = logStrategy;}public void Log(string message){_logStrategy.Log(message);}
    }
    
  • 客户端代码

    说明

    • 方式1:使用单例的ConsoleLogStrategy将日志输出到控制台。
    • 方式2:从对象池中获取一个FileLogStrategy实例,将日志输出到文件,并在使用完毕后将其释放回对象池。
    var logger = new Logger();// 使用单例的控制台输出策略
    logger.SetLogStrategy(ConsoleLogStrategy.Instance);
    logger.Log("This is a log message.");// 使用对象池的文件输出策略
    var fileLogStrategy = FileLogStrategyPool.Acquire();
    logger.SetLogStrategy(fileLogStrategy);
    logger.Log("This is a file log message.");
    FileLogStrategyPool.Release(fileLogStrategy);
    

    输出

    Console Log: This is a log message.
    File Log: This is a file log message.

解释ConsoleLogStrategy 使用单例模式来减少内存消耗,而 FileLogStrategy 使用对象池来管理资源密集型对象的生命周期,避免频繁的创建与销毁。

5.3 策略与上下文的通信成本优化

当不同策略需要不同参数时,上下文需处理多种参数类型,导致接口复杂且类型不安全。

5.3.1 参数封装

将参数封装到统一对象中,减少接口复杂性。

  • 参数封装类用于存储支付过程中需要的参数信息。

    说明

    此部分将支付相关的参数封装到一个类中,方便在不同支付策略中传递和使用。

    这种封装方式提高了代码的可维护性和可扩展性。

    public class PaymentParameters
    {public string CardNumber { get; set; }      // 信用卡卡号public string SecurityCode { get; set; }    // 信用卡安全码public string PhoneNumber { get; set; }     // 支付宝绑定的手机号
    }
    
  • 策略接口:IPaymentStrategy

    • 策略模式的核心是定义一个通用接口,让不同的策略类实现该接口。
    • 这里定义了一个ProcessPayment方法,所有具体的支付策略类(如信用卡支付、支付宝支付)都必须实现该方法。
    public interface IPaymentStrategy
    {void ProcessPayment(double amount, PaymentParameters parameters);  // 定义支付方法
    }
    
  • 具体策略类

    • 信用卡支付策略:CreditCardStrategy

      说明

      • 这是信用卡支付的具体实现。
      • 在支付前,会检查信用卡号和安全码是否为空。如果为空,抛出异常。
      • 如果信息完整,则输出支付信息。
      public class CreditCardStrategy : IPaymentStrategy
      {public void ProcessPayment(double amount, PaymentParameters parameters){if (string.IsNullOrEmpty(parameters.CardNumber) || string.IsNullOrEmpty(parameters.SecurityCode)){throw new ArgumentException("信用卡信息缺失");}Console.WriteLine($"信用卡支付:金额={amount}, 卡号={parameters.CardNumber}, 安全码={parameters.SecurityCode}");}
      }
      
    • 支付宝支付策略:AlipayStrategy

      说明

      • 这是支付宝支付的具体实现。
      • 在支付前,会检查手机号是否为空。如果为空,抛出异常。
      • 如果手机号有效,则输出支付信息。
      public class AlipayStrategy : IPaymentStrategy
      {public void ProcessPayment(double amount, PaymentParameters parameters){if (string.IsNullOrEmpty(parameters.PhoneNumber)){throw new ArgumentException("手机号缺失");}Console.WriteLine($"支付宝支付:金额={amount}, 手机号={parameters.PhoneNumber}");}
      }
      
  • 上下文类:PaymentContext

    上下文类用于动态切换支付策略,并调用对应的支付方法。

    说明

    • PaymentContext类提供了一个接口来设置和执行支付策略。
    • _strategy属性用于存储当前的支付策略。
    • SetStrategy方法用于动态切换支付策略。
    • ExecutePayment方法调用当前策略的ProcessPayment方法,完成支付操作。
    public class PaymentContext
    {private IPaymentStrategy _strategy;  // 当前使用的支付策略public void SetStrategy(IPaymentStrategy strategy){_strategy = strategy;  // 设置当前支付策略}public void ExecutePayment(double amount, PaymentParameters parameters){_strategy?.ProcessPayment(amount, parameters);  // 调用当前策略的支付方法}
    }
    
  • Client Code

    说明

    • 创建了PaymentParameters 参数对象并设置了支付参数。
    • 创建了PaymentContext对象,并通过SetStrategy方法动态切换支付策略。
    • 调用ExecutePayment方法执行支付操作。
    • 通过切换策略,可以轻松地在不同支付方式之间切换,展示了策略模式的灵活性。
    public class Program
    {public static void Main(){var parameters = new PaymentParameters{CardNumber = "1234-5678-9012-3456",  // 信用卡卡号SecurityCode = "123",                // 信用卡安全码PhoneNumber = "13812345678"          // 支付宝绑定的手机号};var context = new PaymentContext();// 使用信用卡支付context.SetStrategy(new CreditCardStrategy());context.ExecutePayment(100.0, parameters);// 切换为支付宝支付context.SetStrategy(new AlipayStrategy());context.ExecutePayment(200.0, parameters);}
    }
    

    输出

    信用卡支付:金额=100, 卡号=1234-5678-9012-3456, 安全码=123
    支付宝支付:金额=200, 手机号=13812345678

5.3.2 适配器模式

通过适配器将不同参数转换为通用格式,简化交互。

  • 通用参数接口(IPaymentParameters

    • 说明

      定义了一个通用接口,用于获取支付参数。GetParameter<T> 方法通过泛型和键值对的方式,允许不同类型的支付方式提供参数访问功能。

    public interface IPaymentParameters
    {T GetParameter<T>(string key);
    }
    
  • 参数适配器

    • 信用卡参数适配器(CreditCardAdapter

      • 功能说明
        • 信用卡支付需要提供卡号和安全码。
        • 通过 GetParameter<T> 方法,根据键值返回对应的参数。
      public class CreditCardAdapter : IPaymentParameters
      {private readonly string _cardNumber;private readonly string _securityCode;public CreditCardAdapter(string cardNumber, string securityCode){_cardNumber = cardNumber;_securityCode = securityCode;}public T GetParameter<T>(string key){switch (key){case "CardNumber": return (T)(object)_cardNumber;case "SecurityCode": return (T)(object)_securityCode;default: throw new KeyNotFoundException($"参数 {key} 不存在");}}
      }
      
    • 支付宝参数适配器(AlipayAdapter

      • 功能说明
        • 支付宝支付需要提供手机号。
        • 通过 GetParameter<T> 方法,根据键值返回对应的参数。
      public class AlipayAdapter : IPaymentParameters
      {private readonly string _phoneNumber;public AlipayAdapter(string phoneNumber){_phoneNumber = phoneNumber;}public T GetParameter<T>(string key){if (key == "PhoneNumber") return (T)(object)_phoneNumber;throw new KeyNotFoundException($"参数 {key} 不存在");}
      }
      
  • 策略接口(IPaymentStrategy

    • 功能说明
      • 定义了支付策略的通用接口。
      • ProcessPayment 方法用于处理支付逻辑,接受金额和支付参数。
    public interface IPaymentStrategy
    {void ProcessPayment(double amount, IPaymentParameters parameters);
    }
    
  • 具体策略类

    • 信用卡支付策略(CreditCardStrategy

      • 功能说明
        • 从参数适配器中获取卡号和安全码。
        • 打印信用卡支付的详细信息。
      public class CreditCardStrategy : IPaymentStrategy
      {public void ProcessPayment(double amount, IPaymentParameters parameters){string cardNumber = parameters.GetParameter<string>("CardNumber");string securityCode = parameters.GetParameter<string>("SecurityCode");Console.WriteLine($"信用卡支付:金额={amount}, 卡号={cardNumber}, 安全码={securityCode}");}
      }
      
    • 支付宝支付策略(AlipayStrategy

      • 功能说明
        • 从参数适配器中获取手机号。
        • 打印支付宝支付的详细信息。
      public class AlipayStrategy : IPaymentStrategy
      {public void ProcessPayment(double amount, IPaymentParameters parameters){string phone = parameters.GetParameter<string>("PhoneNumber");Console.WriteLine($"支付宝支付:金额={amount}, 手机号={phone}");}
      }
      
  • 上下文类(PaymentContext

    • 功能说明
      • 管理具体的支付策略。
      • 通过 SetStrategy 方法设置支付策略。
      • 通过 ExecutePayment 方法执行支付操作。
    public class PaymentContext
    {private IPaymentStrategy _strategy;public void SetStrategy(IPaymentStrategy strategy){_strategy = strategy;}public void ExecutePayment(double amount, IPaymentParameters parameters){_strategy?.ProcessPayment(amount, parameters);}
    }
    
  • 使用示例(Program 类)

    • 功能说明
      • 创建支付上下文。
      • 设置不同的支付策略并执行支付操作。
      • 演示了如何通过策略模式切换不同的支付方式。
    public class Program
    {public static void Main(){var context = new PaymentContext();// 信用卡支付var creditCardParams = new CreditCardAdapter("1234-5678-9012-3456", "123");context.SetStrategy(new CreditCardStrategy());context.ExecutePayment(100.0, creditCardParams);// 支付宝支付var alipayParams = new AlipayAdapter("13812345678");context.SetStrategy(new AlipayStrategy());context.ExecutePayment(200.0, alipayParams);}
    }
    
  • 类图

    聚合
    依赖
    依赖
    依赖
    依赖
    依赖
    «interface»
    IPaymentParameters
    +GetParameter~T~(string key)
    CreditCardAdapter
    -_cardNumber: string
    -_securityCode: string
    +CreditCardAdapter(string, string)
    +GetParameter~T~(string key)
    AlipayAdapter
    -_phoneNumber: string
    +AlipayAdapter(string)
    +GetParameter~T~(string key)
    «interface»
    IPaymentStrategy
    +ProcessPayment(double, IPaymentParameters) : void
    CreditCardStrategy
    +ProcessPayment(double, IPaymentParameters) : void
    AlipayStrategy
    +ProcessPayment(double, IPaymentParameters) : void
    PaymentContext
    -_strategy: IPaymentStrategy
    +SetStrategy(IPaymentStrategy) : void
    +ExecutePayment(double, IPaymentParameters) : void
    Program
    +Main() : void
  • 时序图

    Program PaymentContext CreditCardStrategy CreditCardAdapter AlipayStrategy AlipayAdapter Console 信用卡支付流程 创建实例 创建实例("1234...", "123") SetStrategy(CreditCardStrategy) ExecutePayment(100.0, creditCardParams) ProcessPayment(100.0, creditCardParams) GetParameter<string>("CardNumber") "1234..." GetParameter<string>("SecurityCode") "123" 打印支付信息 支付宝支付流程 创建实例("138...") SetStrategy(AlipayStrategy) ExecutePayment(200.0, alipayParams) ProcessPayment(200.0, alipayParams) GetParameter<string>("PhoneNumber") "138..." 打印支付信息 Program PaymentContext CreditCardStrategy CreditCardAdapter AlipayStrategy AlipayAdapter Console

5.4 客户端与策略解耦优化

  • 在传统的策略模式中,客户端需要了解所有策略类的具体实现细节,并负责选择合适的策略。然而,为了实现一个灵活的支付策略模式,我们可以通过解耦客户端代码与具体策略的方式,使新增支付方式时只需注册新的策略,而无需修改客户端代码。具体实现方式如下:

    1. 引入工厂模式:使用工厂模式来创建策略对象,客户端只需知道工厂接口,而无需了解具体的策略实现。
    2. 策略注册与动态选择:通过注册机制,允许策略在运行时动态选择,客户端只需提供策略标识或条件,而不需了解具体的策略实现。
    3. 使用配置文件:通过配置文件或注解来管理策略的选择,客户端可以通过配置而不是硬编码来选择策略。
  • 策略接口

    // 策略接口保持不变
    public interface IPaymentStrategy
    {void ProcessPayment(decimal amount);
    }
    
  • 策略工厂与注册中心

    策略工厂负责管理和注册具体的支付策略,提供策略的获取方式。

    说明:

    • _strategies 是一个静态字典,用于存储策略的键值对。
    • RegisterStrategy 方法用于将策略注册到工厂中,确保每个策略键是唯一的。
    • GetStrategy 方法通过键获取对应的策略实例,如果键不存在则抛出异常。
    // 策略工厂+注册中心
    public class PaymentStrategyFactory
    {private static readonly Dictionary _strategies = new();// 注册策略public static void RegisterStrategy(string key, IPaymentStrategy strategy){if (!_strategies.ContainsKey(key)){_strategies.Add(key, strategy);}}// 获取策略public static IPaymentStrategy GetStrategy(string key){if (_strategies.TryGetValue(key, out var strategy)){return strategy;}throw new KeyNotFoundException($"未找到支付策略:{key}");}
    }
    
  • 配置中心

    配置中心模拟了外部配置文件(如 appsettings.json),用于定义支付策略的映射关系。

    说明:

    • PaymentStrategies 是一个字典,定义了支付类型与具体策略的映射关系。
    • 例如,CreditCard 映射到 CreditCardPaymentPayPal 映射到 PayPalPayment
    • 还定义了一个默认策略(Default),用于处理未明确指定的支付类型。
    // 配置中心(模拟appsettings.json)
    public static class AppConfig
    {public static readonly Dictionary<string, string> PaymentStrategies = new(){{ "CreditCard", "CreditCardPayment" },{ "PayPal", "PayPalPayment" },{ "Default", "CreditCard" }};
    }
    
  • 初始化注册

    在程序启动时,需要将具体的支付策略注册到工厂中。

    说明:

    • 这里注册了两种支付策略:CreditCardPaymentPayPalPayment
    • 这些策略需要实现 IPaymentStrategy 接口,并在程序启动时完成注册。
    // 初始化注册(通常在程序启动时)
    PaymentStrategyFactory.RegisterStrategy("CreditCardPayment", new CreditCardPayment());
    PaymentStrategyFactory.RegisterStrategy("PayPalPayment", new PayPalPayment());
    
  • 客户端代码 Client Code

    客户端代码实现了支付逻辑的调用,通过配置中心和策略工厂获取具体的支付策略。

    说明:

    • 客户端通过传入的 paymentType,从配置中心获取对应的策略键。
    • 如果未找到匹配的策略键,则使用默认策略。
    • 使用策略工厂获取具体的策略实例,并调用其 ProcessPayment 方法完成支付。
    // 优化后的客户端
    class OptimizedClient
    {public void Checkout(string paymentType){// 通过配置映射获取实际策略keyvar strategyKey = AppConfig.PaymentStrategies.TryGetValue(paymentType, out var key) ? key : AppConfig.PaymentStrategies["Default"];var strategy = PaymentStrategyFactory.GetStrategy(strategyKey);strategy.ProcessPayment(100);}
    }
    

    输出

    Processing Credit Card payment for amount: 100
    Processing PayPal payment for amount: 100
  • 类图

    实现
    实现
    查询策略映射
    获取策略实例
    聚合存储策略实例
    OptimizedClient
    +Checkout(string paymentType)
    «static»
    AppConfig
    +PaymentStrategies: Dictionary<string, string>
    «static»
    PaymentStrategyFactory
    -_strategies: Dictionary<string, IPaymentStrategy>
    +RegisterStrategy(string key, IPaymentStrategy strategy)
    +GetStrategy(string key) : IPaymentStrategy
    «interface»
    IPaymentStrategy
    +ProcessPayment(decimal amount)
    CreditCardPayment
    +ProcessPayment(decimal amount)
    PayPalPayment
    +ProcessPayment(decimal amount)
  • 时序图

    Client OptimizedClient AppConfig PaymentStrategyFactory CreditCardPayment Checkout("CreditCard") PaymentStrategies.TryGetValue("CreditCard") "CreditCardPayment" GetStrategy("CreditCardPayment") CreditCardPayment实例 ProcessPayment(100) 执行支付完成 Client OptimizedClient AppConfig PaymentStrategyFactory CreditCardPayment

六、使用建议

⚠️ 注意事项:

  • 客户端需理解策略间的功能差异
  • 避免过度设计简单算法场景
  • 策略接口设计应保持适度抽象
  • 权衡模式引入的架构复杂度
  • 当存在多个相似类仅在行为不同时优先考虑
  • 配合工厂模式使用可以更好地管理策略对象
  • 注意控制策略类的数量膨胀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/72641.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

尚硅谷爬虫note14

一、scrapy scrapy&#xff1a;为爬取网站数据是&#xff0c;提取结构性数据而编写的应用框架 1. 安装 pip install scrapy 或者&#xff0c;国内源安装 pip install scrapy -i https&#xff1a;//pypi.douban.com/simple 2. 报错 报错1&#xff09;building ‘twisted.te…

Notepad++ 8.6.7 安装与配置全攻略(Windows平台)

一、软件定位与核心优势 Notepad 是开源免费的代码/文本编辑器&#xff0c;支持超过80种编程语言的高亮显示&#xff0c;相比系统自带记事本具有以下优势&#xff1a; 轻量高效&#xff1a;启动速度比同类软件快30%插件扩展&#xff1a;支持NppExec、JSON Viewer等200插件跨文…

建筑兔零基础自学python记录39|实战词云可视化项目——章节分布10(上)

这次我们来制作《红楼梦》各章节的分布情况&#xff1a; 源代码&#xff1a; import pandas as pd import numpy as np import matplotlib.pyplot as pltdf_hlm pd.read_csv("hlm.txt", names["hlm_texts"]).dropna()df_hlm df_hlm[~df_hlm.hlm_texts.s…

基于 ChatGPT 创建专属 GPTs

文章目录 基于 ChatGPT 创建专属 GPTs一、效果展示1.1 中文命名专家1.2 行程小助手 二、核心配置2.1 Instructions2.3 Actions 三、Agent 简介3.1 功能框架3.2 工作流程3.3 意图识别 四、数据流程 基于 ChatGPT 创建专属 GPTs ChatGPT 具备定制 GPTs 的能力&#xff0c;能够通…

【数据挖掘】异构图与同构图

在图论&#xff08;Graph Theory&#xff09;中&#xff0c;异构图&#xff08;Heterogeneous Graph&#xff09;和同构图&#xff08;Homogeneous Graph&#xff09;是两种不同的图结构概念&#xff0c;它们的主要区别在于节点和边的类型是否单一。 1. 异构图&#xff08;Hete…

DeepSeek:构筑大数据平台底座的最优解

一、大数据平台底座的重要性 在数字化浪潮席卷全球的当下,数据已成为企业乃至整个社会最具价值的资产之一 。大数据平台底座作为数据处理和业务支撑的核心枢纽,其重要性不言而喻,犹如大厦的基石,关乎整个数据生态系统的稳定与发展。 从数据处理角度来看,随着互联网、物联…

ubuntu20 安装python2

1. 确保启用了 Universe 仓库 在某些情况下&#xff0c;python2-minimal 包可能位于 Universe 仓库中。你可以通过以下命令启用 Universe 仓库并更新软件包列表&#xff1a; bash复制 sudo add-apt-repository universe sudo apt update 然后尝试安装&#xff1a; bash复制…

STM32---FreeRTOS中断管理试验

一、实验 实验目的&#xff1a;学会使用FreeRTOS的中断管理 创建两个定时器&#xff0c;一个优先级为4&#xff0c;另一个优先级为6&#xff1b;注意&#xff1a;系统所管理的优先级范围 &#xff1a;5~15 现象&#xff1a;两个定时器每1s&#xff0c;打印一段字符串&#x…

docker利用docker-compose-gpu.yml启动RAGFLOW,文档解析出错【亲测已解决】

0.问题说明 想要让RAGFLOW利用GPU资源跑起来&#xff0c;可以选择docker-compose-gpu.yml启动。&#xff08;但是官网启动案例是86平台的不是NVIDIA GPU的&#xff0c;docker-compose-gpu.yml又是第三方维护&#xff0c;所以稍有问题&#xff09; 1.问题 docker利用docker-c…

【AI深度学习网络】卷积神经网络(CNN)入门指南:从生物启发的原理到现代架构演进

深度神经网络系列文章 【AI深度学习网络】卷积神经网络&#xff08;CNN&#xff09;入门指南&#xff1a;从生物启发的原理到现代架构演进【AI实践】基于TensorFlow/Keras的CNN&#xff08;卷积神经网络&#xff09;简单实现&#xff1a;手写数字识别的工程实践 引言 在当今…

【ThreeJS Basics 06】Camera

文章目录 Camera 相机PerspectiveCamera 透视相机正交相机用鼠标控制相机大幅度转动&#xff08;可以看到后面&#xff09; 控制组件FlyControls 飞行组件控制FirstPersonControls 第一人称控制PointerLockControls 指针锁定控制OrbitControls 轨道控制TrackballControls 轨迹球…

Linux | Ubuntu 与 Windows 双系统安装 / 高频故障 / UEFI 安全引导禁用

注&#xff1a;本文为 “buntu 与 Windows 双系统及高频故障解决” 相关文章合辑。 英文引文&#xff0c;机翻未校。 How to install Ubuntu 20.04 and dual boot alongside Windows 10 如何将 Ubuntu 20.04 和双启动与 Windows 10 一起安装 Dave’s RoboShack Published in…

【二.提示词工程与实战应用篇】【3.Prompt调优:让AI更懂你的需求】

最近老张在朋友圈秀出用AI生成的国风水墨画,隔壁王姐用AI写了份惊艳全场的年终总结,就连楼下小卖部老板都在用AI生成营销文案。你看着自己跟AI对话时满屏的"我不太明白您的意思",是不是怀疑自己买了台假电脑?别慌,这可能是你的打开方式不对。今天咱们就聊聊这个…

蓝桥杯C组真题——巧克力

题目如下 思路 代码及解析如下 谢谢观看

使用 Deepseek + kimi 快速生成PPT

前言 最近看到好多文章和视频都在说&#xff0c;使用 Deepseek 和 kimi 能快速生成精美的 ppt&#xff0c;毕竟那都是别人说的&#xff0c;只有自己尝试一次才知道结果。 具体操作 第一步&#xff1a;访问 deepseek 我们访问 deepseek &#xff0c;把我们想要输入的内容告诉…

初始提示词(Prompting)

理解LLM架构 在自然语言处理领域&#xff0c;LLM&#xff08;Large Memory Language Model&#xff0c;大型记忆语言模型&#xff09;架构代表了最前沿的技术。它结合了存储和检索外部知识的能力以及大规模语言模型的强大实力。 LLM架构由外部记忆模块、注意力机制和语…

【Python爬虫】利用代理IP爬取跨境电商AI选品分析

引言 随着DeepSeek的流行&#xff0c;越来越多的用户开始尝试将AI工具融入到日常工作当中&#xff0c;借助AI的强大功能提高工作效率。最近又掀起了一波企业出海的小高潮&#xff0c;那么如果是做跨境电商业务&#xff0c;怎么将AI融入工作流中呢&#xff1f;在做跨境电商的时候…

C语言——链表

大神文献&#xff1a;https://blog.csdn.net/weixin_73588765/article/details/128356985 目录 一、链表概念 1. 什么是链表&#xff1f; 1.1 链表的构成 2. 链表和数组的区别 数组的特点&#xff1a; 链表的特点&#xff1a; 二者对比&#xff1a; 二…

Spring框架自带的定时任务:Spring Task详解

文章目录 一、基本使用1、配置&#xff1a;EnableScheduling2、触发器&#xff1a;Scheduled 二、拓展1、修改默认的线程池2、springboot配置 三、源码分析参考资料 一、基本使用 1、配置&#xff1a;EnableScheduling import org.springframework.context.annotation.Config…

数据库事务、乐观锁及悲观锁

参考&#xff1a;node支付宝支付及同步、异步通知、主动查询支付宝订单状态 以下容结合上述链接查看 1. 什么是数据库事务&#xff1f; 1.1. 连续执行数据库操作 在支付成功后&#xff0c;我们在自定义的paidSuccess里&#xff0c;依次更新了订单状态和用户信息。也就说这里…