JavaScript - Decorator 裝飾者模式

JavaScript - Decorator

Decorator(裝飾者模式)的說明與範例。

為什麼會有Decorator?

假設我們要買一台12吋的MacBook,原始價格是$41900,會隨著加上不同的加購條件而提升價格,例如增加記憶體需多增$10000,增加刻字服務多增$1000,增加保固需多增$8590,如果三項都要(增加記憶體、刻字、保固)則會增加$19590。在這個例子中,不論是合併特性或新增一個特性(例如之後想要新增「購買轉接線」),就得多寫一個function,於是管理和維護變得非常困難,而Decorator就是為了擴充性應運而生。

var MacBook = function(){
    this.cost = function(){return 41900};
    this.screenSize = function(){return 12}
};

var mb = new MacBook();

//增加記憶體需多增$10000
var MacBookWithLargeMemory = function(){
    MacBook.call(this);
    this.cost = this.cost() + 10000;
};

//增加刻字服務多增$1000
var MacBookWithEngraving = function(){
    MacBook.call(this);
    this.cost = this.cost() + 1000;
};

//增加保固需多增$8590
var MacBookWithInsurance = function(){
    MacBook.call(this);
    this.cost = this.cost() + 8590;
};

//增加記憶體、刻字、保固 - 雖然只是將前面的條件合併,卻需要多寫一個function
var MacBookWithLargeEngravingInsurance = function(){
    MacBook.call(this);
    this.cost = this.cost() + 10000 + 1000 + 8590;
};

MacBookWithLargeMemory.prototype = Object.create(MacBook.prototype);

//增加記憶體需多增$10000
var mbWithLargeMemory = new MacBookWithLargeMemory();
console.log(mbWithLargeMemory); //51900

//增加刻字服務多增$1000
var mbWithEngraving = new MacBookWithEngraving();
console.log(mbWithEngraving); //42900

//增加保固需多增$8590
var mbWithInsurance = new MacBookWithInsurance();
console.log(mbWithInsurance); //50490

//增加記憶體、刻字、保固
var mbWithLargeEngravingInsurance = new MacBookWithLargeEngravingInsurance();
console.log(mbWithLargeEngravingInsurance); //61490

Decorator怎麼用?

Decorator接受function作為其參數,並使用匿名函數(anonymous function)包裝起來做執行,然後將執行結果回傳回去。

簡單範例

function decorator(func) {
    return function() {
        return func.apply(this, arguments);
    }
}

function sum(a, b) {
    return a + b;
}

var getSum = decorator(sum);

console.log( getSum(1,2) ); //3
console.log( getSum(2,3) ); //5

改寫上述購買MacBook的例子

function MacBook(){
    this.cost = function(){return 41900};
    this.screenSize = function(){return 12}
}

//Decorator 1 - 增加記憶體需多增$10000
function Memory(mackbook){
    var v = mackbook.cost();
    mackbook.cost = function(){
        return v + 10000;
    }
}

//Decorator 2 - 增加刻字服務多增$1000
function Engraving(mackbook){
    var v = mackbook.cost();
    mackbook.cost = function(){
        return v + 1000;
    }
}

//Decorator 3 - 增加保固需多增$8590
function Insurance(mackbook){
    var v = mackbook.cost();
    mackbook.cost = function(){
        return v + 8590;
    }
}

var mb = new MacBook();

//增加記憶體、刻字、保固
Memory(mb);
Engraving(mb);
Insurance(mb);
console.log(mb.cost()); //61490
console.log(mb.screenSize()); //12

Decorator的優點就如同上例所示 - 可重覆利用(reuse)、彈性(flexibility)和擴充性(expandability)。但其缺點為若管理不慎可能造成結構複雜的問題。


推薦閱讀


由於部落格搬家了,因此在新落格也放了一份,未來若有增刪會在這裡更新-Decorator 裝飾者模式

留言