zoukankan      html  css  js  c++  java
  • C++设计模式——策略模式

    策略模式

    在GOF的《设计模式:可复用面向对象软件的基础》一书中对策略模式是这样说的:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。

    策略模式为了适应不同的需求,只把变化点封装了,这个变化点就是实现不同需求的算法,但是,用户需要知道各种算法的具体情况。就像上面的加班工资,不同的加班情况,有不同的算法。我们不能在程序中将计算工资的算法进行硬编码,而是能自由的变化的。这就是策略模式。

    UML类图

    果冻想 | 一个原创文章分享网站

    Strategy:定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法;
    ConcreteStrategy:实现Strategy接口的具体算法;
    Context:使用一个ConcreteStrategy对象来配置;维护一个对Stategy对象的引用,同时,可以定义一个接口来让Stategy访问它的数据。

    使用场合

    当存在以下情况时使用Strategy模式:

    1. 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法;
    2. 需要使用一个算法的不同变体;
    3. 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构;
    4. 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以替代这些条件语句。(是不是和状态模式有点一样哦?)

    代码实现

    首先实现最单纯的策略模式,代码如下:

    #include <iostream>
    using namespace std;
    
    // The abstract strategy
    class Strategy
    {
    public:
         virtual void AlgorithmInterface() = 0;
    };
    
    class ConcreteStrategyA : public Strategy
    {
    public:
         void AlgorithmInterface()
         {
              cout<<"I am from ConcreteStrategyA."<<endl;
         }
    };
    
    class ConcreteStrategyB : public Strategy
    {
    public:
         void AlgorithmInterface()
         {
              cout<<"I am from ConcreteStrategyB."<<endl;
         }
    };
    
    class ConcreteStrategyC : public Strategy
    {
    public:
         void AlgorithmInterface()
         {
              cout<<"I am from ConcreteStrategyC."<<endl;
         }
    };
    
    class Context
    {
    public:
         Context(Strategy *pStrategyArg) : pStrategy(pStrategyArg)
         {
         }
         void ContextInterface()
         {
              pStrategy->AlgorithmInterface();
         }
    private:
         Strategy *pStrategy;
    };
    
    int main()
    {
         // Create the Strategy
         Strategy *pStrategyA = new ConcreteStrategyA;
         Strategy *pStrategyB = new ConcreteStrategyB;
         Strategy *pStrategyC = new ConcreteStrategyC;
         Context *pContextA = new Context(pStrategyA);
         Context *pContextB = new Context(pStrategyB);
         Context *pContextC = new Context(pStrategyC);
         pContextA->ContextInterface();
         pContextB->ContextInterface();
         pContextC->ContextInterface();
    
         if (pStrategyA) delete pStrategyA;
         if (pStrategyB) delete pStrategyB;
         if (pStrategyC) delete pStrategyC;
    
         if (pContextA) delete pContextA;
         if (pContextB) delete pContextB;
         if (pContextC) delete pContextC;
    }

    在实际操作的过程中,我们会发现,在main函数中,也就是在客户端使用策略模式时,会创建非常多的Strategy,而这样就莫名的增加了客户端的压力,让客户端的复杂度陡然增加了。那么,我们就可以借鉴简单工厂模式,使策略模式和简单工厂模式相结合,从而减轻客户端的压力,代码实现如下:

    /*!
     * file StrategePatternDemo.cpp
     * date 2016/08/14 19:56
     *
     * author ranjiewen
     * contact: ranjiewen@outlook.com
     *
     * rief 
     *
     * TODO: long description
     *
     * 
    ote
    */
    
    #include <iostream>
    using namespace std;
    
    typedef enum StrategyType
    {
        StrategyA,
        StrategyB,
        StrategyC
    };
    
    class Strategy
    {
    public:
        virtual void AlgorithmInterface() = 0;
        virtual ~Strategy() = 0; //基类申请为虚析构函数
    
    };
    Strategy::~Strategy(){}
    
    class ConcreteStrategyA :public Strategy
    {
    public:
        void AlgorithmInterface()
        {
            cout << "I'm from ConcreteStrategyA." << endl;
        }
        ~ConcreteStrategyA(){}
    
    };
    
    class ConcreteStrategyB :public Strategy
    {
    public:
        void AlgorithmInterface()
        {
            cout << "I'm from ConcreteStrategyB." << endl;
        }
        ~ConcreteStrategyB(){}
    };
    
    class ConcreteStrategyC :public Strategy
    {
    public:
        void AlgorithmInterface()
        {
            cout << "I'm from ConcreteStrategyC." << endl;
        }
        ~ConcreteStrategyC(){}
    };
    
    class Context
    {
    private:
        Strategy* pStrategy;
    public:
        Context(StrategyType strategyType)
        {
            switch (strategyType)
            {
            case StrategyA:
                pStrategy = new ConcreteStrategyA;
                break;
            case StrategyB:
                pStrategy = new ConcreteStrategyB;
                break;
            case StrategyC:
                pStrategy = new ConcreteStrategyC;
                break;
            default:
                break;
            }
        }
        ~Context()
        {
            if (pStrategy)
            {
                delete pStrategy;
            }
        }
    
        void ContextInterface()
        {
            if (pStrategy)
            {
                pStrategy->AlgorithmInterface();
            }
        }
    };
    
    int main()
    {
        Context* pContext = new Context(StrategyA);
        pContext->ContextInterface();
        return 0;
    }

    在上面这个代码中,其实,我们可能看到的更多的是简单工厂模式的应用,我们将策略模式将简单工厂模式结合在了一起,让客户端使用起来更轻松。

    总结

    策略模式和状态模式,是大同小异的;状态模式讲究的是状态的变化,和不同状态下,执行的不同行为;而策略模式侧重于同一个动作,实现该行为的算法的不同,不同的策略封装了不同的算法。策略模式适用于实现某一功能,而实现该功能的算法是经常改变的情况。在实际工作中,遇到了实际的场景,可能会有更深的体会。比如,我们做某一个系统,该系统可以适用于各种数据库,我们都知道,连接某一种数据库的方式是不一样的,也可以说,连接数据库的“算法”都是不一样的。这样,我们就可以使用策略模式来实现不同的连接数据库的策略,从而实现数据库的动态变换。

  • 相关阅读:
    December 23rd 2016 Week 52nd Friday
    December 22nd 2016 Week 52nd Thursday
    December 21st 2016 Week 52nd Wednesday
    December 20th 2016 Week 52nd Tuesday
    December 19th 2016 Week 52nd Sunday
    December 18th 2016 Week 52nd Sunday
    uva294(唯一分解定理)
    uva11624Fire!(bfs)
    fzu2150Fire Game(双起点bfs)
    poj3276Face The Right Way
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/5770934.html
Copyright © 2011-2022 走看看