<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## **觀察者模式** >[info] 當一個對象狀態發生改變的時候,依賴他的對象全部會收到通知,并且自動更新等等一連串的操作, 將這些一連串的操作(的邏輯代碼)放到觀察者列表里 >場景:一個事件發生后,要執行一連串的更新操作,傳統的編程方法,就是在事件的代碼之后直接加入邏輯處理,當更新的邏輯增多之后,代碼會變得難以維護。這種方式是耦合的,侵入式的。增加新的邏輯需要修改事件主體的代碼 察者模式實現了低耦合,非侵入式的通知與更新機制 >[danger]狀態觸發類的應用當你的程序要處理的對象有很多種狀態,就可以考慮使用這個模式 如果想在框架任何一個地方里插入其他邏輯二無需大的改動,請用觀察者模式,只需在需要的地方添加一段觸發觀察的代碼就可以 ## **業務場景:** **窗體程序設計中的事件處理**-- 窗體中的所有組件都是“事件源”,也就是目標對象,而事件處理程序類的對象是具體觀察者對象 **注冊**-- 一般和活動掛鉤如注冊送金幣和積分也可以送給推薦人 **下訂單**--下訂單就多了 活動是最起碼的 其次 比如發短信發郵件存入日志 **插件** -- 比如許多框架的第三方插件就是這個原理 **訂閱功能** --簡單的是一些第三方的支付接入或者其他功能接入,他們都暴露一個訂閱功能,你可以選擇訂閱,然后你就作為觀察者,每次第三方有更新和通知的時候,所有訂閱的人,都能收到更新通知了 ## **模式的應用場景** 1. 對象間存在一對多關系,一個對象的狀態發生改變會影響其他對象。 2. 當一個抽象模型有兩個方面,其中一個方面依賴于另一方面時,可將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和復用。 ## **模式的結構** 1. **抽象主題(Subject)角色**:也叫抽象目標類,它提供了一個用于**保存**觀察者對象的聚集類和**增加**、**刪除**觀察者對象的方法,以及**通知**所有觀察者的抽象方法。 2. **具體主題(Concrete??? Subject)角色**:也叫具體目標類,它實現抽象目標中的通知方法,當具體主題的內部狀態發生改變時,通知所有注冊過的觀察者對象。 3. **抽象觀察者(Observer)角色**:它是一個抽象類或接口,它包含了一個更新自己的抽象方法,當接到具體主題的更改通知時被調用。 4. **具體觀察者(Concrete Observer)角色**:實現抽象觀察者中定義的抽象方法,以便在得到目標的更改通知時更新自身的狀態。 ![](https://img.kancloud.cn/9b/b5/9bb5f48938374190f51ee96ff500987d_725x474.png) ``` //抽象目標 abstract class Subject { protected $_observers=array(); //增加觀察者方法 public function add(Observer $observer) { $this->_observers[]=$observer; } //刪除觀察者方法 public function remove(Observer $observer) { foreach($this->_observers as $index => $observer) { if ($observer === $observer) { array_splice($this->_observers, $index, 1); return; } } } //通知觀察者方法 public abstract function notifyObserver(); } //具體目標 class ConcreteSubject extends Subject { public function notifyObserver() { print_r("具體目標發生改變...<br>"); print_r("--------------<br>"); foreach ($this->_observers as $observer) { $observer->response(); } } } //抽象觀察者 interface Observer { function response(); //反應 } //具體觀察者1 class ConcreteObserver1 implements Observer { public function response() { print_r("具體觀察者1作出反應!"); } } //具體觀察者1 class ConcreteObserver2 implements Observer { public function response() { print_r("具體觀察者2作出反應!"); } } class ObserverPattern { public static function main() { $subject=new ConcreteSubject(); $subject->add(new ConcreteObserver1()); $subject->add(new ConcreteObserver2()); $subject->notifyObserver(); } } ObserverPattern::main(); ``` 例子: ``` //抽象主題角色 interface ISubject{ function addObserver( $observer ); } // 具體主題角色(被觀察者) 用于添加、刪除、保存、通知觀察者 class UserList implements ISubject{ private $_observers = array(); public function sendMsg( $name ){ foreach( $this->_observers as $obs ){ $obs->onSendMsg( $this, $name ); } } public function addObserver( $observer ){ $this->_observers[]= $observer; } public function removeObserver($observer_name) { foreach($this->_observers as $index => $observer) { if ($observer->getName() === $observer_name) { array_splice($this->_observers, $index, 1); return; } } } } //抽象觀察者 interface IObserver{ function onSendMsg( $sender, $args ); function getName(); } //具體觀察者角色1 class UserListLogger implements IObserver{ public function onSendMsg( $sender, $args ){ echo( "'$args' 以發送到 UserListLogger\n" ); } public function getName(){ return static::class;//同 return 'UserListLogger'; } } //具體觀察者角色2 class OtherObserver implements IObserver{ public function onSendMsg( $sender, $args ){ echo( "'$args' 已發送到 OtherObserver\n" ); } public function getName(){ return static::class;//同 return 'OtherObserver'; } } $ul = new UserList();//被觀察者 $ul->addObserver( new UserListLogger() );//增加觀察者 $ul->addObserver( new OtherObserver() );//增加觀察者 $ul->sendMsg( "Jack" );//發送消息到觀察者 echo "<br>"; $ul->removeObserver('UserListLogger');//移除觀察者 $ul->sendMsg("hello");//發送消息到觀察者 ``` ## **例子** php 內置了SplSubject與SplObserver接口可以更簡便的實現觀察者模式 >[info]newspaper是被觀察的對象,reader是觀察者。當報紙發布消息, 每一個用戶都會得到通知。這就是觀察者模式的使用場景 ~~~ class Newspaper implements SplSubject { private $name; private $observers; private $content; public function __construct($name){ $this->name = $name; $this->observers = new SplObjectStorage(); } //增加一個觀察者 public function attach(SplObserver $observer){ //向SplObjectStorage中添加一個對象 //此處為SplObjectStorage對象存儲類的attach方法而SplSubject 的 $this->observers->attach($observer); } //移除一個觀察者 public function detach(SplObserver $observer){ $this->observers->detach($observer); } //通知所有觀察者 public function notify(){ foreach ($this->observers as $observer) { $observer->update($this); } } public function getContent(){ return $this->content."{$this->name}"; } public function breakOutNews($content) { $this->content = $content; $this->notify(); } } <?php class Reader implements SplObserver { private $name; public function __construct($name){ $this->name = $name; } public function update(SplSubject $subject) { echo $this->name.' is reading breakout news'.$subject->getContent(); } } <?php include "Newspaper.php"; include "Reader.php"; class WorkFlow { public function run() { $newspaper = new Newspaper('紐約時報');//SplSubject $allen = new Reader("allen");//SplObserver $jimmy = new Reader("jimmy");//SplObserver $tom = new Reader("tom");//SplObserver $newspaper->attach($allen);// $newspaper->attach($jimmy); $newspaper->attach($tom); $newspaper->detach($tom); $newspaper->breakOutNews('USA BREAK DOWN'); } } $work = new WorkFlow(); $work->run(); ~~~ ## **php中的鉤子(hook插件機制)** 插件管理器類作為具體主題(被觀察者)角色:也叫具體目標類,用于保存、添加、刪除及通知觀察者(目的是執行入口函數) 插件作為觀察者,一旦被注冊則調用插件的入口函數 >[warning] /index.php ``` <?php define('ROOTPATH',__DIR__.DIRECTORY_SEPARATOR); /** * 獲取激活的插件 * @return array 返回激活的插件信息數組 */ function get_active_plugins(){ //一般從數據庫拉出 這里用數據模擬 $plugins=[ [ 'name' => 'demo', 'directory'=>'demo' ], ]; return $plugins; } require_once "./core/PluginManager.php"; $pluginManager=new PluginManager(); //trigger通知觀察者(插件) $pluginManager->trigger('demo',''); ``` >[warning] 插件管理類 /core/PluginManager.php ``` <?php class PluginManager{ private $_listeners=array(); public function __construct(){ $this->_init(); } private function _init(){ //外部獲取所有活動插件,返回包含插件名及插件目錄的數組 $plugins=get_active_plugins(); //循環實例激活 foreach ($plugins as $plugin) { $plugin_file=ROOTPATH.'plugins'.DIRECTORY_SEPARATOR.$plugin['directory'].DIRECTORY_SEPARATOR.'actions.php'; if (@file_exists($plugin_file)) { //加載這些插件的文件 include_once($plugin_file); }else{ throw new Exception('文件'.$plugin_file.'不存在!'); } //解析出這些插件的插件類名 $class = strtolower($plugin['name']).'_actions';//如demo_actions if(class_exists($class)){ //實例化插件類 同時實例化的插件析構方法調用register注冊插件(將實例放入$_listeners中) //等同 new demo_actions(PluginManager $this); $pluginManager->register('demo', $demo_actions_instance, 'say_hello'); new $class($this); }else{ throw new Exception($class.'不存在!'); } } } /** * 觸發一個鉤子 * * @param string $hook 鉤子的名稱 * @param mixed $data 鉤子的入參 * @return mixed */ public function trigger($hook,$data){ $result = ''; if (isset($this->_listeners[$hook]) && is_array($this->_listeners[$hook]) && count($this->_listeners[$hook]) > 0){ var_dump($this->_listeners); foreach ($this->_listeners[$hook] as $listener) { //他的key就是 demo_actions->say_hello // 取出插件對象的引用和方法 $class =& $listener[0]; $method = $listener[1]; if(method_exists($class,$method)) { // 動態調用插件的方法 $result .= $class->$method($data); } } } return $result; } /** * 注冊插件 * @param string $hook 鉤子的名稱 * @param obj &$reference 插件類實例的引用 * @param string $method 插件所執行的方法(插件入口方法) * @return void */ public function register($hook, &$reference, $method){ //獲取插件要實現的方法 $key = get_class($reference).'->'.$method; //將插件的引用連同方法push進監聽數組即$_listeners屬性中 $this->_listeners[$hook][$key] = array(&$reference, $method); #此處做些日志記錄方面的東西 } } ``` >[warning] /plugins/demo/actions.php ~~~ <?php /** *需要注意的幾個默認規則: * 1. 本插件類的文件名必須是action * 2. 插件類的名稱必須是{插件名_actions} */ class demo_actions { //解析函數的參數是pluginManager的引用 function __construct(PluginManager &$pluginManager) { //注冊這個插件 //第一個參數是鉤子的名稱 //第二個參數是該類實例的引用 //第三個是插件所執行的方法 $pluginManager->register('demo', $this, 'say_hello'); } function say_hello() { echo 'Hello World'; } } ~~~ ## [php插件機制原理之其他實現方式例子](https://www.jianshu.com/p/7747bbbd14c0)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看