zoukankan      html  css  js  c++  java
  • 别只知道策略模式+简单工厂,试试更香的策略模式+抽象工厂!

    我的相关博文 

    三种工厂模式详解

    策略模式

    在GOF的《设计模式:可复用面向对象软件的基础》一书中对策略模式是这样说的:

    定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。

    策略模式为了适应不同的需求,只把变化点封装了,这个变化点就是实现不同需求的算法,例如加班工资,不同的加班情况,有不同的计算加班工资的方法。

    我们不能在程序中将计算工资的算法进行硬编码,而能够自由变化。

    这就是策略模式。

     

    实验1 策略模式+简单工厂

    代码

    #include <iostream>
    using namespace std;
    
    // Define the strategy type
    typedef enum StrategyType
    {
        StrategyA,
        StrategyB,
        StrategyC
    }STRATEGYTYPE;
    
    // The abstract strategy
    class Strategy
    {
    public:
        virtual void AlgorithmInterface(int x, int y) = 0;
        virtual ~Strategy() = 0; 
    };
    
    Strategy::~Strategy()
    {}
    
    class ConcreteStrategyA : public Strategy
    {
    public:
        void AlgorithmInterface(int x, int y)
        {
            cout << "I am from ConcreteStrategyA: result=X+Y, = " << x+y << endl;
        }
    
        ~ConcreteStrategyA(){
            cout << "~ConcreteStrategyA()." << endl;
        }
    };
    
    class ConcreteStrategyB : public Strategy
    {
    public:
        void AlgorithmInterface(int x, int y)
        {
            cout << "I am from ConcreteStrategyB: result=X*Y, = " << x*y << endl;
        }
    
        ~ConcreteStrategyB(){
            cout << "~ConcreteStrategyB()." << endl;
        }
    };
    
    class ConcreteStrategyC : public Strategy
    {
    public:
        void AlgorithmInterface(int x, int y)
        {
            cout << "I am from ConcreteStrategyC: result=X-Y, = " << x-y << endl;
        }
    
        ~ConcreteStrategyC(){
            cout << "~ConcreteStrategyC()." << endl;
        }
    };
    
    // 用户类 : 使用算法的用户
    class Context
    {
    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(int x, int y) // 定义一个接口来让Stategy访问用户的数据
        {
            if (pStrategy)
                pStrategy->AlgorithmInterface(x, y);
        }
    
    private:
        Strategy *pStrategy; // 维护一个对Stategy对象的引用或指针
        int a;               // 私有数据,这是用户数据,该用户是独立于算法的用户,用户不需要了解算法内部的数据结构
        int b;
    };
    
    int main()
    {
        Context *pContext = new Context(StrategyA);
        pContext->ContextInterface(100, 6);
    
        if (pContext) 
            delete pContext;
    }
    

    上述的例子是策略模式,我们还能看到一点简单工厂模式的影子。

    百度到的绝大多数都是这种例子了。 这个代码完美吗?看下GoF的要领:

    如果我们需要新增新的算法,我们需要修改Context类的构造函数,在里面新增新的算法,这显然不符合GoF采用扩展、子类化的精要。

    所以引出了我下面的策略模式+抽象工厂的解决方案。

    实验2 策略模式+抽象工厂

    代码

    #include <iostream>
    using namespace std;
    
    
    // The abstract strategy
    class Strategy
    {
    public:
        virtual void AlgorithmInterface(int x, int y) = 0;
        virtual ~Strategy() = 0; 
    };
    
    Strategy::~Strategy()
    {}
    
    class ConcreteStrategyA : public Strategy
    {
    public:
        void AlgorithmInterface(int x, int y)
        {
            cout << "I am from ConcreteStrategyA: result=X+Y, = " << x+y << endl;
        }
    
        ~ConcreteStrategyA(){
            cout << "~ConcreteStrategyA().析够" << endl;
        }
    };
    
    class ConcreteStrategyB : public Strategy
    {
    public:
        void AlgorithmInterface(int x, int y)
        {
            cout << "I am from ConcreteStrategyB: result=X*Y, = " << x*y << endl;
        }
    
        ~ConcreteStrategyB(){
            cout << "~ConcreteStrategyB().析够" << endl;
        }
    };
    
    class ConcreteStrategyC : public Strategy
    {
    public:
        void AlgorithmInterface(int x, int y)
        {
            cout << "I am from ConcreteStrategyC: result=X-Y, = " << x-y << endl;
        }
    
        ~ConcreteStrategyC(){
            cout << "~ConcreteStrategyC().析够" << endl;
        }
    };
    
    // 用户类 : 使用算法的用户
    class Context
    {
    public:
        Context(Strategy* paraStrategy)
        {
            pStrategy = paraStrategy;
        }
    
        ~Context()
        {
            // 这里不需要析够pStrategy, pStrategy对应对象的析够会在delete pAbstractStrategyFactory时进行。
            // 即,销毁具体某个策略工厂对象时会负责析够具体的策略对象。所以这里就不需要了。
        }
    
        void ContextInterface(int x, int y) // 定义一个接口来让Stategy访问用户的数据
        {
            if (pStrategy)
                pStrategy->AlgorithmInterface(x, y);
        }
    
    private:
        Strategy *pStrategy; // 维护一个对Stategy对象的引用或指针
        int a;               // 私有数据,这是用户数据,该用户是独立于算法的用户,用户不需要了解算法内部的数据结构
        int b;
    };
    
    
    
    // 点评该类: 一条产品线下的产品,通常存在共性,
    // 也就是说,维护一个对产品的抽象类通常是需要的,而不是必须的。   
    
    class AbstractStrategyFactory   // 抽象工厂这里可以实现多个纯虚方法
    {
    public:
        virtual Strategy* createStrategy(string Strategy)=0;
        virtual ~AbstractStrategyFactory(){}
    };
      
    class StrategyA_Factory:public AbstractStrategyFactory
    {
    Strategy *pStrategy;
    public:
        StrategyA_Factory():pStrategy(NULL)
        {}
        Strategy* createStrategy(string Strategy)
        {
            if(Strategy == "StrategyA"){
                pStrategy = new ConcreteStrategyA();
                return pStrategy;
            }
            return NULL;
        }
        ~StrategyA_Factory()
        {
            cout << "~StrategyA_Factory(). 析够" << endl;
            if(pStrategy)
                delete pStrategy;
        }
    };
    
    class StrategyB_Factory:public AbstractStrategyFactory
    {
    Strategy *pStrategy;
    public:
        StrategyB_Factory():pStrategy(NULL)
        {}
        Strategy* createStrategy(string Strategy)
        {
            if(Strategy == "StrategyB"){
                pStrategy = new ConcreteStrategyB();
                return pStrategy;
            }
            return NULL;
        }
        ~StrategyB_Factory()
        {
            if(pStrategy)
                delete pStrategy;
        }
    };
    
    class StrategyC_Factory:public AbstractStrategyFactory
    {
    Strategy *pStrategy;
    public:
        StrategyC_Factory():pStrategy(NULL)
        {}
        Strategy* createStrategy(string Strategy)
        {
            if(Strategy == "StrategyC"){
                pStrategy = new ConcreteStrategyC();
                return pStrategy;
            }
            return NULL;
        }
        ~StrategyC_Factory()
        {
             if(pStrategy)
                delete pStrategy;       
        }
    };
    
    int main(int argc, char *argv[])
    {
        AbstractStrategyFactory* pAbstractStrategyFactory;  // 创建抽象工厂指针
     
        pAbstractStrategyFactory = new StrategyA_Factory();       // 创建策略A的工厂
        Strategy* pStrategy = pAbstractStrategyFactory->createStrategy("StrategyA");  //使用策略A工厂来生产出策略A
        if(pStrategy == NULL)
        {
            cout << "pStrategy is NULL" << endl;
        }
        else
        {
        // 供用户来使用策略A : 用户使用策略A 和 策略A的实现,是松耦合的。
        Context *pContext = new Context(pStrategy);
        pContext->ContextInterface(100, 6);
    
        delete pAbstractStrategyFactory;
    
        if (pContext) 
            delete pContext;
        }
    
        return 0;
      
    }
    

    编译运行:

    此时,如果要新增算法,那我觉得可以采用扩展、子类化的解决方案了,而不用像本博文上一个例子那样,去修改已有的代码了。

    说大白话,如果要新增算法,现在只需要在已有代码基础上去新增新算法的相关代码,而不是去修改已经写好的一些函数的内部实现。

    当然,这样的设计会导致代码量变大,所以一切都需要权衡,适合自己的就是最好的。

    .

    /************* 社会的有色眼光是:博士生、研究生、本科生、车间工人; 重点大学高材生、普通院校、二流院校、野鸡大学; 年薪百万、五十万、五万; 这些都只是帽子,可以失败千百次,但我和社会都觉得,人只要成功一次,就能换一顶帽子,只是社会看不见你之前的失败的帽子。 当然,换帽子决不是最终目的,走好自己的路就行。 杭州.大话西游 *******/
  • 相关阅读:
    Word Ladder
    Word Ladder II
    Valid Palindrome
    java 正则表达式-忽略大小写与多行匹配
    Vue自定义指令
    定义格式化时间的全局过滤器
    Vue过滤器的使用
    daterangepicker 设置默认值为空(转载)
    js时间戳与日期格式之间的互转
    Vuedevtools安装
  • 原文地址:https://www.cnblogs.com/happybirthdaytoyou/p/14545629.html
Copyright © 2011-2022 走看看