设计模式之策略模式(Strategy)

前言

在学习侯捷老师的有关设计模式的课程(李建忠老师主讲)中,老师对23种设计模式的有自己的划分,如下。所以老师讲解是按照这种顺序讲解。
在这里插入图片描述
组件协作:
在这里插入图片描述

Strategy

1.使用场合

在这里插入图片描述
简单说就是,就是可能今天调用"加法";明天可能调用"乘法";后天发现又需要"除法"了,所以代码需要加一个“除法”的算法
这些算法是由客户程序决定使用哪一种。

这其实就像多重if else的条件选择语句。

2.案例1

我们可以想想下面一种场景:不同国家有不同的税率,我们需要根据是哪个国家,调用不同的税率计算方式。

方式1:

#include <iostream>
using namespace std;

enum TaxBase{
	CN_Tax,
	US_Tax,
	DE_Tax,
};

class SalesOrder{
	TaxBase tax;
public:
	SalesOrder(){}
	SalesOrder(TaxBase t):tax(t){}

	double CalculateTax(){
		//...
		if (tax == CN_Tax){
			cout << "CN tax law" << endl;
			return 1.1;
		}
		else if (tax == US_Tax){
			cout << "US tax law" << endl;
			return 1.2;
		}
		else if (tax == DE_Tax){
			cout << "DE tax law" << endl;
			return 1.3;
		}
	}
};
int main()
{
	SalesOrder s(CN_Tax);
	s.CalculateTax();

	system("pause");
	return 0;
}

这种情况下,虽然程序开发者封装好了这样的算法,只需要生成一个SalesOrder对象,然后传入是哪个国家的税法就行。

但是这里有一个问题:一旦公司的业务有扩展,比如现在对接的国家需要加入法国,那么程序开发者势必要

  1. 在枚举TaxBase中加入FR_Tax
  2. 同时修改类SalesOrder的方法CalculateTax(),加入一个计算FR_Tax情况下的分支。

这样的话,明显违背了设计原则中的开闭原则(对扩展开放,对更改封闭),不应采取。下面看方法2,使用策略模式就能解决这个问题。

方法2:策略模式

#include <iostream>
using namespace std;

class TaxStrategy{
public:
	virtual double Calculate() = 0;
	virtual ~TaxStrategy(){}
};

class CNTax : public TaxStrategy{
public:
	virtual double Calculate(){
		cout << "CN tax law" << endl;
		return 1.1;
	}
};

class USTax : public TaxStrategy{
public:
	virtual double Calculate(){
		cout << "US tax law" << endl;
		return 1.2;
	}
};

class DETax : public TaxStrategy{
public:
	virtual double Calculate(){
		cout << "DE tax law" << endl;
		return 1.3;
	}
};


class SalesOrder{
private:
	TaxStrategy* strategy;
public:
	SalesOrder(TaxStrategy* TaxStrategy){
		strategy = TaxStrategy;
	}
	~SalesOrder(){
		delete this->strategy;
	}

	double CalculateTax(){
		return strategy->Calculate(); //多态调用
	}
};

int main()
{
	SalesOrder s(new CNTax);
	s.CalculateTax();

	system("pause");
	return 0;
}

当我们需要加入法国相关的祱率计算时,只需扩展即可,不用修改已有的代码,如下:

class FRTax : public TaxStrategy{
public:
	virtual double Calculate(){
		cout << "FR tax law" << endl;
		return 1.4;
	}
};

3.案例2:

商场里有两种促销方式:上午满200减50;下午一律打8折。输入价格,根据是上午还是下午,打印出最终的成交价格。

#include<iostream>
using namespace std;

class PromoteSaleStrategy
{
public:
	PromoteSaleStrategy(){}
	virtual ~PromoteSaleStrategy(){}
	virtual double CalculateMethod(double originalprice) = 0;//虚方法
};

class BackCashStrategy : public PromoteSaleStrategy
{
public:
	virtual double CalculateMethod(double originalprice){//虚函数,多态
		if (originalprice > 200){
			std::cout << "返现50" << std::endl;
			return originalprice - 50;
		}
		else{
			std::cout << "无法返现" << std::endl;
			return originalprice;
		}
	}
};
class DiscountStrategy : public PromoteSaleStrategy
{
public:
	virtual double CalculateMethod(double originalprice){//虚函数,多态
		std::cout << "打了8折" << std::endl;
		return originalprice*0.8;
	}
};



class SeLLProduct
{
public:
	SeLLProduct(double price) :_price(price){}
	~SeLLProduct(){}

	void setStrategy(PromoteSaleStrategy* pss){
		_pss = pss;
	}
	void Sell(){
		//多态调用
		std::cout << "当前价格:" << _pss->CalculateMethod(_price) << std::endl;
	}

private:
	PromoteSaleStrategy* _pss;
	double _price;
};

int main()
{
	double price;
	cout << "请输入价格:" ;
	cin >> price;
	SeLLProduct item(price);

	int n;
	cout << "现在是上午还是下午?1:上午  2:下午" << endl;
	cin >> n;
	if (n == 1){
		cout << "上午返现" << endl;
		item.setStrategy(new BackCashStrategy);	
		item.Sell();
	}
	else if (n == 2){
		cout << "下午打折" << endl;
		item.setStrategy(new DiscountStrategy);
		item.Sell();
	}


	system("pause");
	return 0;
}

上述使用策略设计模式,可以很好应对以后有新增的促销方式,并且将促销策略和类SeLLProduct解耦合。

4.模式定义

在这里插入图片描述

  • 这里的"相互替换(变化)"就像案例1中的CNTax USTax DETax子类和案例2中的DiscountStrategy BackCashStrategy子类。
  • 这里"客户程序(稳定)"就像案例1中的SalesOrder和案例2中的SeLLProduct,他们只需拿着基类指针即可。

5.结构

在这里插入图片描述

6.要点总结

  1. Strategy类及其子类提供了一系列可重用的算法,从而可以使得在运行时(指的是多态调用时)方便地根据需要选择算法。
  2. Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值