C++设计模式02-——策略设计模式

C++设计模式02-——策略设计模式

文章目录

    • C++设计模式02-——策略设计模式
      • 一、策略模式的定义:
      • 二、快速理解策略模式:
        • 1. 概述理解
        • 2. 问题场景
        • 3. 策略模式
      • 三、策略模式案例
        • 1. 不同国家税收问题(极客班)
        • 2. 不同鸭子的问题(尚硅谷)

一、策略模式的定义:

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

二、快速理解策略模式:

1. 概述理解

    策略 ——普通语境下,是我们对一件事情的处理方法,由于对不同的事情我们有不同的应对方式,我们通过权衡利弊,得到合适的方案,这个过程就是挑选策略。
    在面向对象编程中,对于某类事务,有着不同的处理方式,将这些方式向上抽象一层就有了策略模式。这里并不是说一般的处理方式不能完成任务,而是我们的代码是面对变化的需求的,我们要让代码简单方便维护,所以才需要此类设计模式。
 

2. 问题场景

    比如,对于早餐来说,想吃馒头、包子、吃油条、吃面包…就要自己买或者自己做这些食物,我们把得到某食物的过程称为做(make)某食物(无论是自己做还是买),早餐吃什么完全取决于自己的想法,想吃啥就要有人做它,现在需求是根据自己的想法显示主食的制作过程,有伪代码如下:

enum StapleFood{ // 主食
    ManTou, // 馒头
    BaoZi, // 包子
    YouTiao, // 油条
    MianBao, // 面包
};

class Breakfast {// 早餐类
private:
	StapleFood staplefood;
public:
    Breakfast() {}
	Breakfast(StapleFood stfood) : staplefood(stfood) {}
 	void setStapleFood(StapleFood stfood) {
 		staplefood = stfood;
 	}
 	void MakeFoodInfo() {
 	    if (staplefood == Mantou) {
 	    	cout << "正在蒸馒头" << endl;
 	    	cout << "......" << endl; // 蒸馒头一系列复杂操作
 	    } else if (staplefood == Baozi ) {
 	    	cout << "正在做包子:" << endl;
 	    	cout << "......" << endl; // 做包子一系列操作
 	    } else if (staplefood == YouTiao) {
 	    	cout << "正在炸油条:" << endl;
 	    	cout << "......" << endl; // 炸油条一系列操作
 	    }
 	}
};

    当主食随着时代发展,可能出现几十上百种食物,它们制作过程各不相同,而且工艺复杂,想要增加一种早餐主食,至少要修改:

  1. 枚举类型:主食
enum StapleFood{ // 主食
    ManTou, // 馒头
    BaoZi, // 包子
    YouTiao, // 油条
    MianBao, // 面包
    添加主食类型
};
  1. 函数MakeFoodInfo:制作过程信息
void MakeFoodInfo() {
 	    if (staplefood == Mantou) {
 	    	cout << "正在蒸馒头" << endl;
 	    	cout << "......" << endl; // 蒸馒头一系列复杂操作
 	    } else if (staplefood == Baozi ) {
 	    	cout << "正在做包子:" << endl;
 	    	cout << "......" << endl; // 做包子一系列操作
 	    } else if (staplefood == YouTiao) {
 	    	cout << "正在炸油条:" << endl;
 	    	cout << "......" << endl; // 炸油条一系列操作
 	    } else if(staplefood == 添加的主食) {
 	        添加制作该食物的过程
 	    }
 	}

严重违反开闭原则! ,因为一旦添加一种食物,就要在原先的结构上修修改改,这样很容易出错,策略模式应运而生。
 

3. 策略模式

    策略模式的做法很简单,也就是我在上面所说的,将这些方式向上抽象一层,利用多态的特性,在C++中让子类继承抽象基类,在java中还可以通过实现抽象接口的形式操作(后面会讲到)。
    沿承上面的早餐的例子,对于主食我们完全可以做一个抽象,如下:

class StapleFood {
public:
  	StapleFood() {}
  	virtual void MakeFoodInfo() = 0;
  	virtual ~StapleFood() {}
};

此时,主食是一个抽象类,因为其含有纯虚函数。
对于目前的主食信息,有:

class MaTou : public StapleFood 
{
  	virtual void MakeFoodInfo() {
  		cout << "正在蒸馒头" << endl;
      	cout << "......" << endl; // 蒸馒头一系列复杂操作
  	}
};
class  BaoZi  : public StapleFood 
{
  	virtual void MakeFoodInfo() {
  		cout << "正在做包子:" << endl;
      	cout << "......" << endl; // 做包子一系列操作
    }
};
class YouTiao : public StapleFood  
{
	virtual void MakeFoodInfo() {
	   cout << "正在炸油条:" << endl;
       cout << "......" << endl; // 炸油条一系列操作
    }
};

这时候把所有美食的制作都交给厨师统一管理:

class Cook {
private:
	StapleFood* staplefood;
public:
	Cook() {}
    Cook(StapleFood* stfood) : staplefood(stfood) {}
    void setStapleFood(StapleFood* stfood) {
    	staplefood = stfood;
    }
    void MakeFoodInfo() {
       if (staplefood == nullptr) {
       		cout << "厨师没有做饭——饿着吧(谁让你没告诉厨师想吃什么)" << endl;
       		return;
       }
       staplefood->MakeFoodInfo();
    }
}

如果早餐想吃包子,就这样告诉厨师:

int main() {
	Cook* cook = new Cook();// new (找)一个厨师
	cook->setStapleFood(new BaoZi()); // 告诉厨师想吃包子
	cook->MakeFoodInfo(); // 厨师开始做包子
    
    return 0;
}

也可以, new出厨师的同时指定厨师做某种食物(现实意义就是为了吃某种食物专门聘请厨师)

int main() {
	BaoZi* baozi = new BaoZi(); // 想吃包子了
	Cook *cook = new Cook(baozi);// 找一个超级会做包子的厨师
	cook->MakeFoodInfo(); // 厨师开始做包子
    
    return 0;
}

 
这个时候当主食随着时代发展,比如推出了新的主食——奥力给,拓展只要新建文件:

class AoLiGei : public StapleFood  
{
	virtual void MakeFoodInfo() {
	   cout << "正在制作奥里给:" << endl;
       cout << "......" << endl; // make奥里给一系列操作
    }
};

这样,并没有修改旧的文件,这里说明一下,一般开发,一个类是放在一个.cpp和.h文件里面的,.h为类的声明,.cpp里面是对类的方法的实现(不考虑内联类,上面代码均为内联而且一个文件里面出现多个类,只是为了方便),我们这种做法(指策略模式),并没有改变旧文件,而是添加了新文件,根本不会对以前的业务造成影响,拓展性极强!
 
这个时候走进来一个美食家: ——嗨害嗨!虽然不是同一个时间,但是在同一个撤硕
针对它的口味,我们可以新建一个AoLiGei类继承自StapleFood(主食),其他地方不需要大的改动。

int main() {
	AoLiGei* aoligei = new AoLiGei(); // 想吃***了
	Cook *cook = new Cook(aoligei);// 不用厨子了,自产自销————指自己做自己吃(杆菌又卫生)
	cook->MakeFoodInfo(); // making 造它就完了!干了~奥里给!
    
    return 0;
}

  

三、策略模式案例

1. 不同国家税收问题(极客班)

代码被我调试过,和老师讲课的时候略有不同,老师上课用的伪代码

初始代码:

// test02.cpp
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

enum TaxBase{
	CN_Tax,
	US_Tax,
	DE_Tax,
	FR_Tax
};

class SalesOrder {
	TaxBase tax;
public:
    void setTaxType(TaxBase tax) {
    	this->tax = tax;
    }
    double CalculateTax() {
   	   double val = 0.0;
        //...
       if (tax == CN_Tax) {
       	  	return 1.0;
       } else if (tax == US_Tax) {
       		return 2.0;
       } else if (tax == DE_Tax) {
       		return 3.0;
       } else if (tax == FR_Tax) {
       		return 4.0;
       }
        //...
        return val;
    }
};

int main() {

	SalesOrder* salesOrder = new SalesOrder();
	salesOrder->setTaxType(US_Tax);

	cout << salesOrder->CalculateTax() << endl;

	return 0;
}

改进代码:

// test01.cpp
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

class Context {
public:
	Context() {}
};

class TaxStrategy {
public:
    virtual double Calculate(const Context& context) = 0;
    virtual ~TaxStrategy() {}
};

class CNTax : public TaxStrategy {
public:
    virtual double Calculate(const Context& context) {
    	double res = 0.0;
        //***********
        return res;
    }
};

class USTax : public TaxStrategy {
public:
    virtual double Calculate(const Context& context) {
    	double res = 1.0;
        //***********
        return res;
    }
};

class DETax : public TaxStrategy {
public:
    virtual double Calculate(const Context& context) {
    	double res = 2.0;
        //***********
        return res;
    }
};

//扩展
//*********************************
class FRTax : public TaxStrategy {
public:
    virtual double Calculate(const Context& context) {
    	double res = 3.0;
        //.........
        return res;
    }
};

class StrategyFactory {
public:
	virtual TaxStrategy* NewStrategy() = 0;
	virtual ~StrategyFactory() {}
};

class CNFactory : public StrategyFactory {
public:
	virtual TaxStrategy* NewStrategy() {
		return new CNTax();
	}
};

class USFactory : public StrategyFactory {
public:
	virtual TaxStrategy* NewStrategy() {
		return new USTax();
	}
};

class DEFactory : public StrategyFactory {
public:
	virtual TaxStrategy* NewStrategy() {
		return new DETax();
	}
};

class FRFactory : public StrategyFactory {
public:
	virtual TaxStrategy* NewStrategy() {
		return new FRTax();
	}
};


class SalesOrder {
private:
    TaxStrategy* strategy;

public:
    SalesOrder(StrategyFactory* strategyFactory) {
        this->strategy = strategyFactory->NewStrategy();
    }
    ~SalesOrder() {
        delete this->strategy;
    }

   double CalculateTax() {
        //...
        Context context;
        double val = strategy->Calculate(context); //多态调用
        //...
        return val;
   }
};

int main() {

	StrategyFactory* strategy = new USFactory();//CNFactory();

	SalesOrder* salesOrder = new SalesOrder(strategy);

	cout << salesOrder->CalculateTax() << endl;

	return 0;
}

代码来自网络——如有侵权联系我删除

2. 不同鸭子的问题(尚硅谷)

   点击这个跳转视频,尚硅谷-设计模式-策略模式,韩老师用的eclipse,java示例,视频很清楚代码如何写的,自己动手丰衣足食。
 

上面两个包括我举得例子思想都是一致的,就没有具体分析了,另外说明,尚硅谷韩老师在讲解这个例子的时候用的是java写的,使用了接口,而李老师使用C++讲解没有用接口(C++好像没接口),使用的继承,但是都是一个思想,我思考了一些时间后得出的结论。


THE END…

你可能感兴趣的:(C++设计模式,c++,设计模式,策略模式)