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

資訊專欄INFORMATION COLUMN

從裝飾模式到裝飾器

monw3c / 2778人閱讀

摘要:從裝飾模式到裝飾器裝飾模式裝飾模式的作用是在不修改原有的接口的情況下,讓類表現(xiàn)的更好。它是一個(gè)語法糖說完了裝飾模式,我們?cè)倏匆幌略谥凶钚乱氲难b飾器。

從裝飾模式到裝飾器 裝飾模式

裝飾模式的作用是:在不修改原有的接口的情況下,讓類表現(xiàn)的更好。
什么叫更好?

為什么需要裝飾模式

自然是繼承有一些問題
繼承會(huì)導(dǎo)致超類和子類之間存在強(qiáng)耦合性,當(dāng)超類改變時(shí),子類也會(huì)隨之改變;
超類的內(nèi)部細(xì)節(jié)對(duì)于子類是可見的,繼承常常被認(rèn)為破壞了封裝性;

js中的裝飾模式

js中的裝飾模式實(shí)際上把一個(gè)對(duì)象A嵌入到另外一個(gè)對(duì)象B中,也就是B對(duì)象包裝了A對(duì)象,形成了一個(gè)包裝鏈。請(qǐng)求隨著這一條包裝鏈一次傳遞到了包裝鏈上的所有對(duì)象,每一個(gè)對(duì)象都有機(jī)會(huì)處理這一個(gè)請(qǐng)求。

設(shè)想一下場(chǎng)景,打農(nóng)藥,我選了一個(gè)后羿,然后開始一級(jí)我學(xué)了第一個(gè)技能。

var HouYi = {
    skill : function() {
        console.log("增加了攻速")
    }
    HP :function(){
        return 1999
    }
}

HouYi.skill()

結(jié)果,自以為自己很6了的后羿去了下路,遇到了狄仁杰,二馬一錯(cuò)蹬幾個(gè)回合下來就后羿就涼了。后羿覺得不服,回家一趟,發(fā)奮努力,又學(xué)了第二個(gè)技能和第三個(gè)技能。

class Hero {
    buy(){
        console.log("有了一雙鞋子")
        // console.log("有了一件復(fù)活甲")
        // console.log("有了一把飲血?jiǎng)?)
    }
}


var Houyi = new Hero()
Houyi.buy()

那么問題來了,我們看了一下,后羿還是回家買了新的武器裝備,而不是寒酸的只有一雙鞋。但是,我們看到,每次后羿買東西都要回家,也就是都要修改buy方法,那么怎么樣在不回家,不修改buy的方法的基礎(chǔ)上又把東西賣了呢,也就是,如何動(dòng)態(tài)的買東西。

從英雄聯(lián)盟過渡到王者榮耀。

也就是在代碼運(yùn)行期間,我們很難切入某個(gè)函數(shù)的執(zhí)行環(huán)境。

class Hero {
    buyShoes(){
        console.log("有了一雙鞋子")
    }
}

var Houyi = new Hero()

var buyAtk = function() {
    console.log("有了一把飲血?jiǎng)?)
}

var buyDef = function () {
    console.log("有了一件復(fù)活甲")
}

var buyShoes= Houyi.buy

Houyi.buybuybuy = function() {
    buyShoes()
    buyAtk()
    buyDef()
}

Houyi.buybuybuy()

總結(jié)一下:裝飾模式是為已有功能動(dòng)態(tài)地添加更多功能的一種方式,把每個(gè)要裝飾的功能放在多帶帶的函數(shù)里,然后用該函數(shù)包裝所要裝飾的已有函數(shù)對(duì)象,因此,當(dāng)需要執(zhí)行特殊行為的時(shí)候,調(diào)用代碼就可以根據(jù)需要有選擇地、按順序地使用裝飾功能來包裝對(duì)象。優(yōu)點(diǎn)是把類(函數(shù))的核心職責(zé)和裝飾功能區(qū)分開了。

裝飾模式的缺點(diǎn):缺點(diǎn)的話我們也能看到我們定義了很多很相似的細(xì)小對(duì)象到我們的命名空間中,這樣使我們的架構(gòu)變得十分的復(fù)雜,窮于管理。這就有可能導(dǎo)致,我們不是使用它而是被它使用。

它是一個(gè)語法糖

說完了裝飾模式,我們?cè)倏匆幌略贓S7中最新引入的裝飾器(decorator)。這個(gè)概念其實(shí)是從python里引進(jìn)的。

def my_decorator(fn):
  def inner(name):
    print "Hello " + fn(name)
  return inner

@my_decorator
def greet(name):
  return name

greet("Decorator!")
# Hello Decorator!

這種@decorator的寫法其實(shí)就是一個(gè)語法糖。

語法糖意指那些沒有給計(jì)算機(jī)語言添加新功能,而只是對(duì)人類來說更“甜蜜”的語法。語法糖往往給程序員提供了更實(shí)用的編碼方式,有益于更好的編碼風(fēng)格,更易讀。不過其并沒有給語言添加什么新東西。

所以,ES7中的 decorator 同樣借鑒了這個(gè)語法糖,不過依賴于ES5的Object.defineProperty 方法 。

defineProperty 所做的事情就是,為一個(gè)對(duì)象增加新的屬性,或者更改對(duì)象某個(gè)已存在的屬性。調(diào)用方式是 Object.defineProperty(obj, prop, descriptor) ,這 3 個(gè)參數(shù)分別代表:

obj: 目標(biāo)對(duì)象

prop: 屬性名

descriptor: 針對(duì)該屬性的描述符

關(guān)于descriptor代表的意思是對(duì)象描述符,它本身一個(gè)對(duì)象,用于描述目標(biāo)對(duì)象的一個(gè)屬性的屬性。

value:屬性的值,默認(rèn)為undefined

writable:能否修改屬性的值,默認(rèn)值為true

enumerable:能否通過for-in循環(huán)返回屬性。默認(rèn)為ture

configurable:能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為訪問器屬性,默認(rèn)為true.

關(guān)于最后一個(gè)configurable還要多說一句,當(dāng)我們把對(duì)象的一個(gè)屬性設(shè)置為false之后,我們就不能再二次修改了,也就是不能置成true,會(huì)報(bào)錯(cuò)。

const object1 = {};

Object.defineProperty(object1, "property1", {
  value: 42,
  writable: false,
  configurable:false
});

object1.property1 = 77;
// throws an error in strict mode

console.log(object1.property1);
// expected output: 42
裝飾類

decorator大量用于裝飾ES6中的類。具體的寫法是:

@decoratorFun
class Base{}

function decoratorFun(target){
    target.bool = true
}

Base.bool  //   true

上面的代碼,decorator就是一個(gè)裝飾器,它裝飾了Base這個(gè)類的行為(為其增加了一個(gè)靜態(tài)屬性)。而函數(shù)的target屬性,就是被裝飾的類本身。

所以,就是說,如果裝飾器是一個(gè)對(duì)類做修改裝飾的一般函數(shù),那么他的第一個(gè)參數(shù)就是被裝飾類的引用。但是,如果一個(gè)參數(shù)不夠用,怎么辦?

如果不夠用,那么直接可以在外面再包一層。

function decorFun2(str){
    return function(target){
        target.name = str
    }
}

@decorFun2("zhangjingwei")
class Person {}
Person.name //   zhangjingwei

@decorFun2("susu")
class Person2 {}
Person2.name     // susu
class Foo1 {  
     classMethod() {  
        return "hello";  
    }  
} 
class Foo2 {  
     static classMethod() {  
        return "hello";  
    }  
} 

Foo1.classMethod()
var foo1 = new Foo1();  
foo1.classMethod() 

Foo2.classMethod()
var foo2 = new Foo2()
foo2.classMethod()
靜態(tài)屬性和實(shí)例屬性。靜態(tài)屬性是類本身的屬性,類生成的對(duì)象不能繼承該屬性,但是實(shí)例屬性是類生成的對(duì)象可以繼承的。   
ES6的規(guī)范說,類里面沒有靜態(tài)屬性,只有靜態(tài)方法。

上面的都是給類添加靜態(tài)屬性,如果想要增加實(shí)例屬性,那么可以操作類的原型。

function decorFun3(name){
    return function(target) {
        target.prototype.name = name
    }
}

@decorFun3("lubanqihao")
class Nongyao {}

let ny1 = new Nongyao()
ny1.name    // lubanqihao
裝飾類的屬性

裝飾器不僅可以裝飾類,還能裝飾類的方法。

有的時(shí)候,我們想把類中的某個(gè)屬性設(shè)置成只讀不支持修改,可以來用裝飾器來實(shí)現(xiàn)。

function readonly(target,name,descriptr){
    descriptor.writable = false
    return descriptor
}

class Cat{
    @readonly
    say(){
        console.log("miaomiao)
    }
}

let kitty = new Cat()
kitty.say = function(){
    console.log("wangwang")
}

kitty.say()      //miaomiao

我們看到通過裝飾器給類中的say方法,設(shè)置成了只讀。

參數(shù)有三個(gè),target name descriptor。

第一個(gè)參數(shù)是類的原型對(duì)象,裝飾器的本意是裝飾類的實(shí)例,但是因?yàn)轭惖膶?shí)例還沒有生成,只能去修飾類的原型。第二個(gè)參數(shù)是要修飾的屬性名。第三個(gè)參數(shù)是該屬性的描述對(duì)象。

這個(gè)很眼熟是不是?

是不是有點(diǎn)類似于Object.defineProperty().其實(shí)裝飾器對(duì)類的屬性的作用,就是通過Object.defineProperty這個(gè)方法進(jìn)行擴(kuò)展和封裝。

實(shí)際上裝飾器的行為原理是這樣的:

let descriptor = {
    value:function(){
        console.log("miaomiao)
    },
    enumerable:false,
    configable:true,
    writable:true
}

descriptor = readonly(Cat.protitype,"say",descriptor) || descriptor

Object.defineProperty(Cat.prototype, "say",descriptor);

所以,我們看到,當(dāng)裝飾器操作類本身的時(shí)候,操作的對(duì)象也是類本身,但裝飾器操作的是類中的方法的時(shí)候,操作的對(duì)象是是類的描述符descriptor,因?yàn)轭愔械膶傩缘娜啃畔⒍加涗浽谶@個(gè)描述符里面。

裝飾器不能修飾方法,是因?yàn)榇嬖谧兞刻嵘粫?huì)生效

core-decorators.js第三方模塊

core-decorators.js是一個(gè)第三方模塊,提供了一些常用的裝飾器。

@autobind:這個(gè)裝飾器的作用是自動(dòng)綁定this對(duì)象。

import {autobind} from "core-decorators";

class Person {
    @autobind
    getPerson() {
        return this
    }
}

let p1 = new Person()
let getPerson = p1.getPerson()

getPerson() === p1     // true

@readonly 修飾方法使方法變得不可寫

import {readonly} from "core-decorators"

class Dog {
    @readonly
    name = "zhang"
}

let d1 = new Dog()
d1.name = "susu"    // 會(huì)報(bào)錯(cuò),因?yàn)閷傩圆豢蓪?/pre>

override 會(huì)檢查子類的方法是否覆蓋了父類的同名方法。如果不正確,會(huì)報(bào)錯(cuò)。

import {override} from "core-decorators"

class Parent {
  speak(first, second) {}
}

class Child extends Parent {
  @override
  speak() {}
  // SyntaxError: Child#speak() does not properly override Parent#speak(first, second)
}

// or

class Child extends Parent {
  @override
  speaks() {}
  // SyntaxError: No descriptor matching Child#speaks() was found on the prototype chain.
  //
  //   Did you mean "speak"?
}
Mixin混入

意思就是在一個(gè)對(duì)象中混入另外一個(gè)對(duì)象的方法,是對(duì)象繼承的一種替代方式。

//一個(gè)混入的簡(jiǎn)單實(shí)現(xiàn):

class Foo {
    foo() {
        console.log("hahaha")
    }
}

class Bar {}

Object.assign(Bar.prototype,Foo)
let bar1 = new Bar()

bar1.foo()

上邊的例子是通過Object.assign方法進(jìn)行的。Bar的實(shí)例都有foo方法。

所以呢,我們可以把混入的方法多帶帶拿出來,結(jié)合裝飾器使用。

// mixin.js

export function mixin(...list){
    return function (target) {
        Object.assign(target.prototype,...list)
    }
}
import {mixin} from "./mixin.js

class Foo {
    foo() {
        console.log("lalala")
    }
}

@mixin(Foo)
class NewFoo {}

let nf = new NewFoo()
nf.foo()

這樣一個(gè)不好的地方,就是他會(huì)改寫新類的原型對(duì)象。

Babel轉(zhuǎn)碼

需要安裝下邊的東西:

npm install --save-dev babel-core babel-preset-stage-0

然后設(shè)置文件.babelrc

{
  "plugins": ["transform-decorators"]
}

這樣,就能在代碼里實(shí)現(xiàn)裝飾器了。

參考資料https://github.com/zhiqiang21...
http://www.liuhaihua.cn/archi...

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

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

相關(guān)文章

  • 聊聊Typescript中的設(shè)計(jì)模式——裝飾篇(decorators)

    摘要:本文從裝飾模式出發(fā),聊聊中的裝飾器和注解。該函數(shù)的函數(shù)名。不提供元數(shù)據(jù)的支持。中的元數(shù)據(jù)操作可以通過包來實(shí)現(xiàn)對(duì)于元數(shù)據(jù)的操作。 ??隨著Typescript的普及,在KOA2和nestjs等nodejs框架中經(jīng)??吹筋愃朴趈ava spring中注解的寫法。本文從裝飾模式出發(fā),聊聊Typescipt中的裝飾器和注解。 什么是裝飾者模式 Typescript中的裝飾器 Typescr...

    yiliang 評(píng)論0 收藏0
  • ES6重新認(rèn)識(shí)JavaScript設(shè)計(jì)模式: 裝飾模式

    摘要:什么是裝飾器模式向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)的設(shè)計(jì)模式被稱為裝飾器模式,它是作為現(xiàn)有的類的一個(gè)包裝。中的裝飾器模式中有一個(gè)的提案,使用一個(gè)以開頭的函數(shù)對(duì)中的及其屬性方法進(jìn)行修飾。 1 什么是裝飾器模式 showImg(https://segmentfault.com/img/remote/1460000015970102?w=1127&h=563); 向一個(gè)現(xiàn)有的對(duì)...

    wendux 評(píng)論0 收藏0
  • 包裝模式就是這么簡(jiǎn)單啦

    摘要:包裝模式是這樣干的首先我們弄一個(gè)裝飾器,它實(shí)現(xiàn)了接口,以組合的方式接收我們的默認(rèn)實(shí)現(xiàn)類。其實(shí)裝飾器抽象類的作用就是代理核心的功能還是由最簡(jiǎn)單的實(shí)現(xiàn)類來做,只不過在擴(kuò)展的時(shí)候可以添加一些沒有的功能而已。 前言 只有光頭才能變強(qiáng) 回顧前面: 給女朋友講解什么是代理模式 前一篇已經(jīng)講解了代理模式了,今天要講解的就是裝飾模式啦~ 在看到FilterInputStream和FilterOutpu...

    Developer 評(píng)論0 收藏0
  • 【用故事解讀 MobX 源碼(四)】裝飾 和 Enhancer

    摘要:所以這是一篇插隊(duì)的文章,用于去理解中的裝飾器和概念。因此,該的作用就是根據(jù)入?yún)⒎祷鼐唧w的描述符。其次局部來看,裝飾器具體應(yīng)用表達(dá)式是,其函數(shù)簽名和是一模一樣。等裝飾器語法,是和直接使用是等效等價(jià)的。 ================前言=================== 初衷:以系列故事的方式展現(xiàn) MobX 源碼邏輯,盡可能以易懂的方式講解源碼; 本系列文章: 《【用故事解...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<