`

助人为乐的中介者模式(Mediator Pattern)

阅读更多

还记得我刚毕业的第一家公司是做b2c的,当时要做一个进销存系统,相信做过的人都应该清楚。拿最简单的进销存系统为例,其可分为采购管理、销售管理、和存货管理,三个模块相互依赖,假设现在公司为一家卖电脑的经销商:

1、销售情况

销售部门要反馈销售情况,畅销就多采购,滞销就不采购。

2、库存情况

即使是畅销产品,库存都有100台了,每天才卖出去1台,也不需要采购了!

库房有货,才能销售,空手套白狼是不行的。

库房的有容积限制的,不可有无限大,所以就有了清仓处理,需要停止采购,打拆销售。

3、督促采购

在特殊情况下,比如一个企业客户一次性购买100台,库存只有80台,这时需要催促采购。

实现代码如下:

<?php
class Purchase{
	public function buyComputer($number){
		$stock = new Stock();
		$sale = new Sale();
		$saleStatus = $sale->getSaleStatus();
		if($saleStatus>80){
			echo "采购电脑".$number."台\n";
			$stock->increase($number);
		}else{
			$buyComputer = $number/2;
			echo "采购电脑".$buyComputer."台\n";
			$stock->increase($buyComputer);
		}
	}
	public function refuseBuy(){
		echo "不再采购电脑\n";
	}
}


class Stock{
	private static $computer_number = 100;
	public function increase($number){
		self::$computer_number += $number;
		echo "库存数量为:".self::$computer_number."\n";
	}
	public function decrease($number){
		self::$computer_number -= $number;
		echo "库存数量为:".self::$computer_number."\n";
	}
	public function getStockNumber(){
		return self::$computer_number;
	}
	public function clearStock(){
		$purchase = new Purchase();
		$sale = new Sale();
		echo "库存数量为:".self::$computer_number."\n";
		//要求拆价销售
		$sale->offSale();
		//要求采购人员停止采购
		$purchase->refuseBuy();
	}
}

class Sale{
	public function sellComputer($number){
		$stock = new Stock();
		$purchase = new Purchase();
		if($stock->getStockNumber()<$number){
			$purchase->buyComputer($number);
		}
		echo "销售电脑".$number."台\n";
		$stock->decrease($number);
	}
	public function getSaleStatus(){
		$saleStatus = mt_rand(0,100);
		echo "电脑的销售情况为:".$saleStatus."\n";
		return $saleStatus;
	}
	public function offSale(){
		$stock = new Stock();
		echo "拆价销售电脑".$stock->getStockNumber()."台\n";
	}
}

$purchase = new Purchase();
$purchase->buyComputer(100);
$sale = new Sale();
$sale->sellComputer(1);
$stock = new Stock();
$stock->clearStock();
?>
运行结果:
电脑的销售情况为:70
采购电脑50台
库存数量为:150
销售电脑1台
库存数量为:149
库存数量为:149
拆价销售电脑149台
不再采购电脑
[Finished in 0.3s]

运行结果是我们所期望的,三个不同类型的参与者完成了各自的活动。但你有没有发现这三个类是彼此关联的?在之前的博客设计模式六原则中提到的迪米特法则认为“每个类只和朋友类交流”,这个朋友类并非越多越好,朋友类越多,耦合性越大,要想修改一个就得修改一片。何况这只是最简单的进销存,如果再加入物流管理,供应商管理,资产管理等等,那程序将会像蜘蛛网般。

 

现有一个助人为乐的中介者作为三个模块的交流核心,每个模块之间不再相互交流,要交流都通过中介者进行。每个模块只负责自己的业务逻辑,不属于自己的则丢给中介者处理,简化了各模块之间的耦合关系。类图如下:



 修改代码如下:

<?php
abstract class AbstractMediator {
	protected $purchase = null;
	protected $stock = null;
	protected $sale = null;

	public function __construct() {
		$this->purchase = new Purchase( $this );
		$this->stock = new Stock( $this );
		$this->sale = new Sale( $this );
	}

	abstract public function execute();
}

class Mediator extends AbstractMediator{
	public function execute() {
		$args = func_get_args();
		if ( !is_array( $args ) || empty( $args ) )
			return;
		$method = $args[0];
		unset( $args[0] );
		call_user_func_array( array( $this, $method ), $args );
	}
//中介者 Mediator定义多个private方法,目的是处理各个对象之间的依赖关系。
	private function buyComputer( $number ) {
		$saleStatus = $this->sale->getSaleStatus();
		if ( $saleStatus<=80 ) {
			$number = $number/2;
		}
		echo "采购电脑".$number."台\n";
		$this->stock->increase( $number );
	}

	private function clearStock() {
		echo "库存数量为:".$this->stock->getStockNumber()."\n";
		//要求拆价销售
		$this->sale->offSale();
		//要求采购人员停止采购
		$this->purchase->refuseBuy();
	}

	private function sellComputer( $number ) {
		if ( $this->stock->getStockNumber()<$number ) {
			$this->purchase->buyComputer( $number );
		}
		echo "销售电脑".$number."台\n";
		$this->stock->decrease( $number );
	}

	private function offSale() {
		echo "拆价销售电脑".$this->stock->getStockNumber()."台\n";
	}
}


abstract class AbstractColleague {
	protected $mediator = null;
	public function __construct( $mediator ) {
		$this->mediator = $mediator;
	}
}

class Purchase extends AbstractColleague{
	public function buyComputer( $number ) {
		$this->mediator->execute( 'buyComputer', $number );
	}
	public function refuseBuy() {
		echo "不再采购电脑\n";
	}
}

class Stock extends AbstractColleague{
	private static $computer_number = 100;
	public function increase( $number ) {
		self::$computer_number += $number;
		echo "库存数量为:".self::$computer_number."\n";
	}
	public function decrease( $number ) {
		self::$computer_number -= $number;
		echo "库存数量为:".self::$computer_number."\n";
	}
	public function getStockNumber() {
		return self::$computer_number;
	}
	public function clearStock() {
		$this->mediator->execute( 'clearStock' );
	}
}

class Sale extends AbstractColleague{
	public function sellComputer( $number ) {
		$this->mediator->execute( 'sellComputer', $number );
	}
	public function getSaleStatus() {
		$saleStatus = mt_rand( 0, 100 );
		echo "电脑的销售情况为:".$saleStatus."\n";
		return $saleStatus;
	}
	public function offSale() {
		$this->mediator->execute( 'offSale' );
	}
}

$mediator = new Mediator();
$purchase = new Purchase( $mediator );
$purchase->buyComputer( 100 );
$sale = new Sale( $mediator );
$sale->sellComputer( 1 );
$stock = new Stock( $mediator );
$stock->clearStock();

?>
运行结果:
电脑的销售情况为:70
采购电脑50台
库存数量为:150
销售电脑1台
库存数量为:149
库存数量为:149
拆价销售电脑149台
不再采购电脑
[Finished in 0.3s]

 加入中介者后,设计结构清晰了很多,而且类间的耦合性大大减少,代码质量也有了很大的提升。

 

 

中介者模式的定义

用一个中介对象封装一系列的对象交互,中介者使各对象不需要显性地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

中介者模式由以下几部门组成:

1、Mediator  抽象中介者角色

抽象中介者角色定义统一的接口,用于各同事角色之间的通信。

2、 Concrete Mediator  具体中介者角色

具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。

3、Colleague  同事角色

每一个同事角色都知道中介者角色,并且与其他的同事角色通信的时候,一定要通过中介者角色协作。每个同事类的行为分为两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等,这种行为叫做自发行为(Self-Method),与其他的同事类或中介者没有任何的依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法(Dep-Method)。

 

 

中介者模式的优点

减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然同时也降低了类间的耦合

 

 

中介者模式的缺点

中介者会膨胀得很大,而且逻辑复杂,原本N个对象直接的相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑也就越复杂。

 

 

中介者模式的实际应用(MVC)

相信大家都使用过MVC框架,其中的C(controller)就是一个中介者,叫做前端控制器(Front Controller),它的作用就是把M和V隔离开,协调M和V协同工作,把M运行的结果和V代表的视图融合成一个前端可以展示的页面,减少M和V的依赖关系。

 

 

中介者模式是一个非常好的封装模式,也是一个很容易被滥用的模式,一个对象依赖几个对象是再正常不过的事情,但是纯理论家就会要求使用中介者模式来封装这种依赖关系,这是非常危险的!因此在使用时请考虑中介者带来的膨胀问题。

  • 大小: 15 KB
3
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics