遇到一道设计模式的面试题,各位大佬看下如何解决,题目要求是优化这段业务代码?

遇到一道设计模式的面试题,各位大佬看下如何解决,题目要求是优化这段业务代码
条件是布尔值或者函数返回值,cb 是函数

function runTask() {
  if(条件A){
    cbA()
    if(条件B){
      cbB()
    }
  }
  if(条件C){
    cbC()
    if(条件D){
      cbD()
    }
  }
}
阅读 15k
27 个回答
function runTask() {
  if(条件A) cbA()
  if(条件A && 条件B) cbB()
  if(条件C) cbC()
  if(条件C && 条件D) cbD()
}

优化的方向有给吗?

我暂时想不出什么优化方案了,蹲一波。

这个方向是简洁性(但是可读性并不好):

function runTask() {
  条件A && (cbA(), 条件B && cbB());
  条件C && (cbC(), 条件D && cbD());
}

这个方向是拓展性:

function runTask(params) {
  const items = [
    {
      validator: (params) => 条件A,
      func: () => {
        // cbA
      },
    },
    {
      validator: (params) => 条件A && 条件B,
      func: () => {
        // cbB
      },
    },
    {
      validator: (params) => 条件C,
      func: () => {
        // cbC
      },
    },
    {
      validator: (params) => 条件C && 条件D,
      func: () => {
        // cbD
      },
    },
  ];

  items.forEach((item) => {
    if (item.validator(params)) {
      item.func();
    }
  });
}
function runTask() {
    ;(
        [
            [conditionA, cbA],
            [conditionA && conditionB, cbB],
            [conditionC, cbC],
            [conditionC && conditionD, cbD]
        ] as const
    ).forEach(([condition, callback]) => condition && callback())
}

老实说,从题目上完全看不出优化的方向。

上面几个答案我感觉有点为了【优化】而【优化】,在实际工作中,我宁可接手的代码是最开始的···

function A() {
  console.log("execute task A");
}
function B() {
  console.log("execute task B");
}
function C() {
  console.log("execute task C");
}
function D() {
  console.log("execute task D");
}
function runTask() {
  const conditionA = () => true;
  const conditionB = () => false;
  const conditionC = () => false;
  const conditionD = () => true;
  const processFlows = [
      [
        [conditionA, A],
        [conditionB, B]
      ],
      [
        [conditionC, C],
        [conditionD, D]
      ] 
    ];
  
  for(const flow of processFlows) {
    for(const [condition, task] of flow) {
      if(condition()) task();
      else break;
    }
  }
}

这样拓展性应该会好一些,每个判断也能独立

let is_True = true;
let is_False = false;
const cbA = () => console.log("cbA");
const cbB = () => console.log("cbB");
const cbC = () => console.log("cbC");
const cbD = () => console.log("cbD");
function runTask() {
  const validationSet = {
    A: () => true,
    B: { precondition: "A", selfCheck: () => true },
    C: is_True,
    D: { precondition: "C", selfCheck: is_False },
  };
  const isConditionMet = (type) => {
    const validator = validationSet[type];

    function notObject(validator) {
      if (typeof validator === "function") return validator();
      if (typeof validator === "boolean") return validator;
      throw new Error("无效validator", validator);
    }

    if (typeof validator === "object") {
      const { precondition, selfCheck } = validator;
      if (!isConditionMet(precondition)) return false;
      return notObject(selfCheck);
    } else {
      return notObject(validator);
    }
  };

  const pendingFunctions = [
    ["A", cbA],
    ["B", cbB],
    ["C", cbC],
    ["D", cbD],
  ];
  pendingFunctions.forEach((item) => {
    const [validatorType, _function] = item;
    isConditionMet(validatorType) && _function();
  });
}
runTask();

将判断和运行的部分抽离出来作为一个单独的部分

function check(cond,func){
    if(cond){
        func();
    }
    return cond;
}

例子中的函数可以优化成这样:

function runTask() {
    const condA = check(条件A,cbA);
    const condB = check(condA && 条件B,cbA);
    const condC = check(条件C,cbC);
    const condD = check(condC && 条件D,cbA);
}

之所以把分支条件保存下来,是因为方便复用。
比如要在条件D下加入条件E和条件F,可以这样做:

    const condE = check(condD && 条件E, cbE);
    const condF = check(condD && 条件F, cbF);

这么一小段代码优化效果不明显,来一段长代码更能看出效果:

function runTask() {
  if (条件A) {
    cbA();
    if (条件B) {
      cbB();
      if (条件E) {
        cbE();
        if (条件F) {
          cbF();
          if (条件G) {
            cbG();
          }
        }
      }
      if (条件H) {
        cbH();
        if (条件I) {
          cbI();
        }
      }
      if (条件L) {
        cbL();
      }
    }
    if (条件M) {
      cbM();
      if (条件N) {
        cbN();
      }
    }
  }
  if (条件C) {
    cbC()
    if (条件D) {
      cbD();
      if (条件J) {
        cbJ();
        if (条件K) {
          cbK();
        }
      }
    }
  }
}

优化为:

function runTask() {
  //为了代码整齐,添加一个基础的条件
  const cond0 = true;
  const condA = check(cond0 && 条件A, cbA);
  const condB = check(condA && 条件B, cbB);
  const condC = check(cond0 && 条件C, cbC);
  const condD = check(condC && 条件D, cbD);
  const condE = check(condB && 条件E, cbE);
  const condF = check(condE && 条件F, cbF);
  const condG = check(condF && 条件G, cbG);
  const condH = check(condB && 条件H, cbH);
  const condI = check(condH && 条件I, cbI);
  const condJ = check(condD && 条件J, cbJ);
  const condK = check(condJ && 条件K, cbK);
  const condL = check(condB && 条件L, cbL);
  const condM = check(condA && 条件M, cbM);
  const condN = check(condM && 条件N, cbN);
}

可以看到,通过指定父分支条件的方式,把缩进优化掉了,代码整洁度up。
归根结底,是把代码从树结构优化为了列表结构。

——————————————更新——————————————

优化大段if else的场景算是很常见的,因此我将方案进行了优化。
核心思想就是使用元编程,将编写的元信息组装为函数。
提供的元信息是一个长成这样的对象:

{
  "A": [null, "then", flagA, thenA],
  "B": ["A" , "then", flagB, thenB],
}

它描述的if代码块是这样的

if(flagA()){
  thenA()
  if(flagB()){
    thenB()
  }
}

元信息的具体结构如下(使用TypeScript描述):

type IfKey = string
type Parent = IfKey | null
type Branch = "then" | "else"
type Flag = () => boolean
type Then = () => void
type Else = () => void
type MetaIf = [Parent, Branch, Flag, Then?, Else?]
type MetaCode = {
  [key: IfKey]: MetaIf
}

元信息是一个对象(MetaCode),该对象的键(IfKey)表示一个if块的键,对象的值表示这个if块的元信息(MetaIf),是一个数组,各个元素的含义如下:
0(Parent):表示父if块的键,为空表示是一个根元素
1(Branch):表示位于父if块的哪个分支————then或者else
2(Flag):一个函数,返回值为布尔值,用于判断进入哪个分支
3(Then):Flag判断为true时,执行的回调函数,可为空
4(Else):Flag判断为false时,执行的回调函数,可为空
使用元信息书写代码后,需要将其转换为函数。大致的流程是:
根据每个if块中记录的父if块的键,构建if块的树
调用时,从根if块开始处理,先运行判断函数,根据判断结果调用该分支的回调函数,接着递归处理该分支下的子if块
可直接使用的代码如下:

function complieMetaIf(metaCode) {
  const metaRoot = {
    flag: () => true,
    then: [],
    else: []
  }
  const metaMap = {};
  for (let [k, v] of Object.entries(metaCode)) {
    metaMap[k] = {
      flag: v[2],
      funcThen: v[3],
      funcElse: v[4],
      then: [],
      else: []
    }
  }
  for (let [k, v] of Object.entries(metaCode)) {
    const parent = v[0] ? metaMap[v[0]] : metaRoot;
    parent[v[1]].push(metaMap[k]);
  }
  function runMeta(meta) {
    if (meta.flag?.()) {
      meta.funcThen?.();
      meta.then.forEach(runMeta);
    } else {
      meta.funcElse?.();
      meta.else.forEach(runMeta);
    }
  }
  return () => runMeta(metaRoot);
}

优化案例:

function runTask(){
  if (flagA()) {
    thenA();
    if (flagB()) {
      thenB();
    } else {
      elseB();
    }
  } else if (flagC()) {
    thenC();
    if (flagD()) {
      thenD();
    }
  } else {
    elseC();
    if (flagE()) {
      thenE();
    } else {
      elseE();
    }
  }
}

与如下代码效果相同:

//为了对齐代码,满足强迫症
const nil = null;
const runTask = complieMetaIf({
  A: [nil, "then", flagA, thenA],
  B: ["A", "then", flagB, thenB, elseB],
  C: ["A", "else", flagC, thenC, elseC],
  D: ["C", "then", flagD, thenD],
  E: ["C", "else", flagE, thenE, elseE],
})

可以执行以下代码进行测试,在浏览器空白页面按F12打开控制台,直接粘贴代码,敲下回车即可运行。

//编译if代码元信息
function complieMetaIf(metaCode) {
  const metaRoot = {
    flag: () => true,
    then: [],
    else: []
  }
  const metaMap = {};
  for (let [k, v] of Object.entries(metaCode)) {
    metaMap[k] = {
      flag: v[2],
      funcThen: v[3],
      funcElse: v[4],
      then: [],
      else: []
    }
  }
  for (let [k, v] of Object.entries(metaCode)) {
    const parent = v[0] ? metaMap[v[0]] : metaRoot;
    parent[v[1]].push(metaMap[k]);
  }
  function runMeta(meta) {
    if (meta.flag?.()) {
      meta.funcThen?.();
      meta.then.forEach(runMeta);
    } else {
      meta.funcElse?.();
      meta.else.forEach(runMeta);
    }
  }
  return () => runMeta(metaRoot);
}

//mock函数
const flags = [true, true, true, true, true];
let logs = ""
const flagA = () => flags[0];
const flagB = () => flags[1];
const flagC = () => flags[2];
const flagD = () => flags[3];
const flagE = () => flags[4];

const thenA = () => logs += "thenA;";
const thenB = () => logs += "thenB;";
const thenC = () => logs += "thenC;";
const thenD = () => logs += "thenD;";
const thenE = () => logs += "thenE;";

const elseA = () => logs += "elseA;";
const elseB = () => logs += "elseB;";
const elseC = () => logs += "elseC;";
const elseD = () => logs += "elseD;";
const elseE = () => logs += "elseE;";

//原本的流程
const runTask1 = () => {
  if (flagA()) {
    thenA();
    if (flagB()) {
      thenB();
    } else {
      elseB();
    }
  } else if (flagC()) {
    thenC();
    if (flagD()) {
      thenD();
    }
  } else {
    elseC();
    if (flagE()) {
      thenE();
    } else {
      elseE();
    }
  }
}
//优化后的流程
//为了对齐代码,满足强迫症
const nil = null;
const runTask2 = complieMetaIf({
  A: [nil, "then", flagA, thenA],
  B: ["A", "then", flagB, thenB, elseB],
  C: ["A", "else", flagC, thenC, elseC],
  D: ["C", "then", flagD, thenD],
  E: ["C", "else", flagE, thenE, elseE],
})
//测试过程
function test() {
  let total = 0;
  let pass = 0;
  let fail = 0;
  //用于遍历flags的所有可能的取值
  function recursion(index) {
    if (index > 4) {
      total++;
      logs = "";
      runTask1();
      let logs1 = logs;
      logs = "";
      runTask2();
      let logs2 = logs;
      if (logs1 === logs2) {
        pass++;
        console.log("pass:", flags, logs1, logs2);
      } else {
        fail++;
        console.log("fail:", flags, logs1, logs2);
      }
    } else {
      flags[index] = true;
      recursion(index + 1);
      flags[index] = false;
      recursion(index + 1);
    }
  }
  recursion(0);
  console.log("total: " + total + " ,pass: " + pass + " ,fail: " + fail);
}

test();

总结:
我所理解的元编程是这样一种编程风格————编写元信息和编译过程,通过运行时编译得到结果。
并且元信息同样可以是用函数生产出来的,这样就能够进行进一步模块化代码。
根据这样的思想,使用complieMetaIf,可以将几乎所有if代码扁平化,从而消除嵌套和缩进。
——————————————更新——————————————
将编写元信息和编译过程割裂的话,有点过度封装了,主要是父If块和分支名都是字符串,不易维护。因此提供一种新的风格:在编写元信息的同时也进行编译,以此提高对代码的控制力。
具体来说,使用如下代码来生成一个if块,并且加入父分支中。

function makeIf(parent, flag, then, Else) {
  const ans = {
    flag: flag,
    then: then ? [then] : [],
    else: Else ? [Else] : [],
    run: () => {
      if (ans.flag()) {
        ans.then.forEach(f => f())
      } else {
        ans.else.forEach(f => f())
      }
    }
  };
  parent?.push(ans.run)
  return ans
}

题目中的代码可以整理为如下形式:

const runTask = (() => {
  const code0 = makeIf(null, () => true);
  const codeA = makeIf(code0.then, flagA, thenA);
  const codeB = makeIf(codeA.then, flagB, thenB);
  const codeC = makeIf(code0.then, flagC, thenC);
  const codeD = makeIf(codeC.then, flagD, thenD);
  return code0.run;
})()

上一次更新中的runTask2可以写成这样的形式:

const runTask3 = (() => {
  const code0 = makeIf(null, () => true)
  const codeA = makeIf(code0.then, flagA, thenA);
  const codeB = makeIf(codeA.then, flagB, thenB, elseB);
  const codeC = makeIf(codeA.else, flagC, thenC, elseC);
  const codeD = makeIf(codeC.then, flagD, thenD);
  const codeE = makeIf(codeC.else, flagE, thenE, elseE);
  return code0.run
})()

总之,具体使用什么风格,还是得结合具体的应用场景来判断,
像题主这样的简单情形,都不需要特地进行优化。
需要易于修改的代码的话,可以使用编写与编译混合的风格。
需要高度封装的代码的话,可以使用编写与编译分离的风格。
软件工程没有银弹,一次就把代码写好是不现实的,保证代码可以被理解和重构,并且经常重构代码以适应当下的场景,或许才是正解。
总之,唯一不变的,就是变化本身。

就这段代码,似乎没有优化的必要,这个逻辑清晰而且没有冗余。但是既然是设计模式的题的,大概是希望用策略模式来解决这个问题,便于扩展。

根据代码,可以分析几个函数的执行条件:

条件A: cbA()
条件A&条件B: dbB()
条件C: cbC()
条件C&条件D: dbD()

把它处理成策略表,可以用映射表,也可以用键值对或对象列表

const list = [
    [() => 条件A, () => cbA()],
    [() => 条件A && 条件B, () => cbB()],
    [() => 条件C, () => cbC()],
    [() => 条件C && 条件D, cbD()],
]

执行策略

list.forEach(([condition, fn]) => {
    if (condition()) { fn(); }
});

策略总量不大的情况下,也可以先过滤再执行

list.filter(([c]) => c()).forEach(([,fn]) => fn());

另外还有一点可以

应该是考察的 IIFE 吧,改用立即执行函数优化.

首先条件AB、条件CD的判断相互独立,且逻辑是相同的,抽取重复逻辑,修改如下:

function runTaskForCondition(cond1, cond2, func1, func2) {
  if (cond1) {
    func1()
    if (cond2) {
      func2()
    }
  }
}
// 例如
function cb(tag) {
  console.log(tag);
} 
runTaskForCondition(条件A,条件B,() => cb('A'), () => cb('B'))
runTaskForCondition(条件C,条件D,() => cb('C'), () => cb('D'))

然后改为立即执行函,修改如下:

var runTask = (function(cond1, cond2, func1, func2) {
  if (cond1 && cond2) {
    return function() {
      func1()
      func2()
    }
  } else if (cond1) {
    return function() {
      func1()
    }
  } else {
    return function() {}
  }
})
// 例如
function cb(tag) {
  console.log(tag);
}
var taskAB = runTask(条件A, 条件B, () => cb('A'), () => cb('B'))
var taskCD = runTask(条件C, 条件D, () => cb('C'), () => cb('D'))
taskAB()
taskCD()

改用立即执行函数之后,各个条件判断只执行一次,后续调用 taskAB / taskCD 则会直接返回符合当前环境条件的函数,避免了重复的判断分支,节省了性能开销。

而源代码在调用时会依次进行4个分支判断,单独看没什么问题,但是具体的软件或者网站中,这些条件可能不会频繁变化,如果作为一个公用方法,或放入一个大数组循环执行,就会进行很多无用的判断分支,产生了额外的性能开销。

例如条件ABCD,AB是判断的服务器版本,v1执行A,v2执行AB,CD是判断的某SDK版本,sdk1执行C,sdk2执行CD,而这些条件在软件初始化时就已经确定,不需在重复判断。不知道我这么举例是否说清楚了。

但如果条件ABCD在软件运行周期中频繁变化,就不太适用于这个方案了,个人拙见仅供参考。


// 定义执行逻辑
const strategies = {
  callbackA: () => console.log('cbA'),
  callbackB: () => console.log('cbB'),
  callbackC: () => console.log('cbC'),
  callbackD: () => console.log('cbD'),
};

// 定义执行条件
const taskConfig = {
  A: true,
  B: true,
  C: true,
  D: true,
};

// 使用观察者模式执行命令,添加,执行
class CommandManager {
  constructor() {
    this.commands = [];
  }

  addCommand(command) {
    this.commands.push(command);
  }

  executeCommands() {
    this.commands.forEach((command) => command());
  }
}

// 执行
const runTask = () => {
  const commandManager = new CommandManager();

  if (taskConfig['A']) {
    commandManager.addCommand(strategies['callbackA']);
    if (taskConfig['B']) {
      commandManager.addCommand(strategies['callbackB']);
    }
  }

  if (taskConfig['C']) {
    commandManager.addCommand(strategies['callbackC']);
    if (taskConfig['D']) {
      commandManager.addCommand(strategies['callbackD']);
    }
  }

  commandManager.executeCommands();
};

runTask();

function runTask() {

if(条件A) cbA();
if(条件A && 条件B) cbB();
if(条件C) cbC();
if(条件C && 条件D) cbD();

}

从题目看不出优化点,有可能是你脱敏的时候搞丢了。

职责单一原则:首先,可以考虑将条件判断和任务执行分开,让代码更清晰易读。
策略模式:可以将每个条件和对应的回调函数封装成单独的对象或数据结构,比如一个对象数组,然后通过遍历这个数组并执行相应的操作来替代多重嵌套判断。
函数组合:如果条件和回调函数之间没有明确的依赖关系(即条件B不依赖于条件A的执行结果,条件D不依赖于条件C的执行结果),可以将所有条件和回调函数放入一个统一的管理结构中,然后使用函数式编程中的compose或者pipe函数进行优化。
下面是一种可能的优化方案:

// 定义任务对象,包含条件与回调函数
class Task {
  constructor(condition, callback) {
    this.condition = condition;
    this.callback = callback;
  }

  shouldRun() {
    return typeof this.condition === 'function' ? this.condition() : this.condition;
  }

  execute() {
    if (this.shouldRun()) {
      this.callback();
    }
  }
}

// 创建任务列表
const tasks = [
  new Task(条件A, () => { cbA(); }),
  new Task(条件B, () => { cbB(); }),
  new Task(条件C, () => { cbC(); }),
  new Task(条件D, () => { cbD(); }),
];

// 遍历任务列表执行
tasks.forEach(task => task.execute());

这样,当有新的条件和回调函数加入时,只需创建新的Task对象添加到tasks数组中即可,提高了代码的可维护性和扩展性。但需要注意的是,这种方式并不能处理条件间存在依赖关系的情况,对于这种情况,可能还需要根据实际逻辑调整优化方案。

这代码不就是好代码嘛 清晰简明 维护也好维护

你说的优化应该是同步异步吧

function async runTask() {
  if(await 条件A){
    await cbA()
    if(await 条件B){
      cbB()
    }
  }
  if(await 条件C){
    await cbC()
    if(条件D){
      cbD()
    }
  }
}

你可以看看这个方案,不知道符不符合优化条件

function runTask(parameter) {
    switch (parameter) {
        case "D":
            cbD()
        case "C":
            cbC()
            break;
        case "B":
            cbB()
        case "A":
            cbA()
            break;
    }
}

function cbA() {
    console.log("A")
}

function cbB() {
    console.log("B")
}

function cbC() {
    console.log("C")
}

function cbD() {
    console.log("D")
}
runTask("B")
新手上路,请多包涵

提供两个切入点:
1.业务逻辑优化:

function runTask() {
if(条件A)cbA()
if(条件A && 条件B)cbB()
if(条件C)cbC()
if(条件C && 条件D)cbD()
}

2.业务执行优化

function runTask() {
let funList = [];
if(条件A){cbA(); funList .push(cbA)}
if(条件A && 条件B){cbB(); funList .push(cbB)}
if(条件C){cbC(); funList .push(cbC)}
if(条件C && 条件D){cbD(); funList .push(cbD)}
return () => {
    funcList.forEach(cb => cb())
    }
}
const runTaskB = runTask()
runTaskB()
runTaskB()
runTaskB()...

在我看来唯一的优化点就是尽早 return 了

新手上路,请多包涵

其实,一看方法抽取是很有必要的:

function fun(条件1,cb1,条件2,cb2){
  if(条件1)
      cb1()
  if(条件2)
      cb2()
}
function runTask() {
  fun(条件A,cbA,条件B,cbB)
  fun(条件C,cbC,条件D,cbD)
}

当然,上面的代码简单看是没啥可优化的了,但如果存在判断条件存在更多层呢,那且不是又要写很多if?,所以可以增加点代码,虽然看似代码复杂了一点点,但耐用

function fun(obj){
  if(obj.条件)
      obj.cb()
  if(obj.children)
      fun(obj.children)
}
function item(_条件,_cb,_children){
    return {
         "条件": _条件,
          "cb": _cb,
          "children": _children
        }
}
function runTask() {
  fun(item(条件A,cbA, item(条件B,cbB)))
  fun(item(条件C,cbC, item(条件D,cbD)))
}

现在不管代码有多少层判断条件执行方法都是固定的,不过还有一个问题,那就是runTask()里相似的代码我们依然写了两遍,所以继续抽写:

 function fun(obj) {
        if (obj.条件)
            obj.cb()
        if (obj.children)
            fun(obj.children)
    }
    function funRun(...objs) {
        objs.forEach(fun)
    }
    function item(_条件,_cb,_children){
        return {
             "条件": _条件,
              "cb": _cb,
              "children": _children
            }
    }
    function runTask() {
        funRun(item(条件A,cbA, item(条件B,cbB)), item(条件C, cbC, item(条件D, cbD)))
    }

这两种哪一个更好?仁者见仁,智者见智

if(条件A) cbA();
if(条件A && 条件B) cbB();
if(条件C) cbC();
if(条件C && 条件D) cbD();

VS

 if(条件A){
    cbA()
    if(条件B){
      cbB()
    }
  }
  if(条件C){
    cbC()
    if(条件D){
      cbD()
    }
  }
新手上路,请多包涵
function executeIf(condition, callback) {
  if (condition) {
    callback();
  }
}

function runTask() {
  const tasks = [
    { condition: 条件A, callback: cbA },
    { condition: 条件B && 条件A, callback: cbB }, // 确保条件A为真时才检查条件B
    { condition: 条件C, callback: cbC },
    { condition: 条件D && 条件C, callback: cbD } // 确保条件C为真时才检查条件D
  ];

  tasks.forEach(task => {
    executeIf(task.condition, task.callback);
  });
}
function RunTask(tasks) {
  let composeList = Array.isArray(tasks) ? tasks : [tasks];
  composeList.forEach((compose) => {
    if (compose.condition) {
      compose.task();
      if (compose?.child?.length > 0) {
        compose.child.forEach((item) => {
          RunTask(item);
        });
      }
    }
  });
}

let c = {
  condition: true,
  task: () => {
    console.log("cbA");
  },
  child: [
    {
      condition: true,
      task: () => {
        console.log("cbB");
      },
      child: [
        {
          condition: false,
          task: () => {
            console.log("cbD");
          },
        },
        {
          condition: true,
          task: () => {
            console.log("cbC");
          },
        },
      ],
    },
  ],
};
let d = [
  {
    condition: true,
    task: () => {
      console.log("cbA");
    },
    child: [
      {
        condition: true,
        task: () => {
          console.log("cbB");
        },
      },
    ],
  },
  {
    condition: true,
    task: () => {
      console.log("cbC");
    },
    child: [
      {
        condition: true,
        task: () => {
          console.log("cbD");
        },
      },
    ],
  },
];

RunTask(c);
RunTask(d);

这样?

楼上的回答都是认真的? 这个真的需要弄一个设计模式出来? 难道你们的代码到处都是这样需要你重构? 还不如吧命名好一点好

这不是典型的责任链模式的例子么,参考这个文章: https://refactoringguru.cn/design-patterns/chain-of-responsib...

以下都为伪代码不保证能跑,首先设计一个责任链处理器:

class TaskHandler {
  constructor() {
    this.chain = [];
  }

  addHandler(handler) {
    this.chain.push(handler);
    // 允许链式调用
    return this;
  }

  handle(taskContext) {
    for (const handler of this.chain) {
      handler.handle(taskContext);
    }
  }
}
// 第一组条件
class HandlerA {
  handle(taskContext) {
    if (taskContext.条件A) {
      taskContext.cbA();
      if (taskContext.条件B) {
        taskContext.cbB();
      }
    }
  }
}
// 第二组条件
class HandlerB {
  handle(taskContext) {
    if (taskContext.条件C) {
      taskContext.cbC();
      if (taskContext.条件D) {
        taskContext.cbD();
      }
    }
  }
}
//给出一个上下文
const taskContext = {
  条件A: true,
  条件B: false,
  条件C: true,
  条件D: true,
  cbA: () => console.log("cbA called"),
  cbB: () => console.log("cbB called"),
  cbC: () => console.log("cbC called"),
  cbD: () => console.log("cbD called"),
};
// 运行
function runTask() {
  const handler = new TaskHandler();

  handler
    .addHandler(new HandlerA())
    .addHandler(new HandlerB());

  handler.handle(taskContext);
}

现在有一个 TaskHandler 类来管理处理者链。使用 addHandler 方法动态地将处理者添加到链中。每个处理者(如 HandlerA 和 HandlerB)都是一个独立的类,实现了 handle 方法。

这样,如果将来需要新增处理者,只需创建一个新的处理者类并将其添加到 TaskHandler 的链中即可,无需更改现有代码。例如

class HandlerC {
  handle(taskContext) {
    if (taskContext.条件E) {
      taskContext.cbE();
    }
  }
}

// 添加新的处理者
  handler
    .addHandler(new HandlerA())
    .addHandler(new HandlerB())
    .addHandler(new HandlerC());
后话:但是我觉得目前这个函数没有必要上设计模式、他还没复杂到需要用设计模式拆分的程度
新手上路,请多包涵

有点像责任链加策略模式

    @Test
    public void psvm() {
        Itf fun1 = () -> {
            System.out.println(1);
        };
        Itf fun2 = () -> {
            System.out.println(2);
        };
        Itf fun3 = () -> {
            System.out.println(3);
        };
        Itf fun4 = () -> {
            System.out.println(4);
        };

        boolean cond1 = true;
        boolean cond2 = true;
        boolean cond3 = false;
        boolean cond4 = true;

        Clz clz1 = new Clz(cond1, fun1);
        Clz clz2 = new Clz(cond2, fun2);
        Clz clz3 = new Clz(cond3, fun3);
        Clz clz4 = new Clz(cond4, fun4);

        List<Clz> list1 = List.of(clz1, clz2);
        List<Clz> list2 = List.of(clz3, clz4);
//
        rec(list1.iterator());
        rec(list2.iterator());

//        List<Clz> list = List.of(clz1, clz2, clz3, clz4);
//        rec(list.iterator());
    }

    private void rec(Iterator<Clz> it) {
        Clz next = it.next();
        if (next.isCond()) {
            next.execute();
            if (it.hasNext()) {
                rec(it);
            }
        }
    }

接口如下

interface Itf {

    void execute();
}

@Data
@AllArgsConstructor
class Clz {

    private boolean cond;
    private Itf itf;

    public void execute() {
        itf.execute();
    }
}

难道只有我觉得这是个数据结构问题而不是设计模式问题吗?

type TaskCondition = [boolean | () => boolean, ()=>void];
type TaskConditionGroup = {
  continue: boolean, // 前一个验证失败时是否继续
  taskList: (TaskCondition | TaskConditionGroup)[],
}

// 这样题目中的内容可以转化为以下描述
const condition: TaskConditionGroup = {
  continue: true,
  taskList: [
    {
      continue: false,
      taskList: [[条件A,方法A],[条件B, 方法B]],
    },
    {
      continue: false,
      taskList: [[条件C,方法C],[条件D, 方法D]],
    },
  ]
};

我觉得怎么执行就没必要写了。@边城 边老大的另外还有一点好似没写完,是啥捏?

感觉像是组合模式和策略模式的集合,但是没有方法内容,组合模式用不起来,试试策略模式是否满足你的要求?。

const cbA = (data) => { console.log('A'+data) }
const cbB = (data) => { console.log('B'+data) }
const cbC = (data) => { console.log('C'+data) }
const cbD = (data) => { console.log('D'+data) }
const choose = {
    "A" : function ( data ){
        cbA(data);
    },
    "B" : function ( data){
        cbA(data);
        cbB(data);
    },
    "C" : function ( data ){
        cbC(data);
    },
    "D" : function ( data ){
        cbC(data);
        cbD(data);
    }
}
const runChoose = function( chooseStr, xxx ){
    choose[chooseStr](xxx);
}
runChoose("A","aaa");
runChoose("D",'ddd');
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏