【设计模式】之策略模式

场景引入

假如你在A城市,要去B城市旅游,交通方式有以下几种选择:

10多年的武隆网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。成都全网营销的优势是能够根据用户设备显示端的尺寸不同,自动调整武隆建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。成都创新互联公司从事“武隆网站设计”,“武隆网站推广”以来,每个客户项目都认真落实执行。

  1. 驾车
  2. 火车
  3. 飞机

不难写出这样的代码:

void transport(string method)
{
    if (method == "drive")
    {
        // 处理驾车相关业务逻辑
    }
    else if (method == "train")
    {
        // 处理乘坐火车相关业务逻辑
    }
    else
    {
        // 处理乘坐飞机相关业务逻辑
    }
}

想一想,有什么问题?

屏幕前的你应该已经想到了,如果增加一种交通方式的话,是不是得增加if-else分支?这样就需要大量的修改,不符合开闭原则,难以维护。

那怎么样能做到在不对源代码直接修改的前提下增加交通方式呢?答案是:把不同交通方式的业务逻辑抽离出来单独做成接口。

首先我们要定义一个基类Transportation,作为这几个交通方式的父类。这个Transportation有个纯虚函数run,从Transportation派生出DriveTrainPlane等子类(叫做策略类),重写run函数。这时的类体系如下:

这样将来如果需要扩展的话,只需要在从Transportation类派生出新的子类了。

代码如下:

class Transportation
{
public:
    virtual void run() = 0;
}

class Drive : public Transportation
{
public:
    void run() override
    {
        // 处理驾车相关业务逻辑
    }
}

class Train : public Transportation
{
public:
    void run() override
    {
        // 处理乘坐火车相关业务逻辑
    }
}

class Plane : public Transportation
{
public:
    void run() override
    {
        // 处理乘坐飞机相关业务逻辑
    }
}

此时多态就体现出来了,使用不同的类,调用run函数,就会做出不同的行为。

那怎么样来使用这些策略类呢?我们再新增一个类Context,可以根据传入的参数做相应的处理:

class Context
{
    Transportation &strategy;
public:
    explicit Context(Transportation &strategy) : strategy(strategy) { }

    void run()
    {
        strategy.run();
    }
}

定义

策略模式(Strategy Pattern):一个类的行为或其算法可以在运行时更改的设计模式。(如例子中不同的交通方式)

主要使用场景

有多种算法,希望避免因为多个if-else分支而带来的难以维护和扩展的问题。

组成

抽象策略类:定义了不同策略的接口(如例子中的Transportation

具体策略类:具体实现抽象策略类的接口(如例子中的DriveTrainPlane

环境:根据需要进行决策(如例子中的Context

优缺点

优点

  1. 可维护性、可扩展性高。
  2. 对客户隐藏了具体的实现细节

缺点

  1. 客户端必须要知道所有的策略类,并自行选择要用哪一个策略类。

本文题目:【设计模式】之策略模式
标题路径:http://myzitong.com/article/dscgiie.html