策略模式
策略模式又称为:Strategy。策略模式是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类,以使算法的对象能够相互替换。
上文主要是说的可替换的,日常生活中可替换非常常见,如我们去一个地方(西藏)?我们可以骑单车、骑摩托、坐汽车、坐火车、坐飞机等,这些都是我们出行可替换的。
上述:骑单车、骑摩托、坐汽车、坐火车、坐飞机等,每一种就是一种算法,可以由我们自己进行定义。
问题
假设我们向商场的各种商户开发一款商场收银软件,需要对顾客买的商品的单价和数量进行收费,我们针对不同商家,我们需要对顾客购买的商品进行包括但不限于:打折、满减、随机立减。
让人头疼的是,每个商家对这些折扣模式都不一样,A 商家需要打 5 折,B 商家打 8 折,C 商家需要达到 100 满减 5 元。
这样我们不得写 N 中折扣模式,臃肿且使用最多的可能就那么几种,只是每个商家的价格模式不一样,那我们有没有一张策略能使每个商家都可以使用呢?
解决方法
我们可以使用策略模式,提供一个可替换的公共模板,每个商家可以在这个模式进行独家定制化,定制一套属于自己的方案,替换成自己的方案即可,这样既影响不到其他商家,也不会使整个软件臃肿。
阿这,这不是我们生活中常常遇到吗?提供一个模板给你,其他你自己来改,难不成这个是设计模式?
是的,其实设计模式和我们生活也息息相关,只是我们一直在做没有留意而已。
结构
Strategy:策略接口类,提供一个通用的策略类型(模版)。 Discount、PointRebate、PointRebate:具体策略类,提供不同的策略算法(不同的折扣类型)。 Payment:支付类,传入不同的策略对象实现不同的策略算法(收银类)。
代码示例
商场策略接口类
代码语言:javascript复制/**
* 商场策略接口类
*/
interface Strategy
{
/**
* 执行策略具体逻辑,如:满减、折扣、返利
* @return mixed
* @author chendashengpc
*/
public function execute();
}
具体策略类
代码语言:javascript复制/**
* 折扣类
*/
class Discount implements Strategy
{
public function execute()
{
// todo 业务代码
return '我是折扣策略';
}
}
/**
* 积分返利类
*/
class PointRebate implements Strategy
{
public function execute()
{
// todo 业务代码
return '我是积分返利策略';
}
}
/**
* 积分返利类
*/
class PointRebate implements Strategy
{
public function execute()
{
// todo 业务代码
return '我是积分返利策略';
}
}
支付类
代码语言:javascript复制/**
* 支付类
*/
class Payment
{
private Strategy $strategy;
/**
* 初始化函数
* @param Strategy $strategy
*/
public function __construct(Strategy $strategy)
{
$this->strategy = $strategy;
}
/**
* 支付策略
* @return mixed
* @author chendashengpc
*/
public function payStrategy()
{
return $this->strategy->execute();
}
}
客户端使用
代码语言:javascript复制/**
* 折扣
*/
$payment = new Payment(new Discount());
echo $payment->payStrategy() . PHP_EOL;
/**
* 积分返利
*/
$payment = new Payment(new PointRebate());
echo $payment->payStrategy() . PHP_EOL;
/**
* 购物返券
*/
$payment = new Payment(new ShoppingVoucher());
echo $payment->payStrategy() . PHP_EOL;
输出
代码语言:javascript复制php Client.php
我是折扣策略
我是积分返利策略
我是购物返券策略
UML
优缺点
优点
- 可以在运行时切换对象内的算法。
- 可以将算法的实现和使用算法的代码隔离开来。
- 可以使用组合来代替继承。
- 开闭原则。无需对上下文进行修改就能够引入新的策略。
缺点
- 如果的算法极少发生改变,那么没有任何理由引入新的类和接口。使用该模式只会让程序过于复杂。
- 客户端必须知晓策略间的不同——它需要选择合适的策略。
- 许多现代编程语言支持函数类型功能,允许在一组匿名函数中实现不同版本的算法。使用这些函数的方式就和使用策略对象时完全相同,无需借助额外的类和接口来保持代码简洁。