前端 JS 设计模式之代理模式、外观模式、观察者模式 和迭代器模式

一、代理模式
  1. 代理模式,使用者无权访问目标对象,中间加代理,通过代理做授权和控制。
  2. 对于代理模式的理解,可以举一个例。比如如果广告商想找到明星进行演出,不会直接联系明星,而是联系明星的经纪人,通过经纪人,去与明星之间进行沟通。
  3. 对于代理模式的应用,在 ES6 中的 Proxy 中也比较常见。
  4. 代理模式的设计原则验证,代理类和目标类分离,隔离开目标类和使用者,符合开放封闭原则。
  5. 代理模式与适配器模式的比较:适配器模式是提供一个不同的接口,比如不同版本的插头。代理模式是提供一个一模一样的接口。
  6. 代理模式与装饰器模式的比较:装饰器模式是扩展功能,原有功能不变且可直接使用。代理模式是显示原有功能,但是经过限制或者阉割之后的。
  7. 代理模式的代码,如下所示:

// 明星
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)
二、外观模式
  1. 外观模式,为子系统中的一组接口提供了一个高层的接口,使用者使用这个高层接口。
  2. 对于外观模式的理解,可以举例。比如在去医院看病,接待员去挂号、门诊、划价和取药。
  3. 外观模式的设计原则验证,不符合单一职责原则和开放封闭原则,因此谨慎使用,不可滥用。
三、观察者模式
  1. 观察者模式,发布和订阅,一对多。
  2. 对于观察者模式的理解,可以举例。比如在咖啡馆点好咖啡以后,就可以玩手机、打游戏等,点好之后坐等被叫。
  3. 对于观察者模式的应用场景,网页事件绑定,PromisejQuery callbacksnodejs 自定义事件等等。在 node.js 中,处理 http 请求,多进程通讯。vuereact 组件生命周期触发, vue watch 等。
  4. 观察者模式的设计原则验证,主题和观察者分离,不是主动触发而是被动监听,两者解耦,符合开放封闭原则。
  5. 观察者模式的代码,如下所示:

// 主题,接收状态变化,触发每个观察者
class Subject {
    constructor() {
        this.state = 0
        this.observers = []
    }
    getState() {
        return this.state
    }
    setState(state) {
        this.state = state
        this.notifyAllObservers()
    }
    attach(observer) {
        this.observers.push(observer)
    }
    notifyAllObservers() {
        this.observers.forEach(observer => {
            observer.update()
        })
    }
}

// 观察者,等待被触发
class Observer {
    constructor(name, subject) {
        this.name = name
        this.subject = subject
        this.subject.attach(this)
    }
    update() {
        console.log(`${this.name} update, state: ${this.subject.getState()}`)
    }
}

// 测试代码
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)

s.setState(1)
s.setState(2)
s.setState(3)

四、迭代器模式
  1. 迭代器模式,顺序访问一个集合,使用者无需知道集合的内部结构和封装。
  2. 对于迭代器的应用场景,比如 jQuery eachES6 Iterator 等等。
  3. ES6 Iterator 的存在原因是 ES6 语法中,有序集合的数据类型已经有很多,需要有一个统一的遍历接口来遍历所有的数据类型。Object 不是有序集合,可以用 Map 代替。
  4. ES6 Iterator 具有 [Symbol.iterator] 属性,属性值是函数,执行函数返回一个迭代器。这个迭代器就有 next 方法可顺序迭代子元素,可以运行 Array.prototype[Symbol.iterator] 来测试。
  5. ES6 IteratorGenerator 的区别是 Iterator 的价值是不限于上述几个类型的遍历,还有 Generator 函数的使用。只要返回的数据符合 Iterator 接口的要求,就可以使用 Iterator 的语法,这就是迭代器模式。
  6. 迭代器模式的设计原则验证,迭代器对象和目标对象分离,迭代器将使用者与目标对象隔离开,符合开放封闭原则。
  7. 迭代器模式的代码,如下所示:
class Iterator {
    constructor(conatiner) {
        this.list = conatiner.list
        this.index = 0
    }
    next() {
        if (this.hasNext()) {
            return this.list[this.index++]
        }
        return null
    }
    hasNext() {
        if (this.index >= this.list.length) {
            return false
        }
        return true
    }
}

class Container {
    constructor(list) {
        this.list = list
    }
    // 生成遍历器
    getIterator() {
        return new Iterator(this)
    }
}

// 测试代码
let container = new Container([1, 2, 3, 4, 5])
let iterator = container.getIterator()
while(iterator.hasNext()) {
    console.log(iterator.next())
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值