JS設計模式--裝飾者模式

歡迎關注個人公衆號睿Talk,獲取我最新的文章:
clipboard.pngjavascript

1、前言

所謂裝飾者模式,就是動態的給類或對象增長職責的設計模式。它能在不改變類或對象自身的基礎上,在程序的運行期間動態的添加職責。這種設計模式很是符合敏捷開發的設計思想:先提煉出產品的MVP(Minimum Viable Product,最小可用產品),再經過快速迭代的方式添加功能。java

2、傳統面嚮對象語言的實現方式

var Car = function() {}
Car.prototype.drive = function() {
    console.log('乞丐版');
}

var AutopilotDecorator = function(car) {
    this.car = car;
}
AutopilotDecorator.prototype.drive = function() {
    this.car.drive();
    console.log('啓動自動駕駛模式');
}

var car = new Car();
car = new AutopilotDecorator(car);
car.drive();    //乞丐版;啓動自動駕駛模式;

這種方式的實現要點是裝飾器類要維護目標對象的一個引用,同時要實現目標類的全部接口(這個例子裏的drive方法,若是還有其它方法,好比brake,AutopilotDecorator也要實現)。調用方法時,先執行目標對象原有的方法,再執行自行添加的特性。編程

當接口比較多,裝飾器也比較多時,能夠獨立抽取一個裝飾器父類,實現目標類的全部接口,再建立真正的裝飾器來繼承這個父類。segmentfault

var Car = function() {}
Car.prototype.drive = function() {
    console.log('乞丐版');
}
/* 多了一個剎車方法 */
Car.prototype.brake = function() {
    console.log('剎車');
}

/* 實現全部接口的裝飾器父類 */
var CarDecorator = function(car) {
    this.car = car;
}
CarDecorator.prototype = {
    drive: function() {
        this.car.drive();
    },
    brake: function() {
        this.car.brake();
    }
}

/* 真正的裝飾器 */
var AutopilotDecorator = function(car) {
    CarDecorator.call(this, car);
}
AutopilotDecorator.prototype = new CarDecorator();
AutopilotDecorator.prototype.drive = function() {
    this.car.drive();
    console.log('啓動自動駕駛模式');
}

/* 真正的裝飾器 */
var HybridDecorator = function(car) {
    CarDecorator.call(this, car);
}
HybridDecorator.prototype = new CarDecorator();
HybridDecorator.prototype.brake = function() {
    this.car.brake();
    console.log('啓動充電模式');
}

var car = new Car();
car = new AutopilotDecorator(car);
car = new HybridDecorator(car);
car.drive();    //乞丐版;啓動自動駕駛模式;
car.brake();    //剎車;啓動充電模式;

3、JS基於對象的實現方式

var car = {
    drive: function() {
        console.log('乞丐版');
    }
}

var driveBasic = car.drive;

var autopilotDecorator = function() {
    console.log('啓動自動駕駛模式');
}

var carToDecorate = Object.create(car);

carToDecorate.drive = function() {
    driveBasic();
    autopilotDecorator();
}

carToDecorate.drive();    //乞丐版;啓動自動駕駛模式;

這種實現方式徹底是基於JS自身的語言特色作考量。定義類的目的是實現代碼的封裝和複用,而JS這門語言是沒有類的概念的。它只有2種數據類型:基本類型和對象類型。實現邏輯的封裝和代碼的重用只須要經過對象來組織代碼,而後利用原生提供的克隆機制(Object.create)來達到目的。設計模式

從代碼的角度看,若是想擴展drive方法,只須要用一個變量來保存原函數的引用,而後再重寫drive方法就能夠了。在重寫的方法裏面,只要記得調用方法原有的行爲就行。 app

另外,咱們能夠經過如下的工具函數,達到裝飾函數的目的:函數

Function.prototype.after = function(afterfn) {
    var _self = this;
    return function() {
        var ret = _self.apply(this, arguments);
        afterfn.apply(this, arguments);
        return ret;
    }
}

var car = {
    drive: function() {
        console.log('乞丐版');
    }
}

var autopilotDecorator = function() {
    console.log('啓動自動駕駛模式');
}

var carToDecorate = Object.create(car);

carToDecorate.drive = car.drive.after(autopilotDecorator);

carToDecorate.drive();    //乞丐版;啓動自動駕駛模式;

經過在Function的原型鏈上定義after函數,給全部的函數都賦予了被擴展的功能,固然也能夠根據須要定義一個before的函數,在函數執行前去作一些操做。這種實現方式借鑑了AOP(Aspect Oriented Programming,面向切面編程)的思想。工具

4、ES7的實現方式

ES7提供了一種相似的Java註解的語法糖decorator,來實現裝飾者模式。使用起來很是簡潔:this

function autopilotDecorator(target, key, descriptor) {
    const method = descriptor.value;
    
    descriptor.value = () => {
        method.apply(target);
        console.log('啓動自動駕駛模式');
    }
    
    return descriptor;
}

class Car {
    @autopilotDecorator
    drive() {
        console.log('乞丐版');
    }
}

let car = new Car();
car.drive();    //乞丐版;啓動自動駕駛模式;

decorator的實現依賴於ES5的Object.defineProperty方法。defineProperty所作的事情是爲一個對象增長新的屬性,或者更改某個已存在的屬性。調用方式是Object.defineProperty(obj, prop, descriptor)spa

var o = {}; // 建立一個新對象

// 在對象中添加一個屬性
Object.defineProperty(o, "name", {
  value : "Dickens",
  writable : true,
  enumerable : true,
  configurable : true
});

// 在對象中添加一個方法
Object.defineProperty(o, "sayHello", {
  value : function() {
        console.log('Hello, my name is: ', this.name)
  },
  writable : true,
  enumerable : true,
  configurable : true
});

o.sayHello()    //Hello, my name is:  Dickens

decorator的參數跟defineProperty是徹底同樣的,含義也相似,經過修改descripter,就能達到擴展功能的目的。

5、總結

本文介紹了裝飾者模式的基本概念,並經過不一樣的實現方式來介紹使用方法。對於不一樣的使用方法,也做了比較透徹的解釋,讓你們不但知其然,還知其因此然。

裝飾者模式是一種十分經常使用且功能強大的模式,利用ES7的語法糖,咱們能用很是簡潔的方式來表達裝飾的意圖,推薦你們在實際項目中用起來。

相關文章
相關標籤/搜索