偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

基于CI的事件驅(qū)動(dòng)擴(kuò)展和開發(fā)規(guī)范

開發(fā) 架構(gòu)
最近在做一個(gè)網(wǎng)盤的項(xiàng)目,得到了很多經(jīng)驗(yàn)和教訓(xùn)??偨Y(jié)了一些常見的問(wèn)題,于是寫了下面這樣一個(gè)小東西來(lái)解決。

問(wèn)題

項(xiàng)目中為了追求速度和性能,數(shù)據(jù)庫(kù)的表設(shè)計(jì)往往不是滿足范式的。這就可能導(dǎo)致在改一個(gè)表中項(xiàng)目實(shí)體的元信息時(shí),需要同時(shí)修改其他表中的信息。比方說(shuō):我有一個(gè)一張表來(lái)表示虛擬的文件(每一行記錄表示一個(gè)文件),另一個(gè)張表用來(lái)記錄已經(jīng)發(fā)布的文件和生成的外鏈信息??赡転榱松龠M(jìn)行一次查表,我們會(huì)把文件的一些基本信息,如(文件名,發(fā)布人的名字)記錄在外鏈的表中。當(dāng)修改了文件表中的元信息時(shí),外鏈表中的信息也需要修改。常見的方法是使用ORM,但如果我還需要“根據(jù)具體情況再?zèng)Q定要修改其他表中的元信息”這種情況時(shí),ORM就有點(diǎn)難搞了。

同時(shí),我希望我在對(duì)上一個(gè)問(wèn)題中提到的“文件”數(shù)據(jù)進(jìn)行操作時(shí),不需要知道任何其他相關(guān)的細(xì)節(jié)。也就是將其他的這些關(guān)系劃到其他模塊去。

系統(tǒng)的接口往往需要復(fù)合的權(quán)限控制,并且在完成基礎(chǔ)的部分的權(quán)限控制之后,不希望由于后續(xù)功能的增加而去修改基礎(chǔ)部分。同時(shí)希望后續(xù)的這些功能在不啟用時(shí),系統(tǒng)能夠恢復(fù)到基礎(chǔ)的權(quán)限控制策略。比方說(shuō),一個(gè)模擬的網(wǎng)盤文件,我在系統(tǒng)沒有增加分享這個(gè)功能時(shí),權(quán)限控制策略是“只有自己可以訪問(wèn)”,在增加了分享功能后,策略是“指定分享的好友都可以訪問(wèn)”。為了在單獨(dú)完成分享模塊代碼時(shí)不修改之前的代碼,常用的方法是使用鉤子來(lái)拋出權(quán)限信息,系統(tǒng)自動(dòng)進(jìn)行復(fù)合,下面會(huì)詳述。

當(dāng)項(xiàng)目不是太大時(shí)(沒有大到需要使用HMVC等更高級(jí)的模式),需要一種簡(jiǎn)單、弱耦合的模塊管理和開發(fā)規(guī)范。

解決方案(以CI為基礎(chǔ)框架)

第一部分 

以 問(wèn)題1和2 中的例子來(lái)說(shuō),數(shù)據(jù)變化的主體是文件,其他都是跟隨變化。很自然就讓人想到觀察者模式,只不過(guò)我這里不是把“關(guān)聯(lián)”的類注冊(cè)到“文件”類中監(jiān)聽變化,而是聲明一個(gè)全局事件,每一個(gè)模塊都持有它的一個(gè)引用,都通過(guò)它來(lái)拋出事件,都通過(guò)監(jiān)聽它的事件來(lái)進(jìn)行自己的操作。

你可能會(huì)說(shuō)這在某種程度上破壞了模塊的封裝,因?yàn)槟K知道了上層的細(xì)節(jié)。但是這樣做就大大降低了模塊之間的耦合。首先,基礎(chǔ)模塊(“文件”)不用知道外部如何應(yīng)對(duì)變化,也不用管理外部的監(jiān)聽者,對(duì)自己的操作只需要拋出一個(gè)事件就夠了。對(duì)監(jiān)聽模塊來(lái)說(shuō),只需要監(jiān)聽系統(tǒng)統(tǒng)一約定的事件就好,設(shè)置不用關(guān)注基礎(chǔ)模塊的監(jiān)聽方法甚至名字都不用關(guān)心。

在CI中的實(shí)現(xiàn)有兩個(gè)步驟:

1.在CI中聲明一個(gè)事件類,生成一個(gè)實(shí)例作為全局事件對(duì)象,綁定在控制器實(shí)力上。

2.使用CI的model作為模塊(為了實(shí)現(xiàn)更強(qiáng)的封裝可以把業(yè)務(wù)邏輯單獨(dú)寫成libraries中的類),初始化時(shí)給它綁定這個(gè)事件。同時(shí)獲取的模塊需要監(jiān)聽的事件,將這些事件綁定到全局事件對(duì)象。

以下是代碼,Event 類。

  1.  <?php 
  2. /** 
  3.  * @author rainer_H 
  4.  * @date 2012-6-25 
  5.  * @encode UTF-8 
  6.  */ 
  7. class Event { 
  8.     private $event_array = array(); 
  9.     public function __construct(){ 
  10.     } 
  11.     //$module_callback : array(module_name, callback_method) 
  12.     public function bind( $event_name$module_callback ){ 
  13.         if( !isset( $this -> event_array[$event_name] ) ){ 
  14.             $this -> event_array[$event_name] = array(); 
  15.         } 
  16.         array_push$this -> event_array[$event_name], $module_callback ); 
  17.     } 
  18.     public function multi_bind( &$bindings ){ 
  19.         foreach$bindings as $event_name => $module_callback ){ 
  20.             $this -> bind( $event_name$module_callback ); 
  21.         } 
  22.     } 
  23.    public function trigger( $event_name ){ 
  24.        if( isset( $this -> event_array[$event_name] )){ 
  25.           foreach$this -> event_array[$event_nameas $module_callback ){ 
  26.              $args = array_slice( func_get_args(), 1); 
  27.                 call_user_func_array(array(  $module_callback[0],$module_callback[1]), $args); 
  28.             } 
  29.         } 
  30.     } 
  31. ?> 

MY_Controller 的構(gòu)造函數(shù)實(shí)現(xiàn):

  1. public function __construct(){ 
  2.         parent::__construct(); 
  3.            //初始化事件中心 
  4.         $this -> load -> library("Event"); 
  5.         //初始化注冊(cè)模塊,這里寫你自己的。 
  6.         $modules = array('user','test'); 
  7.         //初始化事件中心模塊 
  8.         $auths = array(); 
  9.         foreach$modules as $module ){ 
  10.             //初始化各個(gè)模塊,將事件中心傳入以供模塊調(diào)用 
  11.             $model_name = "{$module}_model"
  12.             $this -> load -> model( $model_name$module ); 
  13.             $this -> $model_name -> event =  $this -> event; 
  14.             //以上這句優(yōu)雅一點(diǎn)可以寫成 
  15.             //$this -> $model_name -> set_handler($this -> event); 
  16.             //綁定事件 
  17.             $listen = $this -> $module -> listen(); 
  18.             foreach$listen as $event_name => $callback ){ 
  19.                $listen[$event_name] = array$this-> $module$callback ); 
  20.          } 
  21.           $this -> event -> multi_bind( $listen ); 
  22.      } 
  23.     } 

以上你注意到模塊需要有一個(gè)listen方法,來(lái)返回所有自己需要監(jiān)聽的事件。如果你不喜歡這種約定也可以在模塊獲得全局事件對(duì)象event后,自己在模塊內(nèi)通過(guò)event->bind()來(lái)實(shí)現(xiàn)綁定。

以下是listen返回的事件監(jiān)聽數(shù)組,也是事件格式:

  1. public function listen(){ 
  2.     return array( 
  3.         //事件名 => 觸發(fā)的函數(shù)名 
  4.         "user logged in" => "react_user_login" 
  5.     ); 

第二部分

對(duì)于事件的復(fù)合我采用了一個(gè)簡(jiǎn)單的鉤子模式,就是讓模塊約定聲明一個(gè)auth方法,返回自己要進(jìn)行權(quán)限控制的api和自己進(jìn)行控制的方法。示例如下:

  1. public function auth(){ 
  2.        return array( 
  3.            //api名稱 
  4.            'main/index' => array( 
  5.                //權(quán)限規(guī)則名稱 
  6.                'user_login' => array( 
  7.                    //對(duì)同一api需要忽略掉的規(guī)則 
  8.                    'ignore' => array( 'text_login' ), 
  9.                    //自己的驗(yàn)證函數(shù) 
  10.                    'validate' => 'login_validate' 
  11.                ) 
  12.            ) 
  13.        ); 
  14.    } 

由于一個(gè)api可能會(huì)有多個(gè)模塊聲明自己的驗(yàn)證規(guī)則,所以提供一個(gè)ignore字段來(lái)表示需要明確忽略掉的規(guī)則。在validate指向的函數(shù)值,函數(shù)自己通過(guò)post或這個(gè)get獲取參數(shù)并進(jìn)行驗(yàn)證。這里有點(diǎn)讓人感覺不舒服的地方就是上層的模塊需要知道基礎(chǔ)模塊的權(quán)限驗(yàn)證細(xì)節(jié),以便使用ignore來(lái)去掉和自己沖突的規(guī)則。好在這種情況應(yīng)該不會(huì)太多,大部分可以通過(guò)“將沖突的api拆成不同的api”來(lái)解決。而且這種方法可以使你在增加功能時(shí)完全不再修改之前的權(quán)限設(shè)置。

那么如何進(jìn)行合并?這里改造了一下MY_controller。代碼如下:

  1. class MY_Controller extends CI_Controller{ 
  2.    protected $auth_array = array(); 
  3.    public function __construct(){ 
  4.        parent::__construct(); 
  5.        //初始化事件中心 
  6.        $this -> load -> library("Event"); 
  7.        //初始化注冊(cè)模塊 
  8.        $modules = array('user','test'); 
  9.       //初始化事件中心模塊 
  10.        $auths = array(); 
  11.        foreach( $modules as $module ){ 
  12.            //初始化各個(gè)模塊,將事件中心傳入以供模塊調(diào)用 
  13.            $model_name = "{$module}_model"
  14.            $this -> load -> model( $model_name, $module ); 
  15.            $this -> $model_name -> event =  $this -> event
  16.              //綁定事件 
  17.            $listen = $this -> $module -> listen(); 
  18.            foreach( $listen as $event_name => $callback ){ 
  19.                $listen[$event_name] = array( $this-> $module, $callback ); 
  20.            } 
  21.            $this -> event -> multi_bind( $listen ); 
  22.          //獲取模塊的權(quán)限信息 
  23.            if( method_exists( $this -> $module , "auth") ){ 
  24.                $auths[$module] = $this -> $module -> auth() ; 
  25.            } 
  26.        } 
  27.                //得到整合后的權(quán)限數(shù)組 
  28.        $this -> auth_array = $this -> map_auth_array( $auths ); 
  29.    } 
  30.    private function map_auth_array( $auth_array ) { 
  31.        $output = array(); 
  32.        foreach( $auth_array as  $module_name => $auths_content ){         
  33.            foreach( $auths_content as $route => $auths ){ 
  34.               if( !isset( $output[$route] ) ){ 
  35.                    $output[$route] = array(); 
  36.                    $output[$route]['ignore'] = array(); 
  37.                }  
  38.                foreach( $auths as $auth_name => $auth ){ 
  39.                    $auths[$auth_name]['module'] = $module_name; 
  40.                    if( isset( $auth['ignore'] ) ){ 
  41.                        if( !is_array( $auth['ignore'])){ 
  42.                            $auth['ignore'] = array( $auth['ignore'] ); 
  43.                        } 
  44.                        $output[$route]['ignore'] = array_merge($output[$route]['ignore'],$auth['ignore']); 
  45.                        array_unique( $output[$route]['ignore'] ); 
  46.                    } 
  47.                }  
  48.                $output[$route] += $auths; 
  49.            } 
  50.        } 
  51.           foreach( $output as $route => $auths){ 
  52.            if( !empty( $auths['ignore'] ) ){ 
  53.                foreach( $auths['ignore'as $ignore ){ 
  54.                    unset( $output[$route][$ignore] ); 
  55.                } 
  56.            } 
  57.            unset( $output[$route]['ignore']); 
  58.        } 
  59.       return $output; 
  60.    } 
  61.    public function auth_validate(){ 
  62.        //獲取當(dāng)前路徑 
  63.        $route = 'main/index'
  64.        if( $this -> auth_array[$route] && !empty( $this -> auth_array[$route] ) ){ 
  65.            foreach( $this -> auth_array[$route] as $auth ){ 
  66.                $this -> $auth['module'] -> $auth['validate'](); 
  67.            } 
  68.        } 
  69.    } 

控制器將最后計(jì)算出來(lái)的權(quán)限驗(yàn)證數(shù)組放在了自己的auth_array屬性中,用戶在繼承了該控制器之后,通過(guò)$this -> auth_validate() 就能開始執(zhí)行驗(yàn)證。

如果你不喜歡這種控制器與權(quán)限合并的方式或者你的控制器很復(fù)雜時(shí),你也可以將權(quán)限單獨(dú)提出到一個(gè)類中。另外你可以再權(quán)限合并函數(shù)中記錄日志幫助調(diào)試。

另外貼出兩個(gè)具體的model:

  1. <?php 
  2. /** 
  3.  * @author rainer_H 
  4.  * @date 2012-6-26 
  5.  * @encode UTF-8 
  6.  */ 
  7. class User_model extends CI_Model{ 
  8.     //聲明自己的權(quán)限控制規(guī)則 
  9.     public function auth(){ 
  10.         return array
  11.             //api名稱 
  12.             'main/index' => array
  13.                 //權(quán)限規(guī)則名稱 
  14.                 'user_login' => array
  15.                     //對(duì)同一api需要忽略掉的規(guī)則 
  16.                     'ignore' => array'text_login' ), 
  17.                     //自己的驗(yàn)證函數(shù) 
  18.                     'validate' => 'login_validate' 
  19.                 ) 
  20.             ) 
  21.         ); 
  22.     } 
  23.    public function __construct(  ){ 
  24.         parent::__construct( ); 
  25.     } 
  26.      //聲明自己需要監(jiān)聽的對(duì)象 
  27.     public function listen(){ 
  28.         return array
  29.         ); 
  30.     } 
  31.     public function login_validate(){ 
  32.         echo "user login_validate"
  33.     } 
  34.    public function login(){ 
  35.         $this -> event -> trigger( "user logged in""hahaha" ); 
  36.     } 
  37. ?> 
  38. <?php 
  39. /** 
  40.  * @author rainer_H 
  41.  * @date 2012-6-26 
  42.  * @encode UTF-8 
  43.  */ 
  44. class Test_model extends CI_Model{ 
  45.     public function __construct(  ){ 
  46.         parent::__construct(  ); 
  47.     } 
  48.     public function auth(){ 
  49.         return array
  50.             'main/index' => array
  51.                 'text_login' => array
  52.                     'validate' => 'login_validate' 
  53.                 ) 
  54.             ) 
  55.         ); 
  56.     } 
  57.     public function listen(){ 
  58.         return array
  59.             "user logged in" => "react_user_login" 
  60.         ); 
  61.     } 
  62.     public function login_validate(){ 
  63.         echo "test login_validate"
  64.     } 
  65.      public function react_user_login( $user = false ){ 
  66.         echo "{$user} user logged in react from Test."
  67.     } 
  68. ?> 

原文鏈接:http://www.cnblogs.com/sskyy/archive/2012/06/27/2565294.html

 

【編輯推薦】

 

 

責(zé)任編輯:彭凡 來(lái)源: 博客園
相關(guān)推薦

2023-11-02 08:01:22

2024-06-28 10:19:02

委托事件C#

2023-03-16 15:18:16

2021-08-01 23:47:54

通用模型驅(qū)動(dòng)

2009-12-31 08:49:15

模型驅(qū)動(dòng)開發(fā)

2023-12-28 07:57:27

2013-03-26 14:17:21

架構(gòu)架構(gòu)設(shè)計(jì)事件驅(qū)動(dòng)

2009-07-02 09:56:24

導(dǎo)入事件驅(qū)動(dòng)技術(shù)JSP Servlet

2009-06-29 16:19:57

JSP Servlet

2021-07-27 08:01:22

CICD平臺(tái)

2009-10-20 14:58:15

Javascript事

2021-11-23 23:39:19

微服務(wù)開發(fā)架構(gòu)

2023-02-07 07:25:36

Spring事件驅(qū)動(dòng)

2012-08-24 09:02:36

IBMdW

2025-02-13 08:53:10

WinForm事件驅(qū)動(dòng)編程模型開發(fā)

2020-04-16 21:02:35

前端命名規(guī)范html規(guī)范

2019-04-19 21:06:23

事件驅(qū)動(dòng)架構(gòu)VANTIQ

2015-12-02 14:56:07

Docker開發(fā)模式持續(xù)集成

2023-08-31 08:21:42

KubernetesKADA驅(qū)動(dòng)

2009-06-25 14:05:08

Ajax JSF
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)