程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> JSP編程 >> 關於JSP >> js自定義消息機制研究學習(三)——插件化我們js開發

js自定義消息機制研究學習(三)——插件化我們js開發

編輯:關於JSP

研究了一些基礎的自定義消息機制,對一些簡單的開發已經足夠。

 

現在我們來嘗試面對一些稍微復雜一些的架構設計。

 

首先,增加了一個插件模式:

 

plugs

var plugs=(function(){     function addPlugs(name,plug)     {             var __plugs=this.__plugs=this.__plugs || {};          if(name && plug)          {               __plugs[name]={                  installed:false,                  instance:plug                  };          }              }          function installPlugs()     {          var plugs=this.__plugs=this.__plugs || {};          for(var i in plugs)          {              var plug=plugs[i];              if(!plug.installed)              {                  plug.instance.install(this);                  plug.installed=true;              }          }     }          return {        ini:function(X)        {             X=monitor.ini(X);             if(X.live)             {                 var proto=X.prototype;                 proto.addPlugs=addPlugs;                 proto.installPlugs=installPlugs;             }             X.__plugs={};             X.addPlugs=addPlugs;             X.installPlugs=installPlugs;                         }     }})();

如果你看過前兩篇代碼,這段代碼是比較容易看懂的。它為傳入的對象(或函數)首先綁定了monitor模式,然後為對象增加了兩個方法:addPlugs,installPlugs

 

addPlugs 添加插件

 

installPlugs 安裝插件

 

添加插件很簡單,只是把實體裝到一個{}鍵值對中

 

安裝插件,就會調用每個插件對象的:install方法

 

 

 

 

 

 

為什麼要有插件模式呢?我們舉個例子來說明

 

虛構一個需求:

 

1. 在頁面上動畫展示龜兔賽跑

 

2.兔子和烏龜可以說話

 

3.展示他們比賽過程

 

這裡我沒什麼素材,只簡單展示一下這個程序設計

 

第一步,我們構造一個Animal函數,作為兔子、烏龜的類,代碼如下

 

Animal

    ///動物function Animal(config){    config=config || {};    var othis=this;    this.name=config["name"] || "Anonymous";    this.x=config["x"] || 0;    var toward=1;//右:1,左-1    var __timeout=0;    var __speed=5;    //說    this.say=function(str)    {        this.trigger({type:"say",msg:str});        return str;    }    //停    this.stop=function()    {        clearTimeout(__timeout);         this.trigger({type:"stop",x:this.x});        return this.x;    }    //跑動    this.run=function(speed)    {        __speed=speed || __speed;        this.x+=__speed*toward;        __timeout=setTimeout(function(){ othis.run();},100);        this.trigger({type:"run",x:this.x,toward:toward,speed:__speed});        return {x:this.x,toward:toward,speed:__speed};    }    //向左轉    this.turnLeft=function()    {        toward=-1;        this.trigger({type:"turn",toward:toward});        return toward;    }    //向右轉    this.turnRight=function()    {        toward=1;        this.trigger({type:"turn",toward:toward});        return toward;    }}

 

 

 

我們現在有一個動物的類(Animal),它有一些行為:說(say),停(stop),跑(run),左轉(turnLeft),右轉(turnRight) 

 

因為我在代碼裡使用了trigger的方法,我們先使用上一篇講到monitor,初始化一下:

 

monitor.ini(Animal);

 

 

 

 

第二步 我們先寫一個記錄的功能,用來記錄動物對象的言行,這裡只記錄say,stop,turn的消息,代碼如下:

 

View Code

///記錄器function Logger(){     this.dom=document.getElementById("log");}Logger.prototype={      log:function(str)      {          var time=new Date();          this.dom.innerHTML+="<br/>"+str+'<span style="color:gray">('+time.getHours()+":"+time.getMinutes()+":"+time.getSeconds()+")</span>";      },      handler:function(data,p){          switch(data.type)          {              case "say":                  this.log(p.name+"  說:"+data.msg);                  break;              case "stop":                  this.log('<span style="color:green">'+p.name+" 停在了"+data.x+'</span>');                  break;              case "turn":                  this.log(p.name+" 轉向了"+(data.toward==1?"右":"左"));                  break;          }            } }我們這裡用id=log的一個頁面元素(div)來顯示動物的言行

 

第三步,我們來創建兔子與烏龜這兩個對象:

 

var hare=new Animal({name:"兔子"});var tortoise=new Animal({name:"烏龜"});

 

 

 

 

第四步,我們將記錄器綁定到兩個對象上

 

如果你要綁定到所有動物對象上,你可以使用上一篇講到的live方法。在這裡為了說明為什麼要用插件,我們限定一下需求,假設live是不允許使用的,因為我們還要創建其他的一些動物,Logger是不需要記錄這些非主角的行為。那麼我們要編寫如下的代碼:

 

View Code

var log=new Logger(); hare.bind("say",log);hare.bind("stop",log);hare.bind("turn",log);tortoise.bind("say",log);tortoise.bind("stop",log);tortoise.bind("turn",log);

 

 

 

 

現在提出一個問題,你如果仔細看的話,我們發現在介於live和bind之間,比如有100個Animal對象,我們只要求記錄50個Animal的行為,那麼我們該有多郁悶,我們需要寫很多的bind,假如我們Animal不只這幾個行為,我們為它擴展了100個行為,都要做記錄,如果一行行的寫bind,該多恐怖

 

好吧,改進一下,你或許會建議要函數,例如這樣:

 

View Code

function bindLog(ani){      ani.bind("say",log);      ani.bind("stop",log);      ani.bind("turn",log);}bindLog(hare);bindLog(tortoise);如果只有一兩個這樣的需求,這樣也是不錯的。那麼再擴展呢?要寫很多個,比如十個,類似於Logger的類,他們要去綁定100個Animal一個,數個,或者全部(全部當然可以考慮live)

 

假設這個十個類,有些需要每一個Animal對象都綁定單獨的對象,比如我們寫一個類Display,它來代表顯示在屏幕上的動物,那麼一個動物對象就需要對應一個Display

 

很快我們就會發現,我們需要寫很多的類似於bindLog的方法。如bindDisplay,bindRun等等充斥在我們的主代碼中

 

那麼用開篇寫插件,我們會怎麼做?

 

首先把monitor.ini(Animal);修改為:plugs.ini(Animal)讓它支持插件模式,因為插件模式默認綁定了monitor,所以我們不需要再初始化一次monitor

 

 

 

 

然後我們在Logger的prototype中,添加方法install

 

 

 

 

 

 

View Code

install:function(main){            main.bind("say",this);            main.bind("stop",this);            main.bind("turn",this);}

 

 

 

 

我們的綁定代碼,修改成如下:

 

View Code

//添加安裝插件var log=new Logger(); hare.addPlugs("log",log);tortoise.addPlugs("log",log);hare.installPlugs();tortoise.installPlugs();我們把一系列的bind,修改成為先使用addPlugs,最後調用installPlugs來完成。

 

這樣做的優勢?

 

你的主代碼很清晰,完整如下:

 

View Code

var hare=new Animal({name:"兔子"});var tortoise=new Animal({name:"烏龜"});//記錄器var log=new Logger(); hare.addPlugs("log",log);tortoise.addPlugs("log",log);hare.installPlugs();tortoise.installPlugs();這樣,你很快就能看明白對象與對象之間的關系,也能從更高一點抽象層次上去組織你的對象,組織你的代碼,而不需要頭疼寫一堆一堆的bind了,如果你要換掉一個Logger,比如換成一個只記錄say的Logger 或者說你要把動物說的話以氣泡的形式顯示在他們的頭頂。

 

當我們有很多的組件拼裝時,這樣模式很給我們帶來很大的便利。

 

更重要的:

 

Animal 可以看做一個業務邏輯,我們很好的將它與顯示進行了分離,在測試中,我們可以很簡單的調用hare.run hare.say,而完全不用關心他們的顯示表現,這樣可以讓我們在更高的抽象層次構建我們的js程序。對於一些復雜的業務,既可以讓我們專注於業務,也可以讓我們彼此分工合作,各寫一塊。

 

 

 

 

 

 

 

PS:

 

也許有人要問,為什麼要addPlugs,然後再installPlugs,而不是一個addPlugs直接搞定。

 

在例子寫完以後我發現了這個問題,這是我的疏忽,慣性思維讓我沿用了我的實際使用的plugs。

 

其實我應用的plugs,還有一些擴展方法,如getPlug等等,在實際開發中插件的install方法後還會觸發trigger一個消息等等

 

這樣做的目的是,在installPlugs時,部分插件的安裝,是需要知道其他插件的存在

 

還有一個原因,是涉及懶加載的,在addPlugs時,有時我會addPlugs一個配置,或者一個簡稱,然後有他們實際指向的js文件此時並未加載

 

直到installPlugs時,它才會真正加載js並創建plug對象。所以我是在插件配置都准備好的情況下,才請求相應的js文件(比如直接請求一個服務器合並多個js後的壓縮文件)

 

希望不要給大家造成困擾。

 

我的建議是,如果你對這樣的編程方式感興趣,使用monitor,plugs(當然,他們也可以直接用來解決一些問題)之前最好根據自己的情況修改一下

 

 

完整代碼示例:下載

 

在完整代碼示例中,我增加了一個Display用於顯示動物,然後抱著玩的心態加了段簡單的故事腳本,博君一笑!

 

 

預告:

 

下一篇,是一篇關於消息機制的完結篇。會寫一些雜七雜八的東西。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved