天天一个设想形式之定阅-宣布形式

博主按:《天天一个设想形式》旨在开端体会设想形式的精华,现在采纳
javascript(_靠这用饭_)和
python(_地道喜好_)两种言语完成。固然,每种设想形式都有多种完成体式格局,但此小册只纪录最直接了当的完成体式格局 :)

0. 项目地点

1. 什么是“定阅-宣布形式”?

定阅-宣布形式定义了对象之间的一种一对多的依靠关联,当一个对象的状况发作转变时,一切依靠它的对象都能够获得关照。

相识过事宜机制或许函数式编程的朋侪,应该会体会到“定阅-宣布形式”所带来的“时刻解耦”和“空间解耦”的长处。借助函数式编程中闭包和回调的观点,能够很文雅地完成这类设想形式。

2. “定阅-宣布形式” vs 观察者形式

定阅-宣布形式和观察者形式观点类似,但在定阅-宣布形式中,定阅者和宣布者之间多了一层中间件:一个被笼统出来的信息调理中间。

但实在没有必要太穷究 2 者区分,由于《Head First 设想形式》这本典范书都写了:宣布+定阅=观察者形式其中心头脑是状况转变和宣布关照。在此基础上,依据言语特征,举行完成即可。

3. 代码完成

3.1 python3 完成

python 中我们定义一个事宜类Event, 而且为它供应 事宜监听函数、(事宜完成后)触发函数,以及事宜移除函数。任何类都能够经由过程继续这个通用事宜类,来完成“定阅-宣布”功用。

class Event:
  def __init__(self):
    self.client_list = {}

  def listen(self, key, fn):
    if key not in self.client_list:
      self.client_list[key] = []
    self.client_list[key].append(fn)

  def trigger(self, *args, **kwargs):
    fns = self.client_list[args[0]]

    length = len(fns)
    if not fns or length == 0:
      return False

    for fn in fns:
      fn(*args[1:], **kwargs)

    return False

  def remove(self, key, fn):
    if key not in self.client_list or not fn:
      return False

    fns = self.client_list[key]
    length = len(fns)

    for _fn in fns:
      if _fn == fn:
        fns.remove(_fn)

    return True

# 借助继续为对象装置 宣布-定阅 功用
class SalesOffice(Event):
  def __init__(self):
    super().__init__()

# 依据本身需求定义一个函数:供事宜处理完后挪用
def handle_event(event_name):
  def _handle_event(*args, **kwargs):
    print("Price is", *args, "at", event_name)

  return _handle_event


if __name__ == "__main__":
  # 建立2个回调函数
  fn1 = handle_event("event01")
  fn2 = handle_event("event02")

  sales_office = SalesOffice()

  # 定阅event01 和 event02 这2个事宜,而且绑定相干的 完成后的函数
  sales_office.listen("event01", fn1)
  sales_office.listen("event02", fn2)

  # 当两个事宜完成时刻,触发前几行绑定的相干函数
  sales_office.trigger("event01", 1000)
  sales_office.trigger("event02", 2000)

  sales_office.remove("event01", fn1)

  # 打印:False
  print(sales_office.trigger("event01", 1000))

3.2 ES6 完成

JS 中平常用事宜模子来替代传统的宣布-定阅形式。任何一个对象的原型链被指向Event的时刻,这个对象便能够绑定自定义事宜和对应的回调函数。

const Event = {
  clientList: {},

  // 绑定事宜监听
  listen(key, fn) {
    if (!this.clientList[key]) {
      this.clientList[key] = [];
    }
    this.clientList[key].push(fn);
    return true;
  },

  // 触发对应事宜
  trigger() {
    const key = Array.prototype.shift.apply(arguments),
      fns = this.clientList[key];

    if (!fns || fns.length === 0) {
      return false;
    }

    for (let fn of fns) {
      fn.apply(null, arguments);
    }

    return true;
  },

  // 移除相干事宜
  remove(key, fn) {
    let fns = this.clientList[key];

    // 假如之前没有绑定事宜
    // 或许没有指明要移除的事宜
    // 直接返回
    if (!fns || !fn) {
      return false;
    }

    // 反向遍历移除置指定事宜函数
    for (let l = fns.length - 1; l >= 0; l--) {
      let _fn = fns[l];
      if (_fn === fn) {
        fns.splice(l, 1);
      }
    }

    return true;
  }
};

// 为对象动态装置 宣布-定阅 功用
const installEvent = obj => {
  for (let key in Event) {
    obj[key] = Event[key];
  }
};

let salesOffices = {};
installEvent(salesOffices);

// 绑定自定义事宜和回调函数

salesOffices.listen(
  "event01",
  (fn1 = price => {
    console.log("Price is", price, "at event01");
  })
);

salesOffices.listen(
  "event02",
  (fn2 = price => {
    console.log("Price is", price, "at event02");
  })
);

salesOffices.trigger("event01", 1000);
salesOffices.trigger("event02", 2000);

salesOffices.remove("event01", fn1);

// 输出: false
// 申明删除胜利
console.log(salesOffices.trigger("event01", 1000));

4. 参考

    原文作者:心谭
    原文地址: https://segmentfault.com/a/1190000017320174
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞