[设计模式] —— Strategy 策略模式

本文详细介绍了策略模式的概念、动机和应用场景,通过示例代码展示了如何利用策略模式替代条件判断语句,实现算法的灵活切换,提高代码的扩展性和维护性。

Strategy 策略模式

组件协作模式通过晚绑定,来实现框架与应用程序之间的松耦合。是框架和引用程序协作常用的。

动机

某些对象使用的算法可能多种多样,经常改变,将这些算法都编码到对象中,使对象变得异常复杂,而且有时支持不适用的算法也是一种性能负担。想要在运行时根据需要透明地更改对象的算法,就要将算法与对象本身解耦,从而避免上述问题。

定义

定义一系列算法,把它们一个个封装起来,并且它们可以相互替换(变化),该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。

示例代码
enum TaxBase {
    CN_Tax,
    USA_Tax
};

class SalesOrder {
private:
 TaxBase tax;
public:
 double CalculateTax() {
     // ...
     if (tax == CN_Tax) {
         // CN_...
     } else if (tax == USA_Tax) {
         // USA...
     }
 }
};

现有上面的示例代码,有一个 SalesOrder 类来计算税收,税现在有 CN_Tax 和 USA_Tax 类两种,用枚举表示,这里实现就根据 tax 的类型类做条件表达式的判读。 这样的代码还是在日常开发中蛮常见的,但是这样的代码有一个问题,就是当有需求变化时,我们即需要修改枚举类型,还要修改类的源代码。例如现在需要增加一个税收计算种类 FR_Tax,就需要将代码改成下面的形式:

enum TaxBase {
    CN_Tax,
    USA_Tax,
    FR_Tax // 新增代码
};

class SalesOrder {
private:
 TaxBase tax;

public:
 double CalculateTax() {
     // ...
     if (tax == CN_Tax) {
         // CN_...
     } else if (tax == USA_Tax) {
         // USA...
     } else if (tax == FR_Tax) { // 新增代码
        // FR...
     }
 }
};

其实上面这种方式就违背了开闭原则,即对修改封闭,对扩展开放。这种情况下,使用策略模式就是由上面的定义,将类型一个个封装起来:

class TaxStrategy {
public:
 virtual double Caculate(const Context& context) = 0;
 virtual ~TaxStrategy(){}
};

class CNTax : public TaxStrategy {
public:
 virtual double Caculate(const Context& context) {
     // ...
 }
};

class USATax : public TaxStrategy {
public:
   virtual double Caculate(const Context& context) {
     // ...
 }
}

class SalesOrder {
private:
 TaxStrategy* strategy; // 使用指针实现多态

public:

  SalesOrder(strategyFactory* strategyFactory) { // 工厂方法来生成对应子类
      this->strategy = strategyFactory->NewStrategy();
  }

  ~SalesOrder() {
      delete this->strategy;
  }

  double CalculateTax() {
      // ...
      Context context;
      double val = strategy->Caculate(context); // 多态调用
  }
};

这个时候我们如果再想扩展 FR_Tax 类型则可以在上述代码的基础上,增加一个 TaxStrategy 的 FRTax 的子类(以及相应的工厂方法的子类)即可,无须再修改 SalesOrder 类的代码了。这里使用了工厂方法来生成子类对象,这部分不是本模式的重点,后面会详细介绍工厂方法。

class FRTax : public TaxStrategy {
public:
   virtual double Caculate(const Context& context) {
     // ...
 }
}

上述的方式就是 Strategy 策略模式的内容了。

结构图
总结
  • Strategy 策略模式及其子类为组件提供了一系列可重用的算法,从而是的类型在运行时方便地根据需要在各算法间进行切换。
  • 提供了条件判断语句之外的另一种选择。上面的例子可以看出,消除条件判断表达式就是在解耦合,含多个条件判断语句的代码通常都需要 stategy 模式。
  • 如果 Stategy 对象没有实例变量,上下文可以共享同一个对象,能节省对象开销。

其他设计模式汇总:
[设计模式] —— 设计模式的介绍及分类

### Java 中策略模式的设计与实现 #### 策略模式简介 策略模式Strategy Pattern),又称政策模式,是一种行为设计模式。此模式允许定义一系列算法,并将每一个算法封装起来,使它们可以互换使用[^2]。 #### 接口声明公共方法 为了实现策略模式,首先需要创建一个接口来声明所有支持版本的公共操作。例如,在处理不同类型的支付方式时,可以定义 `PaymentStrategy` 接口: ```java public interface PaymentStrategy { void pay(int amount); } ``` #### 创建具体策略类 接着,通过不同的类去实现这个接口中的方法,这些类代表具体的策略。比如信用卡支付和PayPal支付两种不同的付款方式: 对于信用卡支付: ```java public class CreditCardPayment implements PaymentStrategy { private String cardNumber; public CreditCardPayment(String cardNum){ this.cardNumber = cardNum; } @Override public void pay(int amount) { System.out.println(amount + " paid with credit/debit card"); } } ``` 而对于PayPal支付,则有另一个实现: ```java public class PayPalPayment implements PaymentStrategy { private String emailId; public PayPalPayment(String email){ this.emailId=email; } @Override public void pay(int amount) { System.out.println(amount + " paid using PayPal."); } } ``` 上述两个类实现了相同的接口并提供了各自特有的逻辑,这就是所谓的“具体策略”。 #### 上下文环境设置 最后一步是在上下文中利用这些策略对象。这里我们构建了一个购物车的例子,它接受任何实现了 `PaymentStrategy` 的实例作为参数来进行结账过程: ```java class ShoppingCart { private PaymentStrategy paymentMethod; // 构造函数注入依赖关系 public ShoppingCart(PaymentStrategy pm) { this.paymentMethod=pm; } public void checkout() { int totalAmount = calculateTotal(); paymentMethod.pay(totalAmount); } private int calculateTotal(){ // 计算总价... return 100; } } ``` 这样就完成了整个流程:客户端可以选择合适的支付手段传入到购物车内完成交易动作[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值