遇到一道设计模式的面试题,各位大佬看下如何解决,题目要求是优化这段业务代码
条件是布尔值或者函数返回值,cb 是函数
function runTask() {
if(条件A){
cbA()
if(条件B){
cbB()
}
}
if(条件C){
cbC()
if(条件D){
cbD()
}
}
}
遇到一道设计模式的面试题,各位大佬看下如何解决,题目要求是优化这段业务代码
条件是布尔值或者函数返回值,cb 是函数
function runTask() {
if(条件A){
cbA()
if(条件B){
cbB()
}
}
if(条件C){
cbC()
if(条件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()...
其实,一看方法抽取是很有必要的:
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();
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');
8 回答4.7k 阅读✓ 已解决
6 回答3.4k 阅读✓ 已解决
5 回答2.8k 阅读✓ 已解决
6 回答2.3k 阅读
5 回答6.3k 阅读✓ 已解决
4 回答2.2k 阅读✓ 已解决
8 回答3.6k 阅读