JavaScript設計模式學習筆記


layout: default
title: "JavaScript設計模式學習筆記"
date: 2015-12-04 14:29:29 +0800
categories: design partern
---javascript

JavaScript設計模式學習筆記

1、富有表現力的javascript

  • 函數運行在定義它的做用域中,而不是調用它的做用域中,利用這一點和閉包聯合使用,就能把變量保存在匿名函數中加以保護。java

    2、接口

  1. 模仿接口
  • 用註釋模仿接口
  • 用屬性檢查模仿接口
  • 用鴨式辨型模仿接口
// 檢查接口存在與否
// @param {string} name    接口名稱
// @param {Array} methods 接口方法
function Interface(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; i < methods.length; 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]);
    }
}
 // 檢查接口存在與否
 // @param  {[type]} object 實例對象
 // @param  {[type]} object 接口名稱
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; i < arguments.length; 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; j < interface.methods.length; j++) {
            var method = interface.methods[j];

            if(!object[method] || typeof object[method] !== 'function') {
                throw new Error('Function Interface.ensureImplements: object' + 'does not inplement tht' + interface.name + 'interface.method' + method + ' was not found');
            }
        }
    }
};

3、封裝和信息隱藏

  1. 建立對象的基本模式
  • 門戶大開型對象
function Book(isbn,title,author){}
Book.prototype.method = function() {};
  • 使用命名規範區別公私有成員
  • 在私有屬性和方法名前面加上 _ 線,代表私有特色。
  • 做用域,嵌套函數,閉包
    返回一個內嵌函數,是建立閉包的經常使用手段編程

    4、繼承

  • 採用原型繼承時,須要注意對子類型的讀寫可能不一致,任何對子類型的修改可能都反映到父類上。
  • 原型繼承更能節約內存。
  • 繼承與封裝:
    子類的實例方法都不能經過繼承的特權方法去訪問父類的私有變量。
  • 摻元類
    若是不想繼承父元素的所有方法(重複代碼),而只是想重用其中的某些方法。能夠用摻元類:先建立一個具備各類通用方法的類,在利用它去擴充其餘的類。(適用於類與類之間差異較大時使用,不然使用類式繼承和原型繼承更爲恰當。)
function Mixin() {};
Mixin.prototype = {
    method1:function(){},
    method2:function(){},
    ....
}

function Myclass(){};
augument(Myclass,Mixin,'method2'); //繼承Mixin的Method2方法
new Myclass().method2()   // 調用Method2方法

// 繼承其餘類的方法
function augment(recivingClass, givingClass, methodName) {
    if(arguments[2]){
        for (var i = 2; i < arguments.length; i++) {
            recivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
        };
    }else {
        for(methodName in givingClass.prototype) {
            if(!recivingClass.prototype[methodName]) {
                recivingClass.prototype[methodName] = givingClass.prototype[methodName];
            }
        }
    }
}

5、單體模式

  • 單體模式能夠用來劃分命名空間,以減小網頁中的全局變量,把代碼組織的更爲一致,從而使其更容易閱讀和維護。
    單體用來劃分命名空間並將一批相關方法和屬性組織在一塊兒的對象。
  • 擁有私有成員的單體
var MyNameSpace = {};
MyNameSpace.Singleton = (function(){
    // pravite members.
    var ... //私有變量必須用var 聲明
    // public members.
    return {
        publicAttribute: xxx,
        publicMethod: function(){}
    }
})();
  • 惰性實例單體(lazy loading,須要時在加載)
var MyNameSpace = {};
MyNameSpace.Singleton = (function(){
    var uniqueInstance; //代表單體是否已經被實例化過
    function constructor(){
        // pravite members.
        var praviteAttribute; //私有變量必須用var 聲明
        // public members.
        return {
            publicAttribute: xxx,
            publicMethod: function(){}
        }
    }
return {
    getInstance:function() {
        if(!uniqueInstance){
            uniqueInstance = constructor();
        }
        return uniqueInstance;
    }
}
})();
// 調用方法改成:MyNameSpace.Singleton.getInstance().publicMethod()

6、工廠模式

  1. 簡單工廠模式把成員對象的建立工做轉交給一個外部對象,該外部對象能夠是一個簡單的命名空間,也能夠是一個實例。
  2. 真正的工廠模式是將其成員對象的實例化推遲到子類中進行的類
  3. 工廠模式的主要好處在於消除對象之間的耦合,經過使用工廠模式,能夠把全部實例化代碼集中在一個位置。設計模式

    7、橋接模式

  4. 橋接模式的做用在於將抽象和其實現隔離開來,以便兩者獨立變化
  5. 橋接模式能夠用來鏈接公開的API代碼和私有的代碼(特權函數)。
  6. 讓接口可橋接,抽象函數功能。瀏覽器

    8、門面模式

  • 簡化類的接口,如經常使用的setCss函數,event處理函數,把瀏覽器差別封裝起來,提供便利的接口,提升編程效率。閉包

    9、適配器模式

  • 用於不一樣接口之間的轉換,銜接。函數

    10、亨元模式

  • 用於解決因建立大量對象而累及內存性能的問題的優化模式。
  • 把每一個對象的數據轉化成外部數據,將其做爲參數提供給各個方法。
  • 使用方法:
  1. 儘量的刪除該類的屬性(每一個實例都不一樣的屬性),這些參數應該由管理器添加到該類的各個方法
  2. 建立一個用來控制該類的實例化工廠。例如一個對象來保存每個這類對象的引用,並以用生成這些對象的參數的惟一組合來做爲他們的索引。
  3. 建立一個用來保存外在數據的管理器。
  • 使用條件:
  1. 網頁中有大量資源密集型對象。
  2. 該對象中所保存的數據中至少有一部分能夠被轉化成外在函數分離出來。
  3. 將數據分離出去以後,獨一無二的對象的數目較少。
  • 若是說實例對象在頁面不止一處被使用,能夠建立函數檢查實例的使用狀態,把未使用的對象拿來使用,避免建立多個重複實例。性能

    10、代理模式

  • 虛擬代理模式用於控制那種建立開銷很大的本體的訪問,它會把本體的實例化推遲到有方法被調用的時候。
  • 建立虛擬代理模式的通用方法:
// 虛擬代理
function DynamicProxy() {
    this.args = arguments;
    this.initialized = false;
    var that = this;
    // 觸發初始化 
    addEvent(parent, type, that._initialize);
}
DynamicProxy.prototype = {
    // 初始化(本體實例化)
    _initialize: function() {
        this.parent = new Parent(this.args);
        var that = this;
        this.interval = setInterval(function(){that._checkInitialization();},100);
    },
    // 檢查初始化
    _checkInitialization:function() {
        if (this.parent.parentMethod !== null) {
            clearInterval(this.interval);
            this.initialized = true;
        }
    },
    // 若是初始化完成,調用本體方法
    method: function(args) {
        if(!this.initialized) {
            return;
        }
        return this.parent.method(args);
    }
};
相關文章
相關標籤/搜索