【有毒的设计模式】策略模式

版权声明:O.O 欢迎转载,如果我有能力写到原创文章的话~ https://blog.csdn.net/qq_16468937/article/details/50965055

//Description:说些废话

唔... 我想吐槽一下.. 昨天看简单工厂模式的时候以为那个类多态就仅仅是多态的作用,我没想过那居然就是策略模式(虽然有那么点区别..)

然后特么我今天在Context类上钻了2小时的牛角尖,后来发现....GG....尼*炸了..炸了..炸了..


//部分资料来源:

1.C++实现的简单工厂模式示例来源:http://www.jellythink.com/archives/388

2.某些归纳话语:程杰——大话设计模式


//正文:

策略模式的使用场合——(摘自部分资料来源1那网址)


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





说一下这个UML图吧。

这个Strategy就是一个父对象,有一个虚方法AlgorithmInterface()方法,用于派生给子类。

这就是所说的策略模式定义:定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

从概念上看:所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。

对于上面这句话的理解,就是Strategy与其三个子类,还有三个子类相互之间实现了松耦合,三个子类之间可以相互替换。



那么我们试想一下,如果不用  策略模式/简单工厂模式  来实现上面这个东西的话会怎样?

那我们应该会在main函数里面写出这么些语句:


 
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int chooseNum = 0;
    cout<<"putIn 1/2/3"<<endl;
    cin>>chooseNum;
    switch(chooseNum)
    {
    case 1:
        cout<<"I am StrategyA"<<endl;
        break;
    case 2:
        cout<<"I am StrategyB"<<endl;
        break;
    case 3:
        cout<<"I am StrategyC"<<endl;
        break;
    }
    return a.exec();
}



有很多条件分支在主函数中是不是??那么我们是不是会想到用前面说过的简单工厂模式去封装一下?

那么我们封装一下

—————————————简单工厂模式    start————————————————————————————

为了方便理解,逐个贴吧,首先是一个纯虚类作为父类:


 
 
class Strategy
{
public:
    virtual void AlgorithmInterface() = 0;
};


 
 
 
 

然后就是三个继承下来的子类:


 
 
class ConcreteStrategyA : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout<<"I am StrategyA"<<endl;
    }
};
class ConcreteStrategyB : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout<<"I am StrategyB"<<endl;
    }
};
class ConcreteStrategyC : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout<<"I am StrategyC"<<endl;
    }
};


 
 
 
 
 
 
然后就是工厂了:

 
 
class NormalFactory
{
public:
    Strategy* createChoice(int chosenNum)
    {
        Strategy* tmp = nullptr;
        switch (chosenNum)
        {
        case 1:
            tmp = new ConcreteStrategyA();
            break;
        case 2:
            tmp = new ConcreteStrategyB();
            break;
        case 3:
            tmp = new ConcreteStrategyC();
            break;
        default:
            break;
        }
        return tmp;
    }
};



再然后就是主代码:


 
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int chooseNum = 0;
    cout<<"putIn 1/2/3"<<endl;
    cin>>chooseNum;
    Strategy* MyChosenStrategy = (new NormalFactory)->createChoice(chooseNum);
    MyChosenStrategy->AlgorithmInterface();
    return a.exec();
}


 
 
——————————————简单工厂模式   end     ————————————————————————————————
 
 
那么我们来分析一下:
 用了工厂模式,我们就不用再main函数里面写条件语句了,都交给了工厂NormalFactory去做,我们在main函数里面只需要调用工厂 
 

那么工厂就会帮我们生成一个我们需要的对应的策略子类

但是,你注意到没有,我们暴露了两个类给用户:

1.Strategy

2.NormalFactory

我们并没成功地把Srtategy与客户端分离,这样做有什么不好的地方呢?

那就是:当我们需要增加一个策略的时候,我们就需要对工厂类NormalFactory进行维护和扩展

其实我们进行了简单工厂模式,三个ConcreteStrategy子类已经是策略模式的三个具体策略了。

那么我们应该想一种方法,可以令到在main函数里面看不到Strategy这个纯虚类,只需要关注我们要用的Factory类就行了,对吧。

————————————————简单工厂+策略 模式 start   —————————————————————————————————

其实超简单,就把那个NormalFactory改一下就行(其实简单工厂那已经包含了一大部分的策略模式了)

NoramlFactory 改成 ContextFactory

 
 
class ContextFactory
{
public:
    ContextFactory(int chosenNum)
    {
        switch(chosenNum)
        {
        case 1:
            pStrategy = new ConcreteStrategyA();
            break;
        case 2:
            pStrategy = new ConcreteStrategyB();
            break;
        case 3:
            pStrategy = new ConcreteStrategyC();
            break;
        default:
            break;
        }
    }
    void ContextOutput()
    {
        if(pStrategy)
            pStrategy->AlgorithmInterface();
    }
private:
    Strategy *pStrategy;
};



然后我们就可以屏蔽了Strategy类了,在main里面的两句改一下:

这两句:

    Strategy* MyChosenStrategy = (new NormalFactory)->createChoice(chooseNum);
    MyChosenStrategy->AlgorithmInterface();
 
 
改成:
 
 
    ContextFactory *pContext = new ContextFactory(chooseNum);
    pContext->ContextOutput();

就行了.. 
 
 
————————————————————简单工厂+策略 模式   end  ————————————————————————————————
 
 
那么说到这里就说完了,下面贴一下简单工厂+策略模式的最终代码:
 
 
 
 
#include <iostream>
using namespace std;
class Strategy
{
public:
    virtual void AlgorithmInterface() = 0;
};
class ConcreteStrategyA : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout<<"I am StrategyA"<<endl;
    }
};
class ConcreteStrategyB : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout<<"I am StrategyB"<<endl;
    }
};
class ConcreteStrategyC : public Strategy
{
public:
    void AlgorithmInterface()
    {
        cout<<"I am StrategyC"<<endl;
    }
};
class ContextFactory
{
public:
    ContextFactory(int chosenNum)
    {
        switch(chosenNum)
        {
        case 1:
            pStrategy = new ConcreteStrategyA();
            break;
        case 2:
            pStrategy = new ConcreteStrategyB();
            break;
        case 3:
            pStrategy = new ConcreteStrategyC();
            break;
        default:
            break;
        }
    }
    void ContextOutput()
    {
        if(pStrategy)
            pStrategy->AlgorithmInterface();
    }
private:
    Strategy *pStrategy;
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int chooseNum = 0;
    cout<<"putIn 1/2/3"<<endl;
    cin>>chooseNum;
    ContextFactory *pContext = new ContextFactory(chooseNum);
    pContext->ContextOutput();
    return a.exec();
}



 
 

其实我想说,我用的是:简单工厂模式再用策略模式的方法,这种方法其实简单工厂那里已经包含了一部分的策略模式了,这也是我当初想了大半天,

都不知道究竟什么是策略模式的原因,还以为那只是简单的多态。。

所以如果要理解的更加清楚的话,我还是建议去看看刚刚部分资料来源1那个网址,那个网址是先实现策略模式,再加上简单工厂模式的,可能会好理解一点

我是参考两个资料自己码的代码,不知道有没有什么不对的地方,有不对求指出 ♂





//那么我自己的问题来了:

1.

Q:为什么说:从概念上看,所有这些算法都完成相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合?

A:首先ConcreteStragegyA、B、C 三个类相互之间是都是完成输出一句话的工作,只是输出的话不同,他们都可以用父类Stragtegy来调用,三个算法子类之间为松耦合。


2.

Q:策略模式有什么优点?

A:(1)策略模式简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

       (2)策略模式把switch的行为都封装起来,消除了这些行为的类中消除条件语句(其实我觉得是简单工厂模式封装起来的,其实是Strategy类的行为可以消除这些语句,所谓的封装了变化。所以看部分资料来源1的那个策略模式的实现,你会看到选择的实现是在main里面的,这就是我说为什么那个更加好理解的原因。。)


3.

Q:通俗地说,什么时候用策略模式?

A: 只要分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。

       更加通俗地说,就是你觉得几个子类都是重写父类的那个函数的时候,你就知道你想到的就是策略模式吧。


4.(这个是我要吐槽吐槽+吐槽的)

Q:为什么我老感觉策略模式就是多态?

A:网上搜了下答案:

   策略模式强调的是做同一件事情的不同方法,这些方法不能重复,也就是正交
   多态只不过是一种语言机智,有的不支持多态的语言一样也要实现策略
   策略处于设计层次,多态处于语言的层次

       哦...  好像明白了,这并不是一个层次的东西,网上说的差别很细微,现在刚进程序猿这个坑嘛,所以我还是要理直气壮地说..我特么觉得这策略模式就是多态..GG




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

猜你喜欢

转载自blog.csdn.net/qq_16468937/article/details/50965055