用谓词列表替换条件列表(if/switch/ternary 运算符)的优缺点是什么?
What are the pros and cons of replacing a list of conditionals(if/switch/ternary operators) with a predicate list?
最近我遇到了一个主张用其他东西(多态性,策略,访问者)替换条件(if/switch/ternary运算符,下同)的思想流派等)。
因为我想通过尝试新方法来学习,所以我修改了我的一些 Javascript 代码并立即找到了一个相关案例,它基本上是以下 ifs 列表(本质上是与 switch/nested 三元运算符相同):
function checkResult(input) {
if (isCond1Met(input)) return result1;
if (isCond2Met(input)) return result2;
if (isCond3Met(input)) return result3;
// More conditionals here...
if (isCondNMet(input)) return resultN;
return defaultResult;
};
在我想到尝试使用谓词列表后不久。
假设 checkResult 总是 return 一个字符串(这适用于我的具体情况),上面的 ifs 列表可以替换为谓词列表(它使用箭头函数并找到哪些是 ES6+ 特性) ):
var resultConds = {
result1: isCond1Met,
result2: isCond2Met,
result3: isCond3Met,
// More mappings here...
resultN: isCondNMet
};
var results = Object.keys(resultConds);
function checkResult(input) {
return results.find(result => resultConds[result](input)) || defaultResult;
};
(旁注:checkResult是否应该将resultConds和defaultResult作为参数在这里应该是一个相对较小的问题,下同)
如果上述假设不成立,谓词列表可以改为:
var conds = [
isCond1Met,
isCond2Met,
isCond3Met,
// More predicates here...
isCondNMet
];
var results = [
result1,
result2,
result3,
// More results here...
resultN
];
function checkResult(input) {
return results[conds.findIndex(cond => cond(input))] || defaultResult;
};
更大的重构可能是这样的:
var condResults = {
cond1: result1,
cond2: result2,
cond3: result3,
// More mappings here...
condN: resultN,
};
var conds = Object.keys(condResults);
function checkResult(input) {
return condResults[conds.find(cond => isCondMet[cond](input))] || defaultResult;
};
我想问一下用谓词列表替换条件列表的优缺点(最好有相关经验和解释),至少在这种情况下(例如:输入验证检查return基于条件列表的非布尔结果)?
例如,哪种方法通常可能会更好:
- 可测试性(如单元测试)
- 可扩展性(当有越来越多的时候conditionals/predicates)
- 可读性(对于那些熟悉这两种方法以确保足够公平比较的人)
- Usability/Reusability(avoiding/reducing 代码重复)
- 灵活性(例如,当用于验证输入的内部较低级别逻辑发生巨大变化,同时保留相同的外部较高级别行为时)
- 内存footprint/Time性能(特定于Javascript)
- 等等
此外,如果您认为谓词列表方法可以改进,请随时展示该改进方法的优缺点。
编辑:正如@Bergi 提到的 Javascript 对象是无序的,ES6+ 地图可能是更好的选择:)
一般来说,将业务逻辑(如这些谓词)放在单独的对象中总能提高可测试性、可伸缩性、可读性、可维护性和可重用性。这来自此 OOP 设计固有的模块化,并允许您将这些谓词保存在中央存储中,并在它们上应用您想要的任何业务过程,保持独立于您的代码库。本质上,您将这些条件 视为数据 。您甚至可以动态选择它们,根据自己的喜好对其进行变换,并在抽象层上使用它们。
当您需要花费一定的时间用通用方法替换简单的 a short 条件时,可读性可能会受到影响,但如果您有很多谓词,它会很划算。
adding/changing/removing 谓词的灵活性提高了很多,但是选择不同架构(如何应用哪种谓词)的灵活性会变差 - 你不能只在一个小地方更改代码,你需要触摸每个使用谓词的位置。
内存和性能占用空间也会更大,但还不够重要。
关于可扩展性,只有选择好的架构才有效。需要以线性方式应用的规则列表在一定大小下可能不再适用。
我在这方面非常菜鸟,关于可读性和可用性我更喜欢后者,但这是个人喜好,我通常是倒退的,所以你不应该听我的。
条件方法更可移植,我的意思是很容易移植到非面向对象的语言。但这可能永远不会发生,即使发生了,做这类事情的人可能有工具和经验,所以这应该不是问题。关于性能,我怀疑会有任何显着差异,第一种看起来像分支,第二种像随机访问。
但正如我所说,你不应该听我的,因为我只是在猜测
最近我遇到了一个主张用其他东西(多态性,策略,访问者)替换条件(if/switch/ternary运算符,下同)的思想流派等)。
因为我想通过尝试新方法来学习,所以我修改了我的一些 Javascript 代码并立即找到了一个相关案例,它基本上是以下 ifs 列表(本质上是与 switch/nested 三元运算符相同):
function checkResult(input) {
if (isCond1Met(input)) return result1;
if (isCond2Met(input)) return result2;
if (isCond3Met(input)) return result3;
// More conditionals here...
if (isCondNMet(input)) return resultN;
return defaultResult;
};
在我想到尝试使用谓词列表后不久。
假设 checkResult 总是 return 一个字符串(这适用于我的具体情况),上面的 ifs 列表可以替换为谓词列表(它使用箭头函数并找到哪些是 ES6+ 特性) ):
var resultConds = {
result1: isCond1Met,
result2: isCond2Met,
result3: isCond3Met,
// More mappings here...
resultN: isCondNMet
};
var results = Object.keys(resultConds);
function checkResult(input) {
return results.find(result => resultConds[result](input)) || defaultResult;
};
(旁注:checkResult是否应该将resultConds和defaultResult作为参数在这里应该是一个相对较小的问题,下同)
如果上述假设不成立,谓词列表可以改为:
var conds = [
isCond1Met,
isCond2Met,
isCond3Met,
// More predicates here...
isCondNMet
];
var results = [
result1,
result2,
result3,
// More results here...
resultN
];
function checkResult(input) {
return results[conds.findIndex(cond => cond(input))] || defaultResult;
};
更大的重构可能是这样的:
var condResults = {
cond1: result1,
cond2: result2,
cond3: result3,
// More mappings here...
condN: resultN,
};
var conds = Object.keys(condResults);
function checkResult(input) {
return condResults[conds.find(cond => isCondMet[cond](input))] || defaultResult;
};
我想问一下用谓词列表替换条件列表的优缺点(最好有相关经验和解释),至少在这种情况下(例如:输入验证检查return基于条件列表的非布尔结果)?
例如,哪种方法通常可能会更好:
- 可测试性(如单元测试)
- 可扩展性(当有越来越多的时候conditionals/predicates)
- 可读性(对于那些熟悉这两种方法以确保足够公平比较的人)
- Usability/Reusability(avoiding/reducing 代码重复)
- 灵活性(例如,当用于验证输入的内部较低级别逻辑发生巨大变化,同时保留相同的外部较高级别行为时)
- 内存footprint/Time性能(特定于Javascript)
- 等等
此外,如果您认为谓词列表方法可以改进,请随时展示该改进方法的优缺点。
编辑:正如@Bergi 提到的 Javascript 对象是无序的,ES6+ 地图可能是更好的选择:)
一般来说,将业务逻辑(如这些谓词)放在单独的对象中总能提高可测试性、可伸缩性、可读性、可维护性和可重用性。这来自此 OOP 设计固有的模块化,并允许您将这些谓词保存在中央存储中,并在它们上应用您想要的任何业务过程,保持独立于您的代码库。本质上,您将这些条件 视为数据 。您甚至可以动态选择它们,根据自己的喜好对其进行变换,并在抽象层上使用它们。
当您需要花费一定的时间用通用方法替换简单的 a short 条件时,可读性可能会受到影响,但如果您有很多谓词,它会很划算。
adding/changing/removing 谓词的灵活性提高了很多,但是选择不同架构(如何应用哪种谓词)的灵活性会变差 - 你不能只在一个小地方更改代码,你需要触摸每个使用谓词的位置。
内存和性能占用空间也会更大,但还不够重要。
关于可扩展性,只有选择好的架构才有效。需要以线性方式应用的规则列表在一定大小下可能不再适用。
我在这方面非常菜鸟,关于可读性和可用性我更喜欢后者,但这是个人喜好,我通常是倒退的,所以你不应该听我的。
条件方法更可移植,我的意思是很容易移植到非面向对象的语言。但这可能永远不会发生,即使发生了,做这类事情的人可能有工具和经验,所以这应该不是问题。关于性能,我怀疑会有任何显着差异,第一种看起来像分支,第二种像随机访问。
但正如我所说,你不应该听我的,因为我只是在猜测