继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

javascript设计模式之结构型模式

侠客岛的含笑
关注TA
已关注
手记 133
粉丝 1.6万
获赞 1807

适配器

  • 旧接口格式和使用者不兼容
  • 中间加一个适配转换接口
  • 验证
    • 将旧接口和使用者进行分离
    • 符合开放封闭原则
  • 例子
    • 封装旧接口
      • 图片描述
    • vue computed
      • 图片描述

图片描述

图片描述

装饰器

  • 为对象添加新功能
  • 不改变其原有的结构和功能
  • 场景
    • ES7装饰器
    • core-decorators第三方库 lib
    • babel-plugin-transform-decorators-legacy
  • 验证
    • 将现有对象和装饰器进行分离,两者独立存在
    • 符合开放封闭原则
@testable(true)
class MyTestableClass {
  // ...
}

function testable(isDec) {
  return function(target) {
	  target.isDec = isDec;
  }
}

alert(MyTestableClass.isTestable) // true
其实就是相当于
MyTestable = testable(MyTestable) || MyTestable
混合
function mixins(...list) {
  return function (target) {
    Object.assign(target.prototype, ...list)
  }
}

const Foo = {
  foo() { alert('foo') }
}

@mixins(Foo)
class MyClass {}

let obj = new MyClass();
obj.foo() // 'foo'
装饰方法 例
function readonly(target, name, descriptor){
  // descriptor对象原来的值如下
  // {
  //   value: specifiedFunction,
  //   enumerable: false,
  //   configurable: true,
  //   writable: true
  // };
  descriptor.writable = false;
  return descriptor;
}

class Person {
    constructor() {
        this.first = 'A'
        this.last = 'B'
    }

    @readonly
    name() { return `${this.first} ${this.last}` }
}

var p = new Person()
console.log(p.name())
p.name = function () {} // 这里会报错,因为 name 是只读属性

function log(target, name, descriptor) {
  var oldValue = descriptor.value;

  descriptor.value = function() {
    console.log(`Calling ${name} with`, arguments);
    return oldValue.apply(this, arguments);
  };

  return descriptor;
}

class Math {
  @log
  add(a, b) {
    return a + b;
  }
}

const math = new Math();
const result = math.add(2, 4);
console.log('result', result);

core-decorators

import { readonly } from 'core-decorators'

class Person {
    @readonly
    name() {
        return 'zhang'
    }
}

let p = new Person()
alert(p.name())
// p.name = function () { /*...*/ }  // 此处会报错
废弃装饰器
import { deprecate } from 'core-decorators';

class Person {
  @deprecate
  facepalm() {}

  @deprecate('We stopped facepalming')
  facepalmHard() {}

  @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
  facepalmHarder() {}
}

let person = new Person();

person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.

person.facepalmHard();
// DEPRECATION Person#facepalmHard: We stopped facepalming

person.facepalmHarder();
// DEPRECATION Person#facepalmHarder: We stopped facepalming
//
//     See http://knowyourmeme.com/memes/facepalm for more details.

UML类图

图片描述

class Circle{
	draw(){
		console.Log('画一个圆形’)
}
class Decorator {
	constructor(circle){
		this.circle=circle
	}
	draw(){
		this.circle.draw()
		this.setRedBorder(circle)
	}
	setRedBorder(circle){
		console.log(设置红色边框)
	}
}

//测试代码
let circle=new Circle()
circle.draw()
let dec=new Decorator(circle)
dec.draw()

代理模式

  • 使用者无权访问目标对象
  • 中间加代理,通过代理做授权和控制
  • 例子
    • 科学上网
  • 场景
    • 网页事件代理
      • 图片描述
    • jQuery $.proxy
      • 图片描述
    • ES6 Proxy

UML图

图片描述


class ReadImg {
	constructor(fileName){
		this.fileName=fileName
		this.loadFromDisk()//初始化即从硬盘中加载,模拟
		}
	display(){
		console.log('display...'+this.fileName)
	}
	loadFromDisk(){
		console.Log('loading...'+this.fileName)
	}
}
class ProxyImg {
	constructor(fileName){
		this.realImg=new ReadImg(fileName)
	}
	display() {
		this.realImg.display()
}
// test
let proxyImg=new ProxyImg('1.png')
proxyImg.display()

// 明星 ES6 Proxy
let star = {
    name: '张XX',
    age: 25,
    phone: '13910733521'
}

// 经纪人
let agent = new Proxy(star, {
    get: function (target, key) {
        if (key === 'phone') {
            // 返回经纪人自己的手机号
            return '18611112222'
        }
        if (key === 'price') {
            // 明星不报价,经纪人报价
            return 120000
        }
        return target[key]
    },
    set: function (target, key, val) {
        if (key === 'customPrice') {
            if (val < 100000) {
                // 最低 10w
                throw new Error('价格太低')
            } else {
                target[key] = val
                return true
            }
        }
    }
})

// 主办方
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)

// 想自己提供报价(砍价,或者高价争抢)
agent.customPrice = 150000
// agent.customPrice = 90000  // 报错:价格太低
console.log('customPrice', agent.customPrice)

代理模式vs 适配器模式 装饰器模式 对比

  • 适配器模式:提供一个不同的接口(如不同版本的插头)
  • 代理模式:提供一模一样的接口
  • 装饰器模式:扩展功能,原有功能不变且可直接使用
  • 代理模式:显示原有功能,但是经过限制或者阉割之后的

外观模式

  • 为子系统中的一组接口提供了一个高层接口
  • 使用者使用这个高层接口
  • 示例
    • 去医院看病,接待员去挂号、门诊、划价、取药
  • 验证
    • 不符合单一职责原则和开放封闭原则,因此谨慎使用,不可滥用

图片描述

图片描述

打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP