美文网首页
js设计模式-适配器模式、装饰器模式(2)

js设计模式-适配器模式、装饰器模式(2)

作者: 疯狂吸猫 | 来源:发表于2019-11-21 16:14 被阅读0次

    github所有关于设计模式的代码:js学习设计模式记录

    1.适配器模式

    使用场景:
    旧接口与使用者不兼容,中间添加一个转换接口。
    当他人已完成的代码在格式上不满足新需求时,用适配器模式改变。
    例子: 德国插座转换为中国插座

    class Adoptee{
        specificRequest(){
            return "德国插座"
        }
    }
    class Adapter {
        constructor(){
            this.adoptee=new Adoptee()
        }
        request(){
            let info=this.adoptee.specificRequest()
            return `${info}-转换-中国插座`
        }
    }
    console.log(new Adapter().request())
    

    2.装饰器模式

    使用场景: 旧的功能继续沿用,但是要在旧的功能上添加、修饰一些部分
    例子: 原Circle类可以画一个圆,现要画圆,并且给这个圆添加边框

    class Circle{
        draw(){
            console.log("画一个圆")
        }
    }
    class Decorator{
        constructor(){
            this.circle=new Circle()
        }
        draw(){
            this.circle.draw()
            this.fillBorder()
        }
        fillBorder(){
            console.log("添加边框")
        }
    }
    new Decorator().draw()//画一个圆  添加边框
    

    3.es7装饰器介绍

    装饰器语法可参考:es6-装饰器 JS 装饰器

    类装饰器

    定义一个Demon的类,定义装饰器decorator1,@decorator1写在calss Demon1的前面
    decorator1会获取到参数target,也就是当前的Demon1类。可以在decorator1这个函数中对Demon1的属性进行处理,如下在Demon1中添加一个静态属性decorator="i am decorator"

    @decorator1
    class Demon1{
    }
    function decorator1(target) {
        target.decorator="i am decorator"
    }
    console.log(Demon1.decorator)//i am decorator
    

    装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。装饰器的原理如下

    @decorator
    class A{}
    decorator(target){}
    //相当于↓↓
    class A{}
    A=decorator(A)||A
    

    带参数的装饰器

    @decorator2("new decorator")
    class Demon2{
    }
    function decorator2(newValue){
        return function (target) {
            target.decorator=newValue
        }
    }
    console.log(Demon2.decorator)//new decorator
    

    @decorator2("new decorator")执行decorator2传参“new decorator”,并且在decorator2的内部返回不进行传参时定义的装饰器函数。
    decorator2嵌套两层function,第一层用来传参,第二层是普通的装饰器函数

    @decorator2("new decorator")
    class Demon2{
    }
    function decorator2(newValue){
        return function (target) {
            target.decorator=newValue
        }
    }
    console.log(Demon2.decorator)//new decorator
    

    常用装饰器 :Mixin示例

    Mixin相关知识点参考:Mixin

    Mixin是JavaScript中用的最普遍的模式,几乎所有流行类库都会有Mixin的实现。
    Mixin是掺合,混合,糅合的意思,即可以就任意一个对象的全部或部分属性拷贝到另一个对象上。
    下面的例子中通过装饰器mixin将别的对象的属性、方法添加到Demon3中
    assign知识点:ES6之Object.assign()详解

    function mixin(list){
        return function (target) {
            Object.assign(target.prototype,...list)
        }
    }
    const append1={
        getAppend1Name(){
            console.log("append1")
        }
    }
    
    const append2={
        getAppend2Name(){
            console.log("append2")
        }
    }
    @mixin([ append1, append2])
    class Demon3{
    
    }
    let demon3=new Demon3()
    demon3.getAppend1Name()//append1
    demon3.getAppend2Name()//append2
    

    装饰方法

    readOnly 装饰器
    装饰器总共接收三个参数target,value,description在下面例子中target是Demon4,value是getName,description是getName的属性描述符
    设置属性描述符的writable为false,将getName属性设置为只读

    function readOnly(target,value,description) {
        description.writable=false
    }
    
    class Demon4 {
        constructor(){
            this.name="demon4"
        }
        @readOnly
        getName(){
            return this.name;
        }
    }
    const demon4=new Demon4()
    demon4.getName=function () {//报错:Uncaught TypeError: Cannot assign to read only property 'getName' of object '#<Demon4>'
        console.log("change")
    }
    

    修改getName时会报错


    image.png

    log日志打印装饰器
    以下日志打印装饰器在执行setName时打印出旧的name值与新的name值
    通过description.value重写setName方法,使在调用原来的getName之前先console.log

    function  log(target,value,description) {
        const oldValue=description.value
        description.value=function (name) {
            console.log(`previous name:${this.name}  new name is:${name}`)
            oldValue.call(this,arguments)
        }
    }
    
    class Demon5{
        constructor(){
            this.name="demon5"
        }
        @log
        setName(name){
            this.name=name
        }
    }
    const demon5=new Demon5()
    demon5.setName("DEMON5")//previous name:demon5  new name is:DEMON5
    

    建议不要手写装饰器,使用现成的装饰器库core-decorators.js

    相关文章

      网友评论

          本文标题:js设计模式-适配器模式、装饰器模式(2)

          本文链接:https://www.haomeiwen.com/subject/ggpoictx.html