javascript设计模式2

Javascript设计模式之组合模式

  组合模式:运用该设计模式可以通过组合对象添加属性和方法,通过递归批量式的让叶子对象得到组合对象的属性和方法。打个比方我们现在要动态创建一个银行列表,按银行类型分为网上银行类,卡通银行类,并可配置他们是否显示。用组合模式如何实现呢?

  第一步还是先定义接口,因为要做到某类银行甚至某个银行是否显示可配置,那么我们先约定2个接口,showBank和hideBank。
+展开
-JavaScript
var IcardItem = new Interface(”icardItem”,[["showBank"],["hideBank"]]); 


  接下来先定义卡的组合对象,并设置组合对象的基本方法add,remove,getChild,由于这个类继承了IcardItem接口类,所以还定义了showBank,hideBank这两个接口方法。
+展开
-JavaScript
var cardMain = function(id){ 
      this.cards = []; 
      this.element = document.createElement("div"); 
      this.element.id = id; 
      Interface.regImplement(this,IcardItem); 
    }; 
    cardMain.prototype = { 
      add:function(card){ 
          this.cards.push(card); 
          this.element.appendChild(card.getElement()); 
      }, 
      remove:function(card){ 
        for(i=0;len=this.cards.length,i<len;i++){ 
          if(cards[i] == card){ 
            this.cards.splice(i,1); 
            break
          }    
          this.element.removeChild(card.getElement()); 
        }  
      }, 
      getChild:function(i){ 
          return this.cards[i]; 
      }, 
      getElement:function(){ 
          return this.element;  
      }, 
      showBank:function(){ 
         this.element.style.display ="block"
        for(i=0;len=this.cards.length,i<len;i++){ 
            this.cards[i].showBank(); 
        } 
      }, 
      hideBank:function(){ 
        this.element.style.display ="none"
        for(i=0;len=this.cards.length,i<len;i++){ 
            this.cards[i].hideBank(); 
        } 
      } 
    };


  然后定义叶子对象类bankLogo用以创建银行logo,这里银行logo都以带class的a标签标识:
+展开
-JavaScript
var bankLogo = function(bankClassName){ 
      this.element = document.createElement("a"); 
      this.element.className = bankClassName; 
      Interface.regImplement(this,IcardItem); 
    }; 
    bankLogo.prototype ={ 
      showBank:function(){ 
          this.element.style.display ="block"
      }, 
      hideBank:function(){ 
          this.element.style.display ="none";  
      }, 
      getElement:function(){ 
          return this.element;  
      } 
    };


  最后设置一个单体对象,将操作银行的相关信息形成一个模块,方便调用:
+展开
-JavaScript
var BankAction ={ 
        bankList:[], 
        addBank:function(card){ 
            this.bankList.push(card); 
        }, 
        innerBank:function(conId){ 
            for(i=0;len=this.bankList.length,i<len;i++){ 
                  var cardObj =this.bankList[i].getElement(); 
            } 
            document.getElementById(conId).appendChild(cardObj); 
        } 
    };


  到了实现环节了,实例化生成一个包含所有卡的最外层容器,然后根据卡类,分别生成一个放置银行卡和卡通卡的容器,最后生成各银行卡的实例,并按层级关系形成DOM结构:
+展开
-JavaScript
var bankDivT = new cardMain("PayCard");//创建最外层容器 
    var ebankCard = new cardMain("ebankCard");//创建网银类银行卡容器 
    var ktCard = new cardMain("ktCard");//创建卡通类银行卡容器 
    var ccbBank = new bankLogo('Ebank-CMB');//创建招行银行卡 
    var abcBank = new bankLogo('Ebank-ABC');//创建农行银行卡 
    var abcKtBank = new bankLogo('Kt-ABC');//创建卡通农行卡 
  
    ebankCard.add(ccbBank); 
    ebankCard.add(abcBank); 
    ktCard.add(abcKtBank); 
    bankDivT.add(ebankCard); 
    bankDivT.add(ktCard); 
    BankAction.addBank(bankDivT); 
    BankAction.innerBank("bankList");


  将动态生成的银行列表,DOM结构形如:
+展开
-HTML

<div id="PayCard"> 
      <div id="ebankCard"> 
       <a class="Ebank-CMB"></a> 
       <a class="Ebank-ABC"></a> 
      </div> 
      <div id="ktCard"> 
       <a class="Kt-ABC"></a> 
      </div> 
    </div>

  组合模式应用在动态生成用户界面的时候,是非常不错的选择,他可以很大程度的简化粘合性代码,提升维护性。不过还是要慎用,毕竟当叶子对象很多的时候,递归还是存在性能上的问题。



Javascript设计模式之装饰者模式


  装饰者模式:可以不创建新的子类,给对象创建新的功能。举例说明:支付宝收银台红包结合余额付款的应用场景。
+展开
-JavaScript
var Ieconomics = new Interface("ieconomics",[["getPrice"]]);


首先创建一个组件类,基与该组件实例化的对象,会被作为参数传递给装饰者类,以便装饰者调用到该组件中的各方法。
+展开
-JavaScript
  var economic = function(){ 
     Interface.regImplement(this,Ieconomics); 
   }; 
    economic.prototype={ 
        getPrice:function(){ 
          //代码实现 
        } 
    };


  然后创建一个装饰者抽象类,作为派生装饰者选件类的父类:  
+展开
-JavaScript
var economicsDecorator = function(economic){ 
      this.economic = economic; 
      this.regImplement(economic,Ieconomics); 
   }; 
    economicsDecorator.prototype={ 
        getPrice:function(){ 
          return this.economic.getPrice(); 
        } 
    };


  最后基于上面这个抽象类,派生出一个装饰者选件类:
+展开
-JavaScript
//红包装饰者选件类 
   var coupon = function(economic){ 
      //调用装饰着抽象类的构造函数 
      economicsDecorator.call(this,economic); 
   }; 
   extend(coupon,couponDecorator); 
   coupon.prototype=function(){ 
       //改写getPrice方法 
       getPrice:function(){ 
         return this.economic.getPrice() - this.getCoupon(); 
       }, 
       getCoupon:function(){ 
         //获取红包总价具体实现       
       } 
   };

var myCoupon = new economic(); 
    myCoupon = new coupon(myCoupon);


  实现装饰者模式就是这么简单,首先创建一个组件的实例myCoupon,然后将该对象作为参数传递给装饰者选件类coupon。你会发现两句代码中我都把值赋给了变量myCoupon,这是因为他们都实现了同一个接口类,他们之间是可以互换使用的。

  看到这里心细的同学可能会发现,我们在coupon类中新增了一个getCoupon方法,目前来看不会有任何问题,但是如果我们继续创建一个购物卷装饰者选件类,然后结合红包一起用呢?
+展开
-JavaScript
//购物卷装饰者选件类 
   var voucher = function(economic){ 
     economicsDecorator.call(this,economic); 
   }; 
   extend(voucher,couponDecorator); 
   voucher.prototype=function(){ 
       getPrice:function(){ 
         return this.getPrice() - this.getVoucher(); 
       }, 
       getVoucher:function(){ 
         //获取优惠卷总价具体实现       
       } 
   };

var myCoupon = new economic(); 
    myCoupon = new coupon(myCoupon); 
    myCoupon = new voucher(myCoupon);

  在这种场景下面getCoupon方法已经找不到了,这是因为voucher装饰myCoupon的时候,它的父类economicsDecorator不包含getCoupon方法,那自然是取不到的了,那该怎么办呢?

  分析一下装饰者抽象类economicsDecorator,我们传递了一个myCoupon的引用作为参数,我们可以通过这个参数做一些小动作,获得新增加的方法。
+展开
-JavaScript
var economicsDecorator = function(economic){ 
      this.economic = economic; 
      this.interface = Ieconomics; 
      for(var k in this.economic){ 
       if(typeof this.economic[key] !== "function"){ 
        continue
        var i; 
        for(i = 0;len = this.interface.methods.length,i < len; i++) { 
            //通过遍历比较在接口类中是否包含此方法,如果包含返回下一个 
            if(key == this.interface.methods[i][0]) {  
                break
            } 
        } 
        if(i < this.interface.methods.length) 
         continue
         var decorator = this
         //采用匿名函数调用方式来定义新方法 
         (function(methodName) { 
            decorator[methodName] = function() { 
                return decorator.economic[methodName](); 
            }; 
         })(key); 
        } 
       }  
      } 
      this.regImplement(economic,Ieconomics); 
   }; 
   economicsDecorator.prototype={ 
        getPrice:function(){ 
          return this.economic.getPrice(); 
        } 
    };


  看上面的代码,我们对装饰者抽象类做了一些修改,这样做是为了确保在装饰者选件类中一旦定义新方法,可以在装饰者抽象类中动态的定义出来。这里只是提供一个使用装饰者模式的思路,具体的实现代码远比这个复杂,由于项目还在开发中,demo暂不提供,支付宝新版收银台发布后,会跟大家再做个详细的设计分享。



Javascript设计模式之桥接模式

  桥接模式:将抽象和其实现分离开来,以便二者独立变化。其实很简单,只是在API和具体事件之间增加一个桥梁,从而降低API和使用他的类和对象之间的耦合。

  事实上对大多数同学来说桥接模式并不陌生,下面的this.getName就是一种桥接方法,他是外访问的一个接口,他的内部实现是通过访问内部私有变量来实现的,这个方法起到了外部和内部沟通的桥梁作用。
+展开
-JavaScript
var ioldfish = function(){ 
      var name = '老鱼'; 
      this.getName = function(){ 
        alert(name);  
      } 
    }


  桥接模式用的最多的还是在事件监听器回调函数。下面这个是获取用户信息的API接口函数:
+展开
-JavaScript
function getUserInfo(userid,callback){ 
          asyncRequest('GET','userInfo?userid='+userid,function(resp){ 
          callback(resp.responseText);                                                  
        }); 
    }


  接下去我们要做的是把这个API和某个事件的触发建立一个桥梁关系
+展开
-JavaScript
addEvent(element,'click',bridgeMethod); 
   function bridgeMethod(e){ 
        getUserInfo(this.userid,function(){ 
          //回调函数实现代码                                 
        }); 
   }


  这里在element对象click的时候触发函数并不是getIserInfo,而是新建了一个桥接方法bridgeMethod,通过这层桥接使得API接口函数和click事件相对独立,这样大大拓宽了API的适用范围。



Javascript设计模式之适配器模式

  适配器模式:打个比方,你维护了一个系统,之前一直都是用prototype框架,但是现在打算新引入YUI框架,那如何让两个框架平稳过度呢
,举个例子,如何将prototype中的$方法转换为YUI中的get方法:
+展开
-JavaScript
function $(){};

function YAHOO.util.Dom.get=function(el){};

function prototypeToYuiAdapter(){ 
      return YAHOO.util.Dom.get(arguments); 
    }


  你要在prototype中使用yui的get方法,只需要做以下申明即可:
+展开
-JavaScript
$ = prototypeToYuiAdapter;


  这样的话,在prototype中就可以使用YUI中的get方法了。本人并不是很推崇这种模式,所以不多做阐述,事实上我觉得不到万不得以,我们根本不需要使用这种模式,作为一名负责任的设计者,我宁可做代码重构也不希望使用该模式,只能作为无奈之下的过渡型方案使用。
Javascript设计模式之门面模式,观察者模式

  门面模式:这应该是所有脚本框架中都用到的,最基础的设计模式,随便找个框架中定义好的方法看看就行了,比如说YUI中的setStyle方法等等等等。在这里就不多阐述了。

  观察者模式:该设计模式应用在javascript上似乎更为牵强,不甚理解,这里就不说了,以免误人子第,如有心得者不吝赐教。
来源:http://hi.baidu.com/zhoumm1008/blog/item/6be8faa41ed0709c461064a2.html

加支付宝好友偷能量挖...


评论(0)网络
阅读(125)喜欢(1)JavaScript/Ajax开发技巧