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;
    }

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

    总结

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

  • 相关阅读:
    在【Xamarin+Prism开发详解三:Visual studio 2017 RC初体验】中分享了Visual studio 2017RC的大致情况,同时也发现大家对新的Visual Studio很是感兴趣。于是发时间深入研究了一下Visual Studio 2017RC 是不是和微软Connect()://2016上说得一样神。
    .NET(C#):await返回Task的async方法
    【笔记】关于汉字注音 汉字转拼音,首拼
    MvcPager 概述 MvcPager 分页示例 — 标准Ajax分页 对SEO进行优化的ajax分页 (支持asp.net mvc)
    在Asp.net MVC使用jqGrid--代码少点再少点
    jQuery Grid With ASP.Net MVC
    MVC权限控制
    MVC数据库数据分页显示
    NPOI对Excel的操作(Sheet转DataTable、List<T>)
    基于FormsAuthentication的用户、角色身份认证
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/5770934.html
Copyright © 2011-2022 走看看