
观察者模式解决的问题
在我们的开发过程中,应该都或多或少的碰到过改动其中一部分代码会引起其他一连串改变的问题,显然想要完全避免这种情况不太可能,但我们也应答尽量减少对其他组件的依赖,而观察者模式就是为了解决这个问题。
举个例子来说,我们有一个帖子对象,代码如下:
class Post{protected $_userid = null;protected $_ip = null;protected $_content = null;function __construct(){// ...}// 发帖方法public function addPost(){// ... 发帖逻辑}}在上面是一个普通的帖子对象,随着发帖量和访问量越来越大,运营们开始不干了,公司也经常会接到投诉电话,说我们的网站有许多敏感内容和垃圾广告,因此我们需要做内容审核:首先是对用户的审核,一些黑名单用户应该被禁止发帖;二是对IP的审核;三是对内容敏感词的审核。因此我们的代码就成了如下的样子:class Post{protected $_userid = null;protected $_ip = null;protected $_content = null;function __construct(){}public function addPost(){if (!Postscan::checkUserid($tihs->_userid)) {return false;}if (!Postscan::ipUserid($tihs->_ip)) {return false;}if (!Postscan::checkContent($tihs->_content)) {return false;}// ... }}随着需要审核的字段越来越多,addPost方法变得越来越长,发布对象被也只能紧紧的被嵌入到该系统中。//主体必须实现的接口interface Observable {public function attach(Observer $observer);public function detach(Observer $observer);public function notify();}//观察者必须实现的接口interface Observer {public function do(Observable $subject);}class Post implements Observable{protected $_userid = null;protected $_ip = null;protected $_content = null;protected $_observerlist = array();function __construct(){}public function attach(Observer $observer){$this->_observerlist[] = $observer;}public function detach(Observer $observer){foreach ($this->_observerlist as $key => $value) {if ($observer === $value) {unset($this->_observerlist[$key])}}}public function notify(){foreach ($this->_observerlist as $value) {if (!$value->do($this)) {return false;}}return true;}public function addPost(){if (!$this->notify()) {return false;}// ... }}通过上面的代码,我们可以再很容易的加入审核规则。class Post implements SplSubject{protected $_userid = null;protected $_ip = null;protected $_content = null;protected $_storage = new SplObjectStorage();function __construct(){}public function attach(SplObject $observer){$this->_storage->attach($observer);}public function detach(SplObject $observer){$this->_storage->detach($observer);}public function notify(){foreach ($this->_storage as $value) {if (!$value->update($this)) {return false;}}return true;}public function addPost(){if (!$this->notify()) {return false;}// ... }}很简单吧,最重要的是理解,在这个例子中,我们把一些审核的方法从帖子类中剥离了开来,而且该帖子对象也可以用来作为其他的发布类型。