成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

javascript中的設(shè)計(jì)模式(二)

whidy / 665人閱讀

摘要:在類似于這樣的面向?qū)ο笳Z(yǔ)言中,抽象類的使用在這個(gè)設(shè)計(jì)模式中非常重要。假設(shè)系統(tǒng)中存在大量類似的對(duì)象而導(dǎo)致內(nèi)存消耗過(guò)高,享元模式就非常有用了。享元模式包含兩種狀態(tài)即屬性內(nèi)部狀態(tài)存儲(chǔ)于對(duì)象內(nèi)部。不過(guò)與享元模式不同的是它不會(huì)區(qū)分內(nèi)部狀態(tài)和外部狀態(tài)。

模式8-模版方法模式

模版方法模式是一種基于繼承的設(shè)計(jì)模式。主要由兩部分構(gòu)成:

抽象父類:包含子類的算法框架和一些通用的具體方法;

具體實(shí)現(xiàn)的子類: 包含對(duì)于父類中抽象方法的實(shí)現(xiàn),繼承父類的整個(gè)算法實(shí)現(xiàn)方法,并且可以重寫父類中的方法。

在類似于java這樣的面向?qū)ο笳Z(yǔ)言中,抽象類的使用在這個(gè)設(shè)計(jì)模式中非常重要。因?yàn)樵诰幾g的時(shí)候會(huì)對(duì)繼承抽象類的子類進(jìn)行檢測(cè),要求必須要對(duì)抽象方法進(jìn)行實(shí)現(xiàn)。然而在javascript中沒(méi)有類型檢查,所以要保證子類實(shí)現(xiàn)了所有抽象父類的抽象方法,可以在運(yùn)行時(shí)進(jìn)行檢測(cè),即讓抽象方法拋出錯(cuò)誤。

示例:

var Beverage = function() {}
Beverage.prototype.boilWater = function(){
    console.log("boil water");
}
Beverage.prototype.brew = function (){
    throw new Error("you must define function brew");
}
Beverage.prototype.pourInCup = function (){
    throw new Error("you must define function pourInCup");
}
Beverage.prototype.addCondiments = function (){
    throw new Error("you must define function addCondiments");
}
Beverage.prototype.customerWantsCondiments = function(){
    throw new Error("you must define function customerWantsCondiments");
}

//泡飲料的順序和步驟是定的,算是一個(gè)子類通用的算法
Beverage.prototype.init = function(){ 
    this.boilWater();
    this.brew();
    this.pourInCup(); 
    if(this.customerWantsCondiments){
        this.addCondiments();
    }
};

var Tea = function(){};               
Tea.prototype = new Beverage();        
Tea.prototype.brew = function(){       
    console.log("brew-up");            
}                                     
Tea.prototype.pourInCup = function(){
    console.log("pour tea");   
}
Tea.prototype.addCondiments = function(){
    console.log("add sugar and milk");
}
Tea.prototype.customerWantsCondiments = function() {
    return window.confirm("Do you need condiments?");
}

var tea = new Tea();
tea.init();

var Coffee = function(){};               
Coffee.prototype = new Beverage();        
Coffee.prototype.brew = function(){       
    console.log("brew coffee");            
}                                     
Coffee.prototype.pourInCup = function(){
    console.log("pour coffee");   
}
Coffee.prototype.addCondiments = function(){
    console.log("add lemon");
}
Coffee.prototype.customerWantsCondiments = function() {
    return window.confirm("Do you need condiments?");
}

var coffee = new Coffee();
coffee.init();

這個(gè)設(shè)計(jì)模式是有利于系統(tǒng)的拓展的,并且符合開放-封閉原則。另外,我們?cè)趈s中不一定非要使用繼承的方式來(lái)完成這個(gè)設(shè)計(jì)模式,也可以通過(guò)傳入高階函數(shù)作為參數(shù)來(lái)實(shí)現(xiàn),用以替代父類中的抽象函數(shù)。

模式9-享元模式

享元模式是為了優(yōu)化性能而存在的。假設(shè)系統(tǒng)中存在大量類似的對(duì)象而導(dǎo)致內(nèi)存消耗過(guò)高,享元模式就非常有用了。
享元模式包含兩種狀態(tài)(即屬性):

內(nèi)部狀態(tài):

-存儲(chǔ)于對(duì)象內(nèi)部。
-可以被一些對(duì)象共享。
-獨(dú)立于具體的場(chǎng)景,通常不會(huì)改變。

外部狀態(tài):

取決于具體的場(chǎng)景,并根據(jù)場(chǎng)景而變化,外部狀態(tài)不能被共享。

剝離了外部狀態(tài)的對(duì)象成為共享對(duì)象,外部狀態(tài)在必要時(shí)被傳入共享對(duì)象來(lái)組裝成一個(gè)完整的對(duì)象。系統(tǒng)中可能存在的最大享元對(duì)象個(gè)數(shù)等于不同內(nèi)部狀態(tài)的組合數(shù)。

示例:

//這個(gè)享元只有一個(gè)內(nèi)部狀態(tài)
var Model = function( sex ){ 
    this.sex = sex;
};
Model.prototype.takePhoto = function(){
    console.log( "sex= " + this.sex + " underwear=" + this.underwear);
};

//分別創(chuàng)建一個(gè)男模特對(duì)象和一個(gè)女模特對(duì)象:
var maleModel = new Model( "male" ), 
femaleModel = new Model( "female" );

//給男模特依次穿上所有的男裝,并進(jìn)行拍照:
//注:這里我們是在需要的時(shí)候才傳入外部狀態(tài)
for ( var i = 1; i <= 50; i++ ){ 
    maleModel.underwear = "underwear" + i; 
    maleModel.takePhoto();
};

//同樣,給女模特依次穿上所有的女裝,并進(jìn)行拍照:
for ( var j = 1; j <= 50; j++ ){ 
    femaleModel.underwear = "underwear" + j; 
    femaleModel.takePhoto();
};

應(yīng)用:
文件上傳,只根據(jù)上傳組件的不同來(lái)(使用工廠)新建uploader對(duì)象(只含有一個(gè)uploadType內(nèi)部狀態(tài),同樣uploadType的被共享),而文件信息等儲(chǔ)存在外部,只當(dāng)需要(如刪除文件)時(shí)才(通過(guò)uploadManager)將外部狀態(tài)傳入內(nèi)部。

對(duì)象池是另一種性能優(yōu)化的方案,其思想是創(chuàng)建一個(gè)池子用來(lái)存放空閑對(duì)象,當(dāng)需要使用該對(duì)象時(shí)從池子中取,如果沒(méi)有則創(chuàng)建,用完之后放回。不過(guò)與享元模式不同的是它不會(huì)區(qū)分內(nèi)部狀態(tài)和外部狀態(tài)。

模式10-職責(zé)鏈模式

思想是將可能處理請(qǐng)求的對(duì)象連成一個(gè)鏈,請(qǐng)求者只需知道第一個(gè)對(duì)象,然后將請(qǐng)求沿著鏈依次傳遞直到遇到可以處理該請(qǐng)求的對(duì)象。這就使得請(qǐng)求發(fā)出著和請(qǐng)求接受者之間解耦,也就是說(shuō)請(qǐng)求發(fā)出者不必知道哪個(gè)對(duì)象可以處理請(qǐng)求,避免了在一個(gè)函數(shù)中使用大量的if else判斷。

示例:

var handler1 = function(params){
    if(params === true) {   // check condition
        console.log("request solved by handler1");
    } else {
        return false;      // condition not valid
    }
}

var handler2 = function(params){
    if(params === true) {   // check condition
        console.log("request solved by handler2");
    } else {
        return false;      // condition not valid
    }
}

var handler3 = function(params){
    if(params === true) {   // check condition
        console.log("request solved by handler3");
    } else {
        return false;      // condition not valid
    }
}

var Chain = function( fn ){ 
    this.fn = fn;
    this.successor = null; 
};
Chain.prototype.setNextSuccessor = function( successor ){ 
    return this.successor = successor;
};
Chain.prototype.passRequest = function(){
    var ret = this.fn.apply( this, arguments );
    if ( ret === false ){
        return this.successor && this.successor.passRequest.apply( this.successor, arguments );
    }
    return ret; 
};

//調(diào)用next函數(shù)可以手動(dòng)傳遞請(qǐng)求,用于異步處理
Chain.prototype.next= function(){
    return this.successor && this.successor.passRequest.apply( this.successor, arguments );
};


var chain1 = new Chain(handler1);
var chain2 = new Chain(handler2);
var chain3 = new Chain(handler3);

//指定節(jié)點(diǎn)在職責(zé)鏈中的順序
chain1.setNextSuccessor(chain2); 
chain2.setNextSuccessor(chain3);

//把請(qǐng)求傳遞給第一個(gè)節(jié)點(diǎn):
chain1.passRequest(someParams); 

職責(zé)鏈模式使得各個(gè)鏈結(jié)點(diǎn)之間可以拆分重組,便于插入或刪除結(jié)點(diǎn)。并且請(qǐng)求不一定要從第一個(gè)結(jié)點(diǎn)開始。同時(shí),要避免職責(zé)鏈過(guò)長(zhǎng)帶來(lái)的性能問(wèn)題。
另外,可以利用js的函數(shù)式特性將函數(shù)“鏈接”起來(lái)實(shí)現(xiàn)職責(zé)鏈模式,即為Function對(duì)象的原型添加after函數(shù)。

應(yīng)用:
不同瀏覽器文件上傳控件的選擇,DOM事件冒泡等。

模式11-中介者模式

中介者模式是為了解除對(duì)象之間的強(qiáng)耦合關(guān)系,所有對(duì)象都通過(guò)中介者通信而不再相互引用。

示例:
假設(shè)一個(gè)網(wǎng)頁(yè)中幾個(gè)DOM元素的值共同決定一個(gè)按鈕的有效性,
例如input必須有效,select1和select2必須選擇

傳統(tǒng)的方法中,我們需要為這三個(gè)DOM元素添加值改變監(jiān)聽函數(shù),并且在每個(gè)監(jiān)聽函數(shù)中都要堅(jiān)持另外兩個(gè)DOM的值。這時(shí),如果我們需要加入一個(gè)input2,就需要將所有其他DOM元素的監(jiān)聽函數(shù)進(jìn)行修改。
如果使用中介者模式,我們可以創(chuàng)建一個(gè)mediator對(duì)象,并且提供一個(gè)向其發(fā)送消息的借口。然后,我們?yōu)槠渌鸇OM創(chuàng)建的監(jiān)聽函數(shù)中只需要向中介者發(fā)送一個(gè)消息并且把this作為參數(shù)傳遞告訴中介者是誰(shuí)發(fā)的消息。而中介者的實(shí)現(xiàn)中,只需要對(duì)收到的不同消息進(jìn)行處理即可,如果需要添加新的關(guān)聯(lián)DOM,也只需要稍稍修改mediator的代碼而不會(huì)需要修改其他DOM的監(jiān)聽函數(shù)了。

總之,中介者模式使對(duì)象之間的網(wǎng)狀引用關(guān)系變成了一對(duì)多的關(guān)系,滿足一個(gè)對(duì)象盡可能少地了解其他對(duì)象的原則。但是該模式引入了中介者對(duì)象,也會(huì)造成一些內(nèi)存消耗。

模式12-裝飾者模式

裝飾者模式用于動(dòng)態(tài)地給對(duì)象增加職責(zé)。

為了保證在執(zhí)行原函數(shù)和this指向發(fā)生改變,我們需要引入代理函數(shù)。代理函數(shù)的功能是在原函數(shù)執(zhí)行之前或之后,執(zhí)行另外的函數(shù)。

示例:

使用AOP,改變Function對(duì)象的原型

Function.prototype.before = function(beforefn){
    var _self = this;
    return function(){
        beforefn.apply(this, arguments);  //確保this指向不變
        this.apply(this, arguments);
    }
}

var func1 = function(){
    alert("1");
}

func1 = func1.before(function(){
    alert("0");
});

func1();  //先輸出0再輸出1

不改變?cè)偷淖龇ǎ?/p>

var before = function(fn, beforefn){
    return function() {
        beforefn.apply(this, arguments);
        fn.apply(this, arguments);
    }
}

func1 = before(func1, function(){alert("0")});

應(yīng)用:
對(duì)于某些用戶操作(如單擊按鈕)數(shù)據(jù)統(tǒng)計(jì)上報(bào),改變函數(shù)的arguments對(duì)象(如ajax傳數(shù)據(jù)時(shí)添加屬性),表單驗(yàn)證和提交功能的分離等。

這個(gè)設(shè)計(jì)模式使得開發(fā)人員在開發(fā)框架時(shí)可以只考慮對(duì)象的穩(wěn)定和基礎(chǔ)功能,其他需要添加的個(gè)性功能可以被動(dòng)態(tài)添加。它不同于代理模式的是,代理模式的目的是為了控制對(duì)對(duì)象的訪問(wèn)或添加一些功能,而裝飾者模式則是為了為對(duì)象動(dòng)態(tài)添加功能,并且通常會(huì)形成一條長(zhǎng)長(zhǎng)的裝飾鏈。

值得注意的是,裝飾者模式返回的是一個(gè)新的函數(shù),因此原函數(shù)上的屬性會(huì)消失。同時(shí),裝飾鏈也疊加了函數(shù)的作用域,過(guò)長(zhǎng)則會(huì)對(duì)性能產(chǎn)生影響。

模式13-狀態(tài)模式

狀態(tài)模式使得一個(gè)對(duì)象在其狀態(tài)改變時(shí)改變其行為。也就是說(shuō),在不同狀態(tài)下調(diào)用同一個(gè)名字的函數(shù)其函數(shù)功能是不同的。
在狀態(tài)模式中,一般有兩類對(duì)象:context和狀態(tài)類。context構(gòu)造函數(shù)中應(yīng)該實(shí)例化所有的狀態(tài)類并作為context的屬性,以便context調(diào)用狀態(tài)類中的方法。而狀態(tài)類的構(gòu)造函數(shù)應(yīng)該以context作為參數(shù),以便可以調(diào)用context中改變其state值的接口來(lái)對(duì)其進(jìn)行賦值。

例如一個(gè)擁有不同光強(qiáng)度的燈的控制代碼示例:

var Light = function(){
    this.offLightState = new OffLightState( this );  // 持有狀態(tài)對(duì)象的引用 
    this.weakLightState = new WeakLightState( this );
    this.strongLightState = new StrongLightState( this ); 
    this.superStrongLightState = new SuperStrongLightState( this ); 
    this.button = null;
};

Light.prototype.init = function(){
    var button = document.createElement( "button" ),
    self = this;
    this.button = document.body.appendChild( button ); 
    this.button.innerHTML = "開關(guān)";
    this.currState = this.offLightState;
    this.button.onclick = function(){ 
        self.currState.buttonWasPressed();
    } };

//接下來(lái)就要定義各種狀態(tài)類
var OffLightState = function( light ){ 
    this.light = light;
};
OffLightState.prototype.buttonWasPressed = function(){ 
    console.log( "弱光" );
    this.light.setState( this.light.weakLightState );
};

// 其他狀態(tài)類似,都需要定義一個(gè)buttonWasPressed方法,略

該設(shè)計(jì)模式優(yōu)點(diǎn)是將對(duì)象的狀態(tài)跟對(duì)應(yīng)的方法一起封裝在一個(gè)類里,使得狀態(tài)的管理如添加刪除等更easy。狀態(tài)模式與策略模式很相似,都是有context和一些策略/狀態(tài)類。不同點(diǎn)是策略類之間是平行的,用戶需要知道他們的不同來(lái)選擇調(diào)用,而狀態(tài)類之間的狀態(tài)轉(zhuǎn)換關(guān)系是早就規(guī)定好的,用戶也不必知道其內(nèi)部不同點(diǎn)。

JavaScript版本的狀態(tài)機(jī)(在js中狀態(tài)類不一定需要通過(guò)類來(lái)創(chuàng)建,可以使用顯式的對(duì)象):

var Light = function(){
    this.currState = FSM.off;   // 設(shè)置當(dāng)前狀態(tài) 
    this.button = null;
};

Light.prototype.init = function(){
    var button = document.createElement( "button" ),
    self = this;
    button.innerHTML = "已關(guān)燈";
    this.button = document.body.appendChild( button );
    this.button.onclick = function(){ 
        self.currState.buttonWasPressed.call( self );
    }
};

var FSM = { 
    off: {
        buttonWasPressed: function(){
        console.log( "關(guān)燈" ); 
        this.button.innerHTML = "下一次按我是開燈"; 
        this.currState = FSM.on;
        }
    },
    on: {
        buttonWasPressed: function(){
        console.log( "開燈" ); 
        this.button.innerHTML = "下一次按我是關(guān)燈"; 
        this.currState = FSM.off;
    };

var light = new Light(); 
light.init();

模式14-適配器模式

適配器模式的作用就是轉(zhuǎn)換不兼容的接口。

示例:

var getStudents = function(){
    //這個(gè)函數(shù)返回一個(gè)對(duì)象的數(shù)組
    var arr = [
        {"id": 0,
         "name": "LiLei"
        },
        {"id": 1,
         "name": "HanMeimei"
        }
    ];
}

var printStudents = function(fn){
    var params = fn();
    for(var i = 0; i < params.length; i++){
        console.log(params[i].name + ":" + params[i].id);
    }
}

printStudents(getStudents);

//倘若現(xiàn)在提供學(xué)生信息的函數(shù)變了,返回值類型也變了:
var getStudentsObj = function () {
    var stu = {
        "0": "LiLei",
        "1": "HanMeimei"
    };
}

//adaptor
var stuAdapter = function(oldfn){
    var newRes = {};
    var stu = oldfn();
    for(var i = 0; i < stu.length; i++) {
        newRes[stu[i].id] = stu[i].name; 
    }
    return function(){
        return newRes;
    }
}

printStudent(stuAdapter(oldfn));

裝飾者模式與代理模式的結(jié)構(gòu)與適配器模式很像,都是用一個(gè)對(duì)象來(lái)包裝另一個(gè)對(duì)象,但不同點(diǎn)仍然是他們的意圖。適配者模式只是轉(zhuǎn)換接口,不需要知道對(duì)象的具體實(shí)現(xiàn)。

P.s. 本文總結(jié)自《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》,曾探著

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/81086.html

相關(guān)文章

  • JavaScript高級(jí)程序設(shè)計(jì)學(xué)習(xí)筆記(在HTML中使用JavaScript

    摘要:在中使用在中使用腳本有兩種方式一種是嵌入在中的腳本,另一種是引入外部的腳本。二者并行執(zhí)行,不會(huì)造成阻塞。字符編碼,較少使用。放置的位置將腳本放在標(biāo)簽前是最佳的。小結(jié)把插入到頁(yè)面中要使用元素。延遲腳本總是按照指定它們的順序執(zhí)行。 在 HTML 中使用 JavaScript 在html中使用JavaScript腳本有兩種方式一種是嵌入在HTML中的腳本,另一種是引入外部的腳本。兩種方式都離...

    Jason_Geng 評(píng)論0 收藏0
  • Javascript 設(shè)計(jì)模式讀書筆記()——封裝,簡(jiǎn)單的創(chuàng)建對(duì)象模式

    摘要:創(chuàng)建對(duì)象中,創(chuàng)建對(duì)象的基本模式有三種。因此,在設(shè)計(jì)構(gòu)造函數(shù)時(shí),需要進(jìn)行慎重考慮。因此在中,這種問(wèn)題被稱作繼承破壞封裝。靜態(tài)成員每個(gè)只有一份,直接通過(guò)類對(duì)象進(jìn)行訪問(wèn)。 什么是封裝 找工作時(shí)一些公司給了offer后我就想知道真正拿到手的是多少,畢竟賦稅繁重。但各種稅也好,五險(xiǎn)一金也好我實(shí)在是弄不清楚,于是我就會(huì)在網(wǎng)上的一些稅后收入計(jì)算器上進(jìn)行計(jì)算,只需要填寫一些基本信息,比如稅前收入,所...

    lentrue 評(píng)論0 收藏0
  • JavaScript高級(jí)程序設(shè)計(jì)》筆記:在HTML中使用Javascript

    摘要:元素向頁(yè)面中插入的主要方法就是使用元素。這個(gè)屬性的用途是表明腳本在執(zhí)行時(shí)不會(huì)影響頁(yè)面的構(gòu)造。因此,在元素中設(shè)置屬性,相當(dāng)于告訴瀏覽器立即下載,但延遲執(zhí)行?;祀s模式會(huì)讓的行為與包含非標(biāo)準(zhǔn)特性的相同,而標(biāo)準(zhǔn)模式則讓的行為更接近標(biāo)準(zhǔn)行為。 元素 向html頁(yè)面中插入js的主要方法就是使用元素。使用元素的方式有兩種:直接在頁(yè)面中嵌入js代碼和包含外部js文件。直接在頁(yè)面中嵌入js代碼如下: ...

    genefy 評(píng)論0 收藏0
  • JavaScript:萬(wàn)惡的this拿命來(lái)(

    摘要:構(gòu)造函數(shù)對(duì)于被實(shí)例化的,我們稱之為構(gòu)造函數(shù),及使用關(guān)鍵字調(diào)用的,對(duì)于它們來(lái)說(shuō),會(huì)被改變,指向?qū)嵗I侠踝尤仲x上屬性通過(guò)關(guān)鍵字創(chuàng)建實(shí)例,改變函數(shù)內(nèi)部指向注解通過(guò)這個(gè)栗子,我們可以看出,通過(guò)創(chuàng)建構(gòu)造函數(shù)的實(shí)例,使得的指向改變,指向了實(shí)例本身。 用栗子說(shuō)this Bug年年有,今年特別多 對(duì)于JavaScript這么靈活的語(yǔ)言來(lái)說(shuō),少了this怎么活! function ...

    fox_soyoung 評(píng)論0 收藏0
  • Javascript:String對(duì)象總結(jié)()

    摘要:方法始終從前向后找參數(shù)接收兩個(gè)參數(shù),第一個(gè)參數(shù)可以是一個(gè)對(duì)象或者一個(gè)字符串這個(gè)字符串不會(huì)轉(zhuǎn)換成正則表達(dá)式,第二個(gè)參數(shù)可以是一個(gè)字符串或者一個(gè)函數(shù)。要想替換所有子字符串,唯一的辦法就是提供一個(gè)正則表達(dá)式,而且要指定全局標(biāo)志標(biāo)志。 字符串的模式匹配方法 match() 參數(shù):只接受一個(gè)參數(shù),要么是一個(gè)正則表達(dá)式,要么是一個(gè)RegExp()對(duì)象。 返回:數(shù)組。數(shù)組中的第一項(xiàng)是與整個(gè)模式匹配的...

    zzir 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<