javaScript設計模式探究【1】


    這段時間,有空沒空的看了一下博客園里一個博友-湯姆大叔的深入理解javascript系列,也挺有收獲的,因為面試的臨近,感覺自己唯一的優勢可能就是javascript這一塊了,所以就加強加強,去圖書館借了一本javascript設計模式,挺薄的一本書,放在書架上挺不顯眼的,書架上各種外表光鮮亮麗的javascript書,都看的凌亂了,只是看到設計模式那四個大字,所以就借了來,剛開始只是那么隨意的翻了那么一兩章,就令我有一種豁然開朗之感,遠比書架上那些看似很牛逼的書好的多,現在看書的口味也開始有點叼了,書怎么樣,翻一翻就能感受出來。后來一看是圖靈程序設計叢書,一時覺得外國人果然牛逼,那個翻譯也挺用功的,有些地方斟酌的很仔細,推薦一下《javascript設計模式》---Ross harmes  Dustin Diaz著

         現在也發現個問題,看的書如果不做一些筆記,過了一段時間,就沒什么印象了,倒是有點習慣這種一邊看書,然后一邊總結發博文,跟大家分享一下的做法了。其實要成為javascript大牛這條路挺崎嶇的,個人感覺比成為C++/Java這條路更困難,因為由於腳本語言的定位,本身讓它去實現非常復雜的邏輯功能就不太現實,即使有,也不是很容易能接觸到的,另外由於它的靈活性,所以掌控它就不顯得那么簡單了,總的來說需要經驗,還需要能夠給你一個平台。其他語言學起來難道不累嗎?也累吧,語言並不能代表什么,要更多的往深層次的東西思考,例如設計模式。當然像我這樣的菜鳥,要走的路還有很長很長,加油,一步步來唄。總有爬到高出的時候。

        

View Code
//1.javascript里最簡單,最常見的完成任務方式
function startAnimation(){
        ...
}
function stopAnimation(){
        ...    
}

//2.使用prototype

var Anim = function(){
        ...
};
Anim.prototype.start = function(){
        ...
}
Anim.prototype.stop = function(){
        ...    
}

//3.將類的定義封裝在一條聲明中
var Anim = function(){
    ...    
}
Anim.prototype = {
    start: fucntion(){
        ...    
    }    ,
    stop: function(){
        ...    
    }
};

//4.使用Function.prototype.method用於為類添加新方法
Function.prototype.method = function(name,fn){
    this.prototype[name] = fn ;
};
var Anim = function(){
    ...
};
Anim.method('starrt',function(){
    ...    
});
Anim.method('stop', function(){
    ...
});

//5.鏈式調用
Function.prototype.method = function(name,fn){
    this.prototype[name] = fn ;
    return this;
};
var Anim = function(){
    ...
};
Anim.method('starrt',function(){
    ...    
}).
method('stop', function(){
    ...
});

   不知道大家看完上面的5例代碼有什么感受,反正我覺得挺驚艷的,可能語法什么的我都學過,但是從沒有想過可以這么用。尤其是第五種,記得不錯的話,JQuery應該大量的用到了這種鏈式調用的方式。

        1 接口

       在javascript中模仿接口的三種方法:注釋法,屬性檢查法和鴨式辨型法

        1.1 注釋法--用注釋法最簡單,但是效果最差,只是增加了一段注釋而已,對性能沒有影響,但是沒有錯誤檢查。

View Code
/*
interface Composite{
    function add(child);
    function remove(child);
    functiongetChild(index);
}
interface FormItem{
    function save();
}
*/
var CompositeForm = function(id, method,action){//iimplements Composite, FormItem
    ...
};
//Implement the Composite interface
CompositeForm.prototype.add = function(child){
    ...    
};
CompositeForm.prototype.remove = function(child){
    ...
};
CompositeForm.prototype.getChild = function(index){
    ...
};
//Implement the FormItem interface
COmpositeForm.prototype.save = function(){
    ...
};

   1.2 屬性檢查模仿接口--所有類都明確地聲明自己實現了哪些接口,任何一個要求其啊承諾書屬於特定類型的函數都可以對這個屬性進行檢查,並在所需接口未在聲明之列時拋出一個錯誤,但是這種方法並未確保類真正實現了自稱實現的接口。需要一些額外工作,對性能略有影響。

View Code
/*
interface Composite{
    function add(child);
    function remove(child);
    functiongetChild(index);
}
interface FormItem{
    function save();
}
*/
var CompositeForm = function(id,method,action){
    this.implementsInterfaces = ['Composite', 'FormItem'];
    ...    
};

function addForm(formInstance){
    if(!implements(formInstance,'Composite','FormItem')){
        throw new Error("Object does not implements a required interface:");
    }    
}
//The implememts function, which checks to see if an object declares that it
//implements the required interfaces.
function implements(object){
    for(var i = 1; i<arguments.length;i++){
        var interfaceName = arguments[i];
        var interfaceFound = false;
        for(var j =0;j<object.implementsInterfaces.length;j++){
            if(object.implementsInterfaces[j] == interfaceName){
                interfaceFound = true;
                break;
            }    
        }
        if(!interfaceFound){
            return false;
        }
    }    
    return true;
}

   1.3 鴨式辨型模仿接口--類是否聲明自己支持哪些接口並不重要,只要它具有這些接口中的方法就行。定義:如果對象具有與接口定義的方法同名的所有方法,那么就可以認定它實現了這個接口。

View Code
//Interfaces
var Composite = new Interface('Composite',['add','remove','getChild']);
var FormItem = new interface('FormItem',['save']);

//CompositeForm class
var CompositeForm = function(id, method, action){
    ...    
};

function addForm(formInstance){
    ensureImplements(formInstance, Composite, FormItem);    
}

//ensureImplements函數至少需要兩個參數,第一個參數是想要檢查的對象,其余參數是據以對那個對象進行檢查的接口。

      1.4 具體實現方法---綜合第一種和第三種,用注釋聲明類支持的接口,提高代碼的可重用性及文檔的完整性。我們還用輔助類Interface及其類方法Interface.ensureImplements來對對象實現的方法進行顯式檢查。

View Code
//Interfaces
var Composite = new Interface('Composite',['add','remove','getChild']);
var FormItem = new interface('FormItem',['save']);

//CompositeForm class
var CompositeForm = function(id, method, action){
    ...    
};

function addForm(formInstance){
    ensureImplements(formInstance, Composite, FormItem);    
}

var interface = function(name,methods){
    if(Arguments.length != 2){
        throw new Error("Interface constructor called with:"+Arguments.length+"arguments, but expected exactly 2.");
    }
    this.name = name;
    this.methods = [];
    for(var i =0,len = methods.length;i<len;i++){
        if(typeof methods[i] != 'string'){
                throw new Error("Interface constructor expects method names to be passed in as a string.");
        }    
        this.methods.push(methods[i]);
    }
};
interface.ensureImplements = function(Object){
    if(Arguments.length<2){
        throw new Error("Function Interface.ensureImplements called with"+Arguments.length+"arguments,but expected at least 2.");    
    }    
    for(var i =1,len = Arguments.length;i<len;i++){
        var interface = Arguments[i];
        if(interface.constructor != Interface){
            throw new Error("Function interface.ensureImplements expects arguments two and above to be instances of Interface.");    
        }    
        for(var j = 0,methodsLen = interface.methods.length;j<methodsLen;j++){
            var method = interface.methods[j];
            if(!Object[method]||typeof Object[method]!=='function'){
                throw new Error("Function Interface.ensureImplements:object does not implement the"+interface.name+"inerface.Method"+method+
                "was not found.");    
            }    
        }
    }
};

  1.5 總結是否需要使用接口

        仁者見仁智者見智,對於一些小型的,不太費事的項目,就沒必要使用了。具體實現的時候,還可以簡化。使用公共的Interface.js文件,剔除所有針對構造器的顯式檢查,以Interface.ensureImplements取代原來的構造器檢查。

     2 封裝和信息隱藏

      javascript中創建對象的基本模式有3種。門戶大開型,使用下划線來表示私有方法和屬性,使用閉包來創建真正的私有成員。

  2.1 門戶大開型---所有的屬性和方法都是公開的,可訪問的(就不舉例了)

       2.2 用命名規范區別私有成員---本質上來說這種模式與門戶大開型對象創建模式如出一轍,只不過在一些方法和屬性的名稱前加上了下划線以示其私用性而已。

       //this._menber = member;

     //_method = function(){}               但是這樣外部其實還是可以訪問的。

     2.3 作用域、嵌套函數和閉包

     在javascript中只有函數具有作用域。閉包的好處就是可以實現在函數外部調用內部的變量。返回一個內嵌函數是創建閉包的最常用的手段。

View Code
function foo(){
    var a = 10;
    function bar(){
        a * = 2;
        return a;
    }
    return bar;    
}
var baz = foo();      
baz(); //return 20
baz(); //return 40
baz(); //return 80

var blat = foo();
blat();          //return 20   because a new copy of a is being used

     上面這段代碼其實涉及到共享變量的問題,var baz = foo() 聲明一個函數bar的引用。使用baz的時候共享變量a,具體的可以看深入理解JavaScript系列(10):JavaScript核心(晉級高手必讀篇)里面有涉及到,講的挺詳細的。

     2.4 總結封裝利弊:

           封裝保護了內部數據的完整性,通過將數據的訪問途徑限制為取值器和賦值器這兩個方法可以獲得對取值和賦值的完全控制,可以減少其它函數所需的錯誤檢查代碼的數量。 對   象重構因此變得輕松。通過只公開在那些接口中規定的方法,可以弱化模塊間的耦合。

           封裝導致了復雜的作用域鏈。學習起來挺困難的,新手容易迷糊。

      3 繼承--在javascript中繼承是非常復雜的,比其他任何面向對象語言中的繼承都要復雜...下次再總結吧,我感覺就繼承,我能寫一篇博文了。沒事的話,明天繼續

       以上全部都屬個人原創,請大家轉載的時候附上原創鏈接: http://www.cnblogs.com/tonylp


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM