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

本文详细介绍了前端开发中常见的四种设计模式:代理模式,用于授权和控制访问;外观模式,提供一个高层接口简化子系统的使用;观察者模式,实现发布-订阅机制,广泛应用于事件绑定;以及迭代器模式,允许顺序访问集合而无需暴露其内部结构。每个模式都结合实例进行了深入讲解,并讨论了它们的设计原则和适用场景。

一、代理模式

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

代理模式的代码,如下所示:


// 明星
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. 对于观察者模式的应用场景,网页事件绑定,Promise,jQuery callbacks 和 nodejs 自定义事件等等。在
    node.js 中,处理 http 请求,多进程通讯。vue 和 react 组件生命周期触发, vue watch 等。
  4. 观察者模式的设计原则验证,主题和观察者分离,不是主动触发而是被动监听,两者解耦,符合开放封闭原则。

观察者模式的代码,如下所示:


// 主题,接收状态变化,触发每个观察者
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 each、ES6 Iterator 等等。
  3. ES6 Iterator 的存在原因是 ES6语法中,有序集合的数据类型已经有很多,需要有一个统一的遍历接口来遍历所有的数据类型。Object 不是有序集合,可以用 Map 代替。
  4. ES6 Iterator 具有 [Symbol.iterator] 属性,属性值是函数,执行函数返回一个迭代器。这个迭代器就有 next
    方法可顺序迭代子元素,可以运行 Array.prototype[Symbol.iterator] 来测试。
  5. ES6 Iterator 与 Generator 的区别是 Iterator 的价值是不限于上述几个类型的遍历,还有 Generator
    函数的使用。只要返回的数据符合 Iterator 接口的要求,就可以使用 Iterator 的语法,这就是迭代器模式。
  6. 迭代器模式的设计原则验证,迭代器对象和目标对象分离,迭代器将使用者与目标对象隔离开,符合开放封闭原则。

迭代器模式的代码,如下所示:

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、付费专栏及课程。

余额充值