设计模式(2):策略模式

一、什么是策略模式?

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式可以使算法的变化独立于使用它的客户。

策略模式根据功能大致分为三个类:

  • 抽象策略类(Strategy)
  • 具体策略类(ConcreteStrategy)
  • 环境类(Context)

二、不使用策略模式的例子

理论可能有一些抽象,直接来看具体代码的例子。

如果我有一个context类,这个类想同时使用2种不同的策略,那我该怎么办?

最简单的方法是下面这样:

首先我新建2个不同的策略类AB:

class ConcreteStrategyA { // 策略A
public:
  void execute() override {
    // 具体算法A 
  }
};
class ConcreteStrategyB { // 策略B
public:
  void execute() override { 
    // 具体算法B
  }  
};
// ...还有策略CDEF等等

context类中组合策略类AB:

class Context {
private:
  ConcreteStrategyA* strategyA_;
  ConcreteStrategyB* strategyB_;
public:
  Context(ConcreteStrategyA* strategyA, ConcreteStrategyB* strategyB) {
    strategyA_ = strategyA;
    strategyB_ = strategyB;
  } 

  void businessMethodA() {
    // 调用策略算法A
    strategyA_->execute();
  }
  void businessMethodB() {
    // 调用策略算法B
    strategyB_->execute();
  }
};

如果这时候我想再增加一些其它策略,那我需要单独写一个策略类C,然后更改context类中,再加一个策略C,再写一个策略C调用的算法void businessMethodC()。可以看出这种方法耦合程度高,不太好。

此外如果我们有strategyA,strategyB,strategyC等100个策略呢,总不能在context中为每一个策略都单独写一个businessMethod(){}函数吧,这时候策略模式就登场啦!!!

三、使用策略模式的例子

我们可以把上面的所有策略都继承同一个抽象父类,context中只组合抽象父类,借用父类指针指向不同的子类对象来调用不同的策略,下面来看实现:

1.抽象策略类(Strategy),是具体策略类的父类

class Strategy {
public:
  virtual void execute() = 0; 
};

2.具体策略类(ConcreteStrategy),封装了策略具体要怎么实现

class ConcreteStrategyA : public Strategy { // 策略A
public:
  void execute() override {
    // 具体算法A 
  }
};
class ConcreteStrategyB : public Strategy { // 策略B
public:
  void execute() override { 
    // 具体算法B
  }  
};

3.环境类(Context),维护一个策略对象,提供执行业务的方法

class Context {
private:
  Strategy* strategy_; // 不用继承用组合,直接组合最顶层的抽象策略类    
public:
  // 根据父类指针指向的不同子类对象,可以调用不同的策略方法
  Context(Strategy* strategy) : strategy_(strategy) {} 
  
  // 切换策略的函数,同一个对象可以使用不同策略
  void setStrategy(Strategy* strategy) {
    this->strategy_ = strategy;
  }

  void businessMethod() {
    // 调用策略算法
    strategy_->execute();
  }
};

4.客户端调用

Strategy* Strategy = new ConcreteStrategyA(); // 新建抽象父类策略指针,指向子类策略A
Context* ctx = new Context(Strategy);  // 新建环境类,调用策略算法
ctx->businessMethod();

// ctx切换策略为B
ctx->setStrategy(new ConcreteStrategyB()); 
ctx->businessMethod();

策略模式说白了,就是一个对象context想使用不同的策略,但是又不想单独建立一大堆策略类ABCD…,这时候就可以单独抽象一个父类来供context调用。

虽然看起来策略模式比第一种实现代码量大一些,但是如果我们想要新加一些策略CDEF,我们并不需要更改context类,只需要单独写一个策略C的类,然后继承抽象策略类,在context中同样可以调用新加的策略。

四、总结

策略模式优点

  • 策略算法可以自由切换:策略模式可以方便地切换不同的算法或策略,而不需要修改 Context 类的代码。
  • 算法和使用算法的客户解耦:策略类封装算法,Context 和策略类解耦,客户只需要决定用哪个策略即可。
  • 遵循开闭原则:可以在不修改原代码的情况下引入新算法,扩展系统功能。

策略模式缺点

  • 会增加许多策略类:每新增一个算法就需要增加一个新的策略类。
  • 增加了系统复杂度:需要了解所有策略类的不同之处,给客户带来额外的复杂性。
  • 客户必须理解策略之间的差异:否则无法选择合适的策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值