Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2020/06/08 责任链模式 #42

Open
ChenPt opened this issue Jun 8, 2020 · 0 comments
Open

2020/06/08 责任链模式 #42

ChenPt opened this issue Jun 8, 2020 · 0 comments
Labels
设计模式 设计模式

Comments

@ChenPt
Copy link
Owner

ChenPt commented Jun 8, 2020

日常编写控制逻辑的代码,使用得最多的应该是if elseswitch case了,对于简单的判断条件,且判断条件的可能取值较少,我们可以直接使用if else编写。举个例子

  1. 简单的判断
if (value < 0) return '取值必须大于0'
  1. 简单的判断 - 可能取值较多
let result = ''
switch(value) {
  case 'A':
    result = 'Acer'
  break
  case 'B':
    result = 'BiliBili'
  break
  case 'C':
    result = 'Carry'
  break
}
console.log(result)

这两种情况使用if else或者switch case或者表驱动法(Map结构)都比较合适,如果是复杂一点的条件的话,就不太适合。举个例子

let result = ''
if  (type === 'edit' && user === 'A') {
  result = 'editA'
} else if (type === 'edit' && user === 'B') {
  if (age > 20) {
    result = 'editB20'
    return
  }
  result = ' editBLess20'
}

如果后续还需要扩展,需要判断type为new类型的,增加其他条件。或者是判断条件有所改动,这段代码的逻辑就会变得比较不直观,扩展也需要改动到原来的逻辑处理。

let result = ''
if  ((type === 'edit' || type === 'new') && user === 'A') {
  result = 'editA'
} else if (type === 'edit' && user === 'B') {
  if (age > 20) {
    result = 'editB20'
    return
  }
  result = ' editBLess20'
}
return result

分析下这段代码,这段代码简单概括就是根据条件取得对应的result,意思就是只要有其中某一个条件符合,则会取得result对应的值并返回。
类似的还有这种代码

let msg = '';
if (!itemCode) {
  msg = '物料编号不能为空'
  return msg
}
if (!qty) {
  msg = '数量不能为空'
  return msg
}
if (!price) {
  msg = '价格不能为空'
  return msg
}
if (!status) {
  msg = '状态不能为空'
  return msg
}

这个例子简单概括也是根据多个字段的值,取得msg,返回。如果是简单地判断某一个字段的值,则可以使用switch case去写,也可以通过Map的形式去写

const map = {
  A: 5,
  B: 4,
  C: 3,
  D: 2,
  E: 1
}
const getValue = value => map[value] || ''

但如果是判断多个字段,或者多个条件耦合的判断,场景比较复杂的,通过if else去实现代码会比较丑且不易读,扩展性也差

责任链模式

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。 -- 菜鸟教程

通常,我们理解中的责任链模式有两种。

  1. 第一种是请求可以被某一个handler处理,处理完之后,将请求继续抛给下一个handler处理。
  2. 请求被某一个handler处理,处理完之后请求并不会向下家传递。

责任链模式,其实我们一直有接触。如DOM的事件冒泡与事件捕获就是一个责任链的设计思想,属于上述的第一种类型。

事件冒泡:一个事件发生,从底层节点往上开始冒泡,当有节点绑定了该事件时,则会触发绑定的回调函数,且事件还会继续往上冒泡,直至最顶层节点。不过手动阻止冒泡事件需要自己编写,event.stopPropagation()

使用责任链模式

设计的接口如下

每一个链条节点都设置了三个字段,result,condition,actionresult为匹配到后返回的结果,condition为匹配的条件,条件为true时,则当前链条节点匹配成功,处理action,并返回结果,停止继续传播。

责任链类。setNext方法可供各个节点串联起来。getResult方法返回匹配到的节点的result参数。

生成规则链的函数,利用reduce方法快速构造

具体应用

数据校验。SN不能为空,且不能为中文,且不能包含感叹号(全/半角),且位数不能小于5

当然,这里完全可以不用构造责任链,由于使用的是数组结构,可以利用这个顺序数据结构的特性,只需根据责任链的思想去编写即可

// 直接用数组方法去编写
export function checkSn(value): {res: boolean, message: string} {
  const dutys = [
    {
      condition: /[\u4e00-\u9fa5]+/g.test(value),
      result: '不能包含中文'
    },
    {
      condition: /\s+/g.test(value),
      result: '不能包含空格'
    },
    {
      condition: /[\!|\!]+/g.test(value),
      result: '不能包含感叹号'
    },
    {
      condition: /^\S{0,4}$/g.test(value),
      result: '长度不能小于5'
    },
    {
      condition: true,
      result: ''
    }
  ];
  const result = dutys.find(duty => duty.condition).result || '';
  // const result = createDutyChain(dutys).getResult();
  return {
    res: !result,
    message: result
  };
}

责任链的优缺点

优点:

  1. 可动态增加或修改handler
  2. 扩展性高
  3. 只需将值传入链条中,然后取得结果,无需关注内部节点的处理逻辑

缺点:

  1. 只能从头到尾按顺序传递
  2. 不能保证请求一定会被处理
@ChenPt ChenPt added the 设计模式 设计模式 label Jun 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
设计模式 设计模式
Projects
None yet
Development

No branches or pull requests

1 participant