PHP設計模式漫談之調解者模式

Websites發表於2015-07-22

原文出處:blogspot

我們將給大家介紹調解者模式,這個模式的目的是封裝一組物件之間的相互作用,防止物件之間相互干擾,調解者(Mediator)在同事物件(Colleague)之間充當中間匯聚點。

同事物件之間應該保持鬆散耦合,避免一個物件直接明確指向另一個物件。在調解者模式下,物件的關係和依賴發生衝突時,我們可以使用調解者在耦合的物件之間協調工作流,依賴可以從同事朝調解者或從調解者向同事建立,這兩個方向上的依賴都可以使用AbstractColleague或AbstractMediator中斷。

圖1 調解者和同事物件

物件不是孤立的,物件之間必須相互協作才能完成任務。雖然調解者模式可以限制物件之間的相互作用,但如果濫用,會致使編寫聚合性類變得非常困難。舉一個實用的例子,在領域驅動設計(Domain-Driven Design)中的服務就是實體之間的調解者。再舉一個PHP相關的例子,Zend_Form裝飾和過濾功能實際上可以看作是Zend_Form_Decorator和Zend_Filter例項之間的一個簡單調解者,它們都使用Zend_Validate物件進行驗證。

當調解者必須監聽同事物件的事件時,它通常是作為觀察者(Observer)實現的,產生一個黑板(blackboard)物件,一些同事寫,另一些同事就讀。來自同事的事件被推向調解者,再由調解者將其轉發給其它訂閱的同事,同事之間不需要相互瞭解,這個架構成功用於隨Zend框架釋出的Dojo JavaScript庫。這個模式的另一個好處是物件的變化包含在計算方法中,可以通過配置不同的調解者實現這一目標,但例項化相關物件將是一個鬆散的操作,不同容器和工廠之間的協作關係將是分散的。參與者:

◆同事(Colleague):重點是它的職責,它只與一個調解者Mediator或AbstractMediator通訊。

◆調解者(Mediator):協同多個Colleagues(AbstractColleagues)共同工作。

◆AbstractMediator,AbstractColleague:從這些角色的真實實現解耦的可選介面,可能不止一個AbstractColleague角色。

下面的程式碼實現了一個表單輸入的過濾過程,類似於Zend_Form_Element功能。

<?php 
/** 
 
* AbstractColleague. 
 
*/
interface Filter 
{ 
 public function filter($value); 
} 
 
/** 
 
* Colleague. We decide in the implementation phase 
 
* that Colleagues should not know the next Colleague 
 
* in the chain, resorting to a Mediator to link them together. 
 
* This choice succesfully avoids a base abstract class 
 
* for Filters. 
 
* Remember that this is an example: it is not only 
 
* Chain of Responsibility that can be alternatively implemented 
 
* as a Mediator. 
 
*/
class TrimFilter implements Filter 
{ 
 public function filter($value) 
 { 
 return trim($value); 
 } 
}

/** 
 
* Colleague. 
 
*/
class NullFilter implements Filter 
{ 
 public function filter($value) 
 { 
 return $value ? $value : ''; 
 } 
} 
 
/** 
 
* Colleague. 
 
*/
class HtmlEntitiesFilter implements Filter 
{ 
 public function filter($value) 
 { 
 return htmlentities($value); 
 } 
}

/** 
 
* The Mediator. We avoid referencing it from ConcreteColleagues 
 
* and so the need for an interface. We leave the implementation 
 
* of a bidirectional channel for the Observer pattern's example. 
 
* This class responsibility is to store the value and coordinate 
 
* filters computation when they have to be applied to the value. 
 
* Filtering responsibilities are obviously a concern of 
 
* the Colleagues, which are Filter implementations. 
 
*/
class InputElement 
{ 
 protected $_filters; 
 protected $_value; 
 
 public function addFilter(Filter $filter) 
 { 
 $this->_filters[] = $filter; 
 return $this; 
 } 
 
 public function setValue($value) 
 { 
 $this->_value = $this->_filter($value); 
 } 
 
 protected function _filter($value) 
 { 
 foreach ($this->_filters as $filter) { 
 $value = $filter->filter($value); 
 } 
 return $value; 
 } 
 
 public function getValue() 
 { 
 return $this->_value; 
 } 
} 
 
$input = new InputElement(); 
$input->addFilter(new NullFilter()) 
 ->addFilter(new TrimFilter()) 
 ->addFilter(new HtmlEntitiesFilter()); 
$input->setValue(' You should use the <h1>-<h6> tags for your headings.'); 
echo $input->getValue(), "\n";



相關文章