在决定调用哪个方法时,如何避免if.else(或任何条件语句)



如何在不违反LSP的情况下遵循打开-关闭原则,同时决定在静态类型语言中使用不同参数调用哪个方法?

考虑类似的要求

  • 操作1:对表1 执行DB操作

  • 动作2:根据输入对表2执行DB操作

  • 行动3:什么都不做

上述要求的代码看起来像

process(obj) {

if(obj.type === action1) {
db.updateTable1()
}
if(obj.type === action2) {
db.updateTable2(obj.status)
}
if(obj.type === action3) {
//May be log action 3 recieved
}
}

在上面的代码中,通过将if语句的主体移动到方法并维护一个以action为名称的键映射,找到了一种遵循OCP的方法来执行其他操作。参考

然而,感觉解决方案违反了OCP,因为包装第一个if块的内容的方法将不接收任何参数,包装第二个if块将具有参数的内容的第二个方法。

要么强制所有方法在遵循OCP但违反LSP的权衡中遵循相同的签名,要么放弃OCP本身,从而使用multi-if语句。

一个简单的解决方案是定义一个策略,执行当前包含在if / else if / else分支中的代码:

interface Strategy {
String getType();
void apply();
}

需要注册的策略:

class Executor {
private Map<String, Strategy> strategies;
void registerStrategy(strategy Strategy) {
strategies.put(strategy.getType(), strategy);
}
void process(obj) {
if (strategies.containsKey(obj.type)) {
// apply might execute db.updateTable1(),
// depending on the interface's implementation
strategies.get(obj.type).apply();
} else {
System.out.println("No strategy registered for type: " + obj.type);
}
}
}

不幸的是,当你在Java、C++、C#等中使用OOP时,你必须处理你所认识到的权衡,因为系统是动态组合在一起的,而SOLID在某种程度上解决了缺陷。但SOLID原则旨在提供指导,我不会习惯性地遵循它们。

我希望能找到一个比我自己更优秀的程序员来演示命令模式的例子。但我只是发现了一些非常糟糕的例子,这些例子并没有真正解决你的问题。

定义将意图(定义为字符串或枚举、按钮单击(与操作(对象、lambda函数(关联的问题总是需要我们必须处理的间接级别。一些抽象层是可以接受的,例如:永远不要直接在视图中调用模型或服务。您还可以考虑实现am事件调度器和相应的侦听器,这将有助于松耦合。但在较低级别,你必须查找所有听众。。。

obj的性质是不明确的,但我建议拥有一个定义良好的接口,并将其传递到整个代码中,其中接口的类实现将等效于您的"操作"。以下是Typescript中的一个示例:

interface someDBInterface {
performAction() : void;
}
function process(obj : someDBInterface) {
let result = obj.performAction();
}
class action1 implements someDBInterface {
status: any
performAction() {
//db.updateTable1();
}
}
class action2 implements someDBInterface {
status : any
performAction() {
//db.updateTable1(this.status);
}
}
class action3 implements someDBInterface {
performAction() {
//May be log action 3 recieved
}
}

如果这不符合您的要求,请随时联系:(

最新更新