c++ 职责链+策略模式,实现链式过程处理

想象一下一件商品的加工,需要经过多道工艺流程处理。这一道道工艺流程就像是一个职责链,从头到尾传递。就好像网络传输时,消息发送到对端主机,经过协议栈,在这个过程中,它在不同的协议栈层级中被一层层抽丝剥茧,剥掉ip头,脱下tcp头,扯掉http头。又像清丽的舞娘不再犹抱琵琶,缓缓揭开自己面纱,犹如李清照《一剪梅》中的“轻解罗裳,独上兰舟”,最后对端的层得到了自己想要的东西。

(注:纯知识总结分享,示例和业务内容虚构)

前言

假设一个常见的应用场景。在公司申请工作流程,你的申请就会在一条流中传递,这条流程从开始提交申请,到你的经理,最终是最后部门的任务接收者。这些个对象每个对象都能审批和转交下一步。这就像是一条职责链。同时随着需求的变动,又可能需要变换或增加新的处理者,类似这种采用策略模式+职责链就很合适了。

职责链(Chain of Responsibility)模式也许被看做一个使用策略对象的“递归的动态一般化".此时发起一个调用,在一个链序列中的每个策略都试图满足这个调用。这个过程直到有一个策略成功满足该调用或者到达序列的末尾才结束。通过遍历策略链,调用函数的不同实现,直至达到某个终止条件到达最后的处理。

策略模式

策略模式(Strategy):它定义了算法家族,分别放封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。策略是一个接口,该接口定义若干个算法标识,即定义了若干个抽象方法。

在策略模式中,我们定义一系列算法,并将它们封装在独立的类中,这些类实现了一个共同的接口。然后,我们可以在运行时选择一个具体的算法类来执行特定的行为。

对于Strategy模式来说,主要有如下优点:

1、  提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。

2、  避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。

3、  遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

以下是一个使用策略模式的示例:

#include 

// 策略接口
class Strategy {
public:
    virtual void execute() = 0;
};

// 具体策略类1
class ConcreteStrategy1 : public Strategy {
public:
    void execute() override {
        std::cout << "Executing strategy 1" << std::endl;
    }
};

// 具体策略类2
class ConcreteStrategy2 : public Strategy {
public:
    void execute() override {
        std::cout << "Executing strategy 2" << std::endl;
    }
};

// 上下文类
class Context {
private:
    Strategy* strategy;

public:
    Context(Strategy* strategy) : strategy(strategy) {}

    void setStrategy(Strategy* strategy) {
        this->strategy = strategy;
    }

    void executeStrategy() {
        strategy->execute();
    }
};

int main() {
    // 创建具体策略对象
    ConcreteStrategy1 strategy1;
    ConcreteStrategy2 strategy2;

    // 创建上下文对象并设置初始策略
    Context context(&strategy1);

    // 执行初始策略
    context.executeStrategy();

    // 切换策略并执行
    context.setStrategy(&strategy2);
    context.executeStrategy();

    return 0;
}

在上面的示例中,我们定义了一个`Strategy`接口,它有一个`execute()`方法。然后,我们创建了两个具体的策略类`ConcreteStrategy1`和`ConcreteStrategy2`,它们分别实现了`execute()`方法。

接下来,我们定义了一个上下文类`Context`,它有一个指向`Strategy`接口的指针成员变量。在构造函数中,我们传入一个初始的策略对象,并在`executeStrategy()`方法中调用该策略对象的`execute()`方法。

在`main()`函数中,我们创建了具体的策略对象,并将其传递给上下文对象。然后,我们调用上下文对象的`executeStrategy()`方法来执行策略。

通过使用策略模式,我们可以在运行时动态地选择不同的策略,并且可以轻松地添加新的策略类。这使得我们的代码更加灵活和可扩展。

职责链模式

在GOF的《设计模式:可复用面向对象软件的基础》一书中对职责链模式是这样说的:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,直到有一个对象处理它为止。在职责链模式中,每个处理者都包含一个对下一个处理者的引用,当一个请求到达时,首先由第一个处理者处理,如果该处理者能够处理该请求,则处理结束,否则将请求传递给下一个处理者,直到请求被处理或者到达链的末尾。

优缺点

1、降低耦合度;职责链模式使得一个对象不用知道是哪一个对象处理它的请求。对象仅需要知道该请求会被正确的处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需要知道链的结构;

2、增强了给对象指派职责的灵活性;当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责;


3、不保证被接受,既然一个请求没有明确的接收者,那么就不能保证它一定会被处理;该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。

以下是一个简单的C++职责链模式的示例:

#include 
using namespace std;

// 抽象处理者
class Handler {
public:
    virtual void setNext(Handler* next) = 0;
    virtual void handleRequest(int request) = 0;
};

// 具体处理者A
class ConcreteHandlerA : public Handler {
private:
    Handler* next;
public:
    void setNext(Handler* next) {
        this->next = next;
    }
    void handleRequest(int request) {
        if (request >= 0 && request < 10) {
            cout << "ConcreteHandlerA处理请求:" << request << endl;
        }
        else if (next != nullptr) {
            next->handleRequest(request);
        }
    }
};

// 具体处理者B
class ConcreteHandlerB : public Handler {
private:
    Handler* next;
public:
    void setNext(Handler* next) {
        this->next = next;
    }
    void handleRequest(int request) {
        if (request >= 10 && request < 20) {
            cout << "ConcreteHandlerB处理请求:" << request << endl;
        }
        else if (next != nullptr) {
            next->handleRequest(request);
        }
    }
};

// 具体处理者C
class ConcreteHandlerC : public Handler {
private:
    Handler* next;
public:
    void setNext(Handler* next) {
        this->next = next;
    }
    void handleRequest(int request) {
        if (request >= 20 && request < 30) {
            cout << "ConcreteHandlerC处理请求:" << request << endl;
        }
        else if (next != nullptr) {
            next->handleRequest(request);
        }
    }
};

int main() {
    // 创建处理者对象
    Handler* handlerA = new ConcreteHandlerA();
    Handler* handlerB = new ConcreteHandlerB();
    Handler* handlerC = new ConcreteHandlerC();

    // 设置处理者的下一个处理者
    handlerA->setNext(handlerB);
    handlerB->setNext(handlerC);

    // 发起请求
    handlerA->handleRequest(5);
    handlerA->handleRequest(15);
    handlerA->handleRequest(25);

    // 释放内存
    delete handlerA;
    delete handlerB;
    delete handlerC;

    return 0;
}

具体实现举例

以控制机器导轨上的滑块儿(slider)为例,若想让滑块儿按需求完成准确的动作,需经过参数校正、速度限制、算法补偿等一系列的加工处理,最后下发给控制器响应。如果不经过好的设计,每次增加新的功能都无法很好的维护和拓展。而采用职责链和策略模式是一种好的处理方式。比如滑块儿的运动可以像工厂流水线一样经过一系列的加工处理(职责链模式)。

先定义一下该滑块儿所具备的基础动作功能策略接口:

class SliderIFA
{
public:
  SliderIFA() = default;
  virtual ~SliderIFA() = default;

public:
  // 按指定位置移动
  virtual void tMove() = 0;
  // 按步进方式移动
  virtual void iMove() = 0;
  virtual void enable() = 0;
  // ......
}

接下来实现不同的技能(策略),如基本技能,慢动作技能,快动作技能,花样动作技能,采用策略模式和责任链模式的组合,分别给予实现,实现同一策略动作的加工处理。

定义一个父类BaseIFA继承自策略接口SliderIFA ,先实现一种策略作为公共类用,内部实现职责链模式。而且定义这样一个父类还有个好处是,如果策略接口有很多,继承自该父类的策略类,不用实现所有的策略接口,只需重载实现需要的接口即可。其他未重载的接口则自动执行父类中的方法。 

class BaseIFA : public SliderIFA
{
public:
  BaseIFA() {}

public:
  void setNextStrategy(std::shared_ptr coreIfa) { nextStrategy_ = std::move(coreIfa); }

public:
  void tMove() override;
  void iMove() override;
  void enable() override;

protected:
 std::shared_ptr nextStrategy_;

}
void BaseIFA::enable()
{
  if (nextStrategy_)
  {
    return nextStrategy_->enable();
  }
}

void BaseIFA::tMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->tMove();
  }
}

void BaseIFA::iMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->iMove();
  }
}

举例,责任者一的实现:

class Hander1:public BaseIFA
{
public:
  Hander1() {}

public:
  void tMove() override;
  void iMove() override;
  void enable() override;
}

void Hander1::enable()
{
  if (nextStrategy_)
  {
    return nextStrategy_->enable();
  }
}

void Hander1::tMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->tMove();
  }
}

void Hander1::iMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->iMove();
  }
}

责任者二的实现:

class Hander2:public BaseIFA
{
public:
  Hander2() {}

public:
  void tMove() override;
  void iMove() override;
  void enable() override;
}

void Hander2::enable()
{
  if (nextStrategy_)
  {
    return nextStrategy_->enable();
  }
}

void Hander2::tMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->tMove();
  }
}

void Hander2::iMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->iMove();
  }
}

最终使用如下所示,每个hander都是一种策略接口的实现,然后按照责任链模式链式处理。比如可以按照3->1->2的加工顺序,或者按照1->2->3的加工顺序处理。或者只经过1和2这两道加工工序,实现效果:

int main()
{
    std::shared_ptr core_ = nullptr;

    auto hander1_ = std::make_shared();
    auto hander2_ = std::make_shared();
    auto hander3_ = std::make_shared();

    // 举例,实现1->2->3的排列组合链式处理

    hander1_->setNextStrategy(hander2_ );
    hander2_->setNextStrategy(hander3_ );

    core_ = std::move(hander1_); //入口

    // 执行
    core_->tMove();

    return 0;
} 

最终的一个tMove接口会先经过hander1->hander2->hander3的链式加工处理,达到的想要的效果。且可以任意的排列组合,hander1->hander3也是可以的。

优化改进,为了保持BaseIFA这个基类的简洁直观,可以单独整一个默认的策略类,作为最终职责链最后一级的处理,接口默认实现都写在这里。这样只需定一个DefaultHander继承自策略接口SliderIFA,在BaseIFA基类中持有它的引用即可。如:

class BaseIFA : public SliderIFA
{
public:
  explicit BaseIFA(std::shared_ptr coreImp) : coreImp_(std::move(coreImp)) {}

public:
  void setNextStrategy(std::shared_ptr coreIfa) { nextStrategy_ = std::move(coreIfa); }

public:
  void tMove() override;
  void iMove() override;
  void enable() override;

protected:
 std::shared_ptr nextStrategy_;

 std::shared_ptr coreImp_;
}

void BaseIFA::enable()
{
  if (nextStrategy_)
  {
    return nextStrategy_->enable();
  }
  if (core_)
  {
    return core_->enable();
  }
}
 
void BaseIFA::tMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->tMove();
  }
  if (core_)
  {
    return core_->tMove();
  }
}
 
void BaseIFA::iMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->iMove();
  }
  if (core_)
  {
    return core_->iMove();
  }
}

class DefalutHander: public SliderIFA
{
public:
  BaseIFA() {}
 
public:
  void tMove() override;
  void iMove() override;
  void enable() override;

}

class Hander1:public BaseIFA
{
public:
  explicit Hander1(std::shared_ptr core_) {}

public:
  void tMove() override;
  void iMove() override;
  void enable() override;
}

void Hander1::enable()
{
  if (nextStrategy_)
  {
    return nextStrategy_->enable();
  }
  if (core_)
  {
    return core_->enable();
  }
}

void Hander1::tMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->tMove();
  }
  if (core_)
  {
    return core_->tMove();
  }
}

void Hander1::iMove()
{
  if (nextStrategy_)
  {
    return nextStrategy_->iMove();
  }
  if (core_)
  {
    return core_->iMove();
  }
}

int main()
{
    std::shared_ptr core_ = nullptr;

    //默认策略类
    auto default_ = std::make_shared();
    //策略实现一
    auto hander1_ = std::make_shared(default_ );
    //策略实现二
    auto hander2_ = std::make_shared(default_ );
    //策略实现三
    auto hander3_ = std::make_shared(default_ );

    // 举例,实现1->2->3的排列组合链式处理

    hander1_->setNextStrategy(hander2_ );
    hander2_->setNextStrategy(hander3_ );

    core_ = std::move(hander1_); //入口

    // 执行
    core_->tMove();

    return 0;
} 

其他资源

c++ 策略模式_每木昔月的博客-CSDN博客_c++策略模式

C++常用设计模式

模式和原则 [原] - Justin - 博客园

设计模式随笔系列:鸭子-策略模式(Strategy)[原] - Justin - 博客园

c++手撕代码(六)设计模式:观察者,策略,责任链, 装饰器 - 知乎

Java设计模式——策略模式_塔塔开!!!的博客-CSDN博客_策略模式

C++设计模式——职责链模式_静思心远的博客-CSDN博客_c++设计模式职责链

C++设计模式-策略模式(Strategy)基本轮廓_IT1995的博客-CSDN博客_c++ 策略模式

设计模式(C++实现)(二十一)——职责链模式_huashuolin001的博客-CSDN博客

c++设计模式(七) 职责链模式:尝试采用一系列策略模式 - Just enjoy programming - C++博客

你可能感兴趣的:(C++,策略模式,c++,开发语言)