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

How to avoid if..else(or any conditionals) while deciding which method to be called?

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

考虑

这样的要求

上述要求的代码看起来像

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 语句的主体移动到方法并维护以操作作为名称的键映射,想出了一种在上面的代码中遵循 OCP 以执行其他操作的方法。 Reference

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

它要么强制所有方法在遵循 OCP 但违反 LSP 的权衡中遵循相同的签名,要么放弃 OCP 本身,从而使用多个 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 函数)相关联的问题将始终需要我们必须处理的间接级别。一些抽象层是可以接受的,例如:永远不要直接在视图中调用模型或服务。您还可以考虑实施事件调度程序和相应的侦听器,这将有助于松散耦合。但是在较低的级别上,您必须查找所有听众 ...

obj 的性质不明确,但我建议使用 well-defined 接口并在整个代码中传递它,其中接口的 class 实现等同于 'action'.这是一个在 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
  }
}

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