Java 如何在不违反Liskov替换原则的情况下有效地在类之间共享函数

Java 如何在不违反Liskov替换原则的情况下有效地在类之间共享函数,java,oop,solid-principles,liskov-substitution-principle,Java,Oop,Solid Principles,Liskov Substitution Principle,我有一个代码库,它最初是用许多不同的选项创建的,这些选项允许您让代码以稍微不同的方式执行相同的过程,如下所示: public class MainFunction { public void main(String option){ if (option.equals("vanilla mode")){ this.firstFunction(); }else{ this.differentVersionOfFirstFunction();

我有一个代码库,它最初是用许多不同的选项创建的,这些选项允许您让代码以稍微不同的方式执行相同的过程,如下所示:

public class MainFunction {
  public void main(String option){
     if (option.equals("vanilla mode")){
        this.firstFunction();
     }else{
        this.differentVersionOfFirstFunction();
     }
     this.secondFunction();
  }

  public void firstFunction(){
    //First functions code
  }

  public void secondFunction(){
     //Second functions code
  }

  public void differentVersionOfFirstFunction(){
     // different code from First functions code that produces the same type of end result using a slightly different method
  }
}
随着各种不同选项的添加,代码变得越来越复杂,这一点也变得越来越复杂

为了解决这个问题,我最初计划创建一个父对象,然后在需要时,可以在父对象方法上有不同细微变化的子对象。问题是,我知道这会违反Liskov替代原则,事实上,我可能有孩子应该使用他们父母不使用的相同方法

所以我只剩下在同一个类对象中使用不同的方法,以稍微不同的方式完成相同的工作

public class MainFunction {
  public void main1(){
    this.firstFunction();
    this.secondFunction();
  }

  public void main2(){
    this.differentVersionOfFirstFunction();
    this.secondFunction();
  }

  public void firstFunction(){
    //First functions code
  }

  public void secondFunction(){
    //Second functions code
  }

  public void differentVersionOfFirstFunction(){
    // different code from First functions code that produces the same type of end result using a slightly different method
  }
}

我想我可以创建一个单独的实用程序类来保存我所有的各种函数,但我不确定是否有更优雅的解决方案?

也许您可以尝试使用strategy模式,在main函数中注入您每次都需要使用的strategy对象。看一看

我看不出你的例子是如何违反Liskov替换原则的。然而,我看到的是,它们可能违反了打开/关闭原则,这意味着每次需要修改程序时,都会编辑一些
MainFunction.java
文件,并有可能影响程序运行的所有可能场景。一个更好的解决方案是拥有大量解耦组件,这样当您需要修改某些内容时,您只修改一小部分内容,而这不太可能影响程序可能遇到的所有场景。这就是单一责任原则

正如在另一个答案中提到的,您的场景似乎非常适合应用策略模式。这可能如下所示:

  • 使用
    void main()
    方法创建接口
    main函数
    ,不带任何选项
  • 使用
    public abstract void main()
    成员创建一个抽象策略类,例如
    AbstractMainFunction
    ,不带任何选项。此类将实现
    main函数
    接口
  • 根据需要创建
    abstractmain函数
    的单独实现,例如
    vanillamodemain函数
    differentmain函数
    。您可能会发现在
    abstractmain函数中保留一些共享代码非常有用
  • 创建策略切换器类,例如
    MainFunctionService
    。它将有一个方法,
    public void main(String选项)
    ,如第一个示例所示,并且可能会有这样一个switch语句:

    MainFunction strategy = defaultFunction;
    switch(option) {
        case "vanilla":
             strategy = vanillaFunction;
             break;
        case "different":
             strategy = differentFunction;
             break;
    }
    strategy.main();
    

  • 看起来有很多事情要做,但最终您将看到这是如何真正简化维护和进一步开发的。

    谢谢,这看起来是正确的方向,但我仍然担心,当我有两个非常相似的实现时,可能会有一些代码重复,我将试一试,看看效果如何。如果您担心代码重复,请检查模板方法模式,可能会有所帮助。这个策略切换器类是否也违反了打开/关闭原则?@jaco0646,这是一个很好的问题,答案可能是,这取决于:-)。如果有太多的选项,并且选项的格式很复杂,那么是的,最好将选项解析功能构建到策略本身中,并应用责任链模式而不是策略模式。然而,在我看来,如果逻辑相对简单,那么程序的入口点有一个switch语句就很好了,并且它将遵循单一责任原则——只有一个改变的原因,即当一个新选项出现时。谢谢,我有一个关于这个的工作演示,现在我要对所有代码进行转换!我已经实现了这一点,虽然我不确定是否正确,但当我制作一个版本的香草模式主函数时,比如说,一个键函数需要不同数量的参数,那么必须在子函数中创建一个新函数,以及它继承的所有类,但是这个新函数对于其他不需要额外参数的孩子来说毫无意义?如果函数非常不同,甚至它们的参数也不同,那么直接调用策略上的
    main
    方法,例如
    case“a”:strategy1.main(a,b,c);打破案例“b”:应力2.干管(x、y、z)。还可以考虑使用<代码>上下文< /代码>类,将其作为单个参数传递给任何策略。然后,该策略本身将从
    Context
    中提取所需的数据,或者
    Context
    将有一些常用的参数解析方法。