成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

裝飾者模式能做什么?

Ilikewhite / 2476人閱讀

摘要:自行車的基類如下其它方法那么我們可以先創(chuàng)建一個裝飾者模式基類這個基類其實沒有做什么事情,它只是接受一個實例,實現(xiàn)其對應(yīng)的方法,并且將調(diào)用其方法返回而已。

什么是裝飾者模式

裝飾者模式是一種為函數(shù)或類增添特性的技術(shù),它可以讓我們在不修改原來對象的基礎(chǔ)上,為其增添新的能力和行為。它本質(zhì)上也是一個函數(shù)(在javascipt中,類也只是函數(shù)的語法糖)。

我們什么時候可以弄到它呢

我們來假設(shè)一個場景,一個自行車商店有幾種型號的自行車,現(xiàn)在商店允許用戶為每一種自行車提供一些額外的配件,比如前燈、尾燈、鈴鐺等。每選擇一種或幾種配件都會影響自行車的售價。

如果按照比較傳統(tǒng)的創(chuàng)建子類的方式,就等于我們目前有一個自行車基類,而我們要為每一種可能的選擇創(chuàng)建一個新的類。可是由于用戶可以選擇一種或者幾種任意的配件,這就導(dǎo)致最終可能會生產(chǎn)幾十上百個子類,這明顯是不科學(xué)的。然而,對這種情況,我們可以使用裝飾者模式來解決這個問題。

自行車的基類如下:

class Bicycle {
    // 其它方法
    wash () {}
    ride () {}
    getPrice() {
        return 200;
    }
}

那么我們可以先創(chuàng)建一個裝飾者模式基類

class BicycleDecotator {
    constructor(bicycle) {
        this.bicycle = bicycle;
    }
    wash () {
        return this.bicycle.wash();
    }
    ride () {
        return this.bicycle.ride();
    }
    getPrice() {
        return this.bicycle.getPrice();
    }
}

這個基類其實沒有做什么事情,它只是接受一個Bicycle實例,實現(xiàn)其對應(yīng)的方法,并且將調(diào)用其方法返回而已。

有了這個基類之后,我們就可以根據(jù)我們的需求對原來的Bicycle類為所欲為了。比如我可以創(chuàng)建一個添加了前燈的裝飾器以及添加了尾燈的裝飾器:

class HeadLightDecorator extends BicycleDecorator {
    constructor(bicycle) {
        super(bicycle);
    }
    getPrice() {
        return this.bicycle.getPrice() + 20;
    }
}
class TailLightDecorator extends BicycleDecorator {
    constructor(bicycle) {
        super(bicycle);
    }
    getPrice() {
        return this.bicycle.getPrice() + 20;
    }
}

那么,接下來我們就可以來對其自由組合了:

let bicycle = new Bicycle();
console.log(bicycle.getPrice()); // 200
bicycle = new HeadLightDecorator(bicycle); // 添加了前燈的自行車
console.log(bicycle.getPrice());  // 220
bicycle = new TailLightDecorator(bicycle); // 添加了前燈和尾燈的自行車
console.log(bicycle.getPrice()); // 240

這樣寫的好處是什么呢?假設(shè)說我們有10個配件,那么我們只需要寫10個配件裝飾器,然后就可以任意搭配成不同配件的自行車并計算價格。而如果是按照子類的實現(xiàn)方式的話,10個配件可能就需要有幾百個甚至上千個子類了。

從例子中我們可以看出裝飾者模式的適用場合:

如果你需要為類增添特性或職責(zé),可是從類派生子類的解決方法并不太現(xiàn)實的情況下,就應(yīng)該使用裝飾者模式。

在例子中,我們并沒有對原來的Bicycle基類進行修改,因此也不會對原有的代碼產(chǎn)生副作用。我們只是在原有的基礎(chǔ)上增添了一些功能。因此,如果想為對象增添特性又不想改變使用該對象的代碼的話,則可以采用裝飾者模式。

裝飾者模式除了可以應(yīng)用在類上之外,還可以應(yīng)用在函數(shù)上(其實這就是高階函數(shù))。比如,我們想測量函數(shù)的執(zhí)行時間,那么我可以寫這么一個裝飾器:

function func() {
    console.log("func");
}
function timeProfileDecorator(func) {
    return function (...args) {
        const startTime = new Date();
        func.call(this, ...args);
        const elapserdTime = (new Date()).getTime() - startTime.getTime();
        console.log(`該函數(shù)消耗了${elapserdTime}ms`);
    }
}
const newFunc = timeProfileDecorator(func);
console.log(newFunc());
做一些有趣的事情

既然知道了裝飾者模式可以在不修改原來代碼的情況下為其增添一些新的功能,那么我們就可以來做一些有趣的事情。

我們可以為一個類的方法提供性能分析的功能。

class TimeProfileDecorator {
  constructor(component, keys) {
    this.component = component;
    this.timers = {};
    const self = this;
    for (let i in keys) {
      let key = keys[i];
        if (typeof component[key] === "function") {
          this[key] = function(...args) {
            this.startTimer(key);
            // 解決this引用錯誤問題
            component[key].call(component, ...args);
            this.logTimer(key);
          }
        }
    }
  }
  startTimer(namespace) {
    this.timers[namespace] = new Date();
  }
  logTimer(namespace) {
    const elapserdTime = (new Date()).getTime() - this.timers[namespace].getTime();
    console.log(`該函數(shù)消耗了${elapserdTime}ms`);
  }
}
// example
class Test {
  constructor() {
    this.name = "cjg";
    this.age = 22;
  }
  sayName() {
    console.log(this.name);
  }
  sayAge() {
    console.log(this.age);
  }
}

let test1 = new Test();
test1 = new TimeProfileDecorator(test1, ["sayName", "sayAge"]);
console.log(test1.sayName());
console.log(test1.sayAge());
對函數(shù)進行增強

節(jié)流函數(shù)or防抖函數(shù)

function throttle(func, delay) {
    const self = this;
    let tid;
    return function(...args) {
        if (tid) return;
        tid = setTimeout(() => {
            func.call(self, ...args);
            tid = null;
        }, delay);
    }
}

function debounce(func, delay) {
    const self = this;
    let tid;
    return function(...args) {
        if (tid) clearTimeout(tid);
        tid = setTimeout(() => {
            func.call(self, ...args);
            tid = null;
        }, delay);
    }
}

緩存函數(shù)返回值

// 緩存函數(shù)結(jié)果,對于一些計算量比較大的函數(shù)效果比較明顯。
function memorize(func) {
    const cache = {};
    return function (...args) {
        const key = JSON.stringify(args);
        if (cache[key]) {
          console.log("緩存了");
          return cache[key];
        }
        const result = func.call(this, ...args);
        cache[key] = result;
        return result;
    };
}

function fib(num) {
  return num < 2 ? num : fib(num - 1) + fib(num - 2);
}

const enhanceFib = memorize(fib);
console.log(enhanceFib(40));
console.log(enhanceFib(40));
console.log(enhanceFib(40));
console.log(enhanceFib(40));

構(gòu)造React高階組件,為組件增加額外的功能,比如為組件提供shallowCompare功能:

import React from "react";
const { Component } = react;

const ShadowCompareDecorator = (Instance) => class extends Component {
  shouldComponentUpdate(nextProps, nextState) {
    return !shallowCompare(this.props, nextProps) ||
      !shallowCompare(this.state, nextState);
  }
  render() {
    return (
      
    );
  }
};

export default ShadowCompareDecorator;

當(dāng)然,你如果用過react-redux的話,你肯定也用過connect。其實connect也是一種高階組件的方式。它通過裝飾者模式,從Provider的context里拿到全局的state,并且將其通過props的方式傳給原來的組件。

總結(jié)

使用裝飾者模式可以讓我們?yōu)樵械念惡秃瘮?shù)增添新的功能,并且不會修改原有的代碼或者改變其調(diào)用方式,因此不會對原有的系統(tǒng)帶來副作用。我們也不用擔(dān)心原來系統(tǒng)會因為它而失靈或者不兼容。就我個人而言,我覺得這是一種特別好用的設(shè)計模式。

一個好消息就是,js的裝飾器已經(jīng)加入了es7的草案里啦。它讓我們可以更加優(yōu)雅的使用裝飾者模式,如果有興趣的可以添加下babel的plugins插件提前體驗下。阮一峰老師的這個教程也十分淺顯易懂。

參考文獻:

Javascript設(shè)計模式

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/109786.html

相關(guān)文章

  • Java 設(shè)計模式裝飾模式

    摘要:裝飾者模式組成結(jié)構(gòu)抽象構(gòu)件給出抽象接口或抽象類,以規(guī)范準(zhǔn)備接收附加功能的對象。裝飾者模式圖解裝飾者模式應(yīng)用場景需要擴展一個類的功能,或給一個類添加附加職責(zé)。裝飾者對象接受所有來自客戶端的請求。參考資料設(shè)計模式 一、了解裝飾者模式 1.1 什么是裝飾者模式 裝飾者模式指的是在不必改變原類文件和使用繼承的情況下,動態(tài)地擴展一個對象的功能。它是通過創(chuàng)建一個包裝對象,也就是裝飾者來包裹真實的對...

    kumfo 評論0 收藏0
  • 前端也要學(xué)系列:設(shè)計模式裝飾模式

    摘要:什么是裝飾者模式今天我們來講另外一個非常實用的設(shè)計模式裝飾者模式。就增加功能來說,裝飾者模式相比生成子類更為靈活。下面,裝飾者模式就要正式登場了。下一步,我們可以愉快的去使用裝飾者模式啦 什么是裝飾者模式 今天我們來講另外一個非常實用的設(shè)計模式:裝飾者模式。這個名字聽上去有些莫名其妙,不著急,我們先來記住它的一個別名:包裝器模式。 我們記著這兩個名字來開始今天的文章。 首先還是上《設(shè)計...

    高勝山 評論0 收藏0
  • 開發(fā)之路(設(shè)計模式三:裝飾模式

    摘要:若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。裝飾者模式意味著一群裝飾者類,這些類用來包裝具體組件。裝飾者類反映出被裝飾組件類型。裝飾者會導(dǎo)致設(shè)計中出現(xiàn)許多小對象,如果過度使用,會讓程序變得很復(fù)雜。 嘿嘿嘿,你是不是很喜歡用繼承呢?感覺沒什么事情是一個爸爸類搞不定的,有的話就兩個,快來跟我看看這個模式吧,它能讓你斷奶,給愛用繼承的人一個全新的設(shè)計眼界。 直奔主題,你是否有聽說...

    Vicky 評論0 收藏0
  • 5 分鐘即可掌握的 JavaScript 裝飾模式與 AOP

    摘要:下裝飾者的實現(xiàn)了解了裝飾者模式和的概念之后,我們寫一段能夠兼容的代碼來實現(xiàn)裝飾者模式原函數(shù)拍照片定義函數(shù)裝飾函數(shù)加濾鏡用裝飾函數(shù)裝飾原函數(shù)這樣我們就實現(xiàn)了抽離拍照與濾鏡邏輯,如果以后需要自動上傳功能,也可以通過函數(shù)來添加。 showImg(https://segmentfault.com/img/bVbueyz?w=852&h=356); 什么是裝飾者模式 當(dāng)我們拍了一張照片準(zhǔn)備發(fā)朋友...

    chunquedong 評論0 收藏0
  • 設(shè)計模式裝飾模式

    摘要:相關(guān)設(shè)計模式裝飾者模式和代理模式裝飾者模式關(guān)注再一個對象上動態(tài)添加方法代理模式關(guān)注再對代理對象的控制訪問,可以對客戶隱藏被代理類的信息裝飾著模式和適配器模式都叫包裝模式關(guān)于新職責(zé)適配器也可以在轉(zhuǎn)換時增加新的職責(zé),但主要目的不在此。 0x01.定義與類型 定義:裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態(tài)地擴展一個對象的功能。它是通過創(chuàng)建一個包裝對象,也就是裝飾來包裹真實的...

    chuyao 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<