设计模式学习笔记-策略模式

考虑这样一个场景。我们要计算两个数的值,但是算法不确定,可以是加减乘除的任意一种,甚至可以是加减乘除任意组合计算。

就实现方式来说可以有多种。比如我可以通过if else 继续算法控制

class Context {
	private $_a = null;
	private $_b = null;
	public function __construct($a, $b) {
		$this->_a = $a;
		$this->_b = $b;
	}
	//
	public function calculate($flag) {
		if($flag == '1') { //加
			return $this->_a + $this->_b;
		}
		else if($flag == '2') { //减
			return $this->_a - $this->_b;
		}
		else if($flag == '3') { //乘
			return $this->_a * $this->_b;
		}
		else if($flag == '4') { //除
			return $this->_a / $this->_b;
		}
		return false;
	}
}

甚至可以通过计算,分别实现加减乘除的子类

abstract class Context {
	private $_a = null;
	private $_b = null;
	public function __construct($a, $b) {
		$this->_a = $a;
		$this->_b = $b;
	}
	//
	public abstract function calculate();
}
class AddContext extends Context {
	public function calculate(){
		return $this->_a + $this->_b;
	}
}
class SubtractContext extends Context {
	public function calculate(){
		return $this->_a - $this->_b;
	}
}
class MultiplyContext extends Context {
	public function calculate(){
		return $this->_a * $this->_b;
	}
}
class DivideContext extends Context {
	public function calculate(){
		return $this->_a / $this->_b;
	}
}

在上面的方法中一个通过if else实现,虽然能达到效果,但是当算法多的时候我们需要维护大量的if else,
同时,如果要添加算法,就需要在原来的类中修改,违反了OCP原则。而继承这种方法暴露的问题则是
1.继承实现会暴露一些不必要的接口,上面只是一个calculate,如果 我如果定义方法 public Axxx function(){} 。那么这些子类是可以访问和修改的
2.父类通常至少定义了部分子类的具体表示,因为继承对子类揭示了其父类的具体实现,所以破坏了封装。子类中的实现与它的父类有如此紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类变化。
3.继承无法重复利用基本的算法,比如其他地方也要用的加减乘除的算法。 也就是说,它们也要通过继承,去实现加减乘除。这样会引起类的暴增。 

因为上述原因,我们需要一个更好的方式去实现,即能减少if else的维护,又能有更好的扩展性,同时基本算法还能重复利用。

而这就需要引入今天的主角---策略模式

interface IStrategy {
	public function calculate($a,$b);
}
//加
class addStrategy  implements IStrategy {
	public function calculate($a, $b) {
		return $a + $b;
	}
}
//减
class SubtractStrategy  implements IStrategy {
	public function calculate($a, $b) {
		return $a - $b;
	}
}
//乘
class MultiplyStrategy  implements IStrategy {
	public function calculate($a, $b) {
		return $a * $b;
	}
}
//除
class DivideStrategy  implements IStrategy {
	public function calculate($a, $b) {
		return $a / $b;
	}
}

class Context {
	private $_a = null;
	private $_b = null;
	private $_strategy = null; //组合
	public function __construct($a, $b) {
		$this->_a = $a;
		$this->_b = $b;
	}
	public function setStrategy(IStrategy $strategy) {//设置算法
		$this->_strategy = $strategy;
	}
	public function calculate() {
		if(is_null($this->_strategy)) 
			return false;
		return $this->_strategy->calculate($this->_a, $this->_b); // 策略
	}
}

策略模式优缺点:

1.定义一个算法家族,这些算法可以相互替换,而不控制算法步骤,不依赖其他(组合,由弹性),相关算法系列 Strategy类层次为Context定义了一系列的可供重用的算法或行为

2.一个类定义了多种行为 , 并且这些行为在这个类的操作中以多个条件语句的形式出现。

3.将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句

4.有一个潜在的缺点就是一个客户要选择一个合适的Strategy就必须知道这些 Strategy到底有何不同。此时可能不得不向s使用者暴露具体的实现问题。因此仅当这些不同行为变体与使用者相关的行为时 , 才需要使用Strategy模式增加了对象数目

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值