如何摆脱遗产?

时间:2016-03-31 07:42:21

标签: java oop inheritance design-patterns

我有一个算法,我有两种不同的算法实现。应该从许多地方调用这些实现,具体取决于用户选择的模式。我不想在所有调用实现的地方编写条件语句。所以,我创建了一个抽象类,实现继承它。我可以在一个地方设置所需的模式,如下所示:

if(firstMode){
    list = new ListForm1();
}
else{
    list = new LiastForm2();
}

之后在其他所有地方,我都可以享受多态性带来的所有好处。 它运作良好,但我想摆脱以下原因的继承:

  1. 我听说组合比继承更好。
  2. 第一种形式的算法比第二种形式容易得多。在第一种形式中,我只有3种方法,在第二种形式中,我有15种方法。抽象类必须包括所有15种(和5种常用方法)。事实证明,12种方法没有使用第一种形式。
  3. 理论上,可能会有一种新的算法形式,与其他两种形式的共同点更少,但它会带来10种新​​方法,所有这些方法都必须添加一个抽象类。
  4. 据我所知,战略模式在这里使用没有意义。 以下是战略模式的例子:

    //abstract strategy
        interface Strategy {
            int execute(int a, int b); 
        }
    
    // concrete strategy1
    class ConcreteStrategyAdd implements Strategy {
    
        public int execute(int a, int b) {
            return a + b;  
        }
    }
    
    // concrete strategy2
    class ConcreteStrategySubtract implements Strategy {
    
        public int execute(int a, int b) {
            return a - b;  
        }
    }
    
    //concrete strategy3
    class ConcreteStrategyMultiply implements Strategy {
    
        public int execute(int a, int b) {
            return a * b; 
        }    
    }
    
    class Context {
    
        private Strategy strategy;
    
        public Context() {
        }
    
        // Set new concrete strategy
        public void setStrategy(Strategy strategy) {
            this.strategy = strategy;
        }
    
        // use strategy
        public int executeStrategy(int a, int b) {
            return strategy.execute(a, b);
        }
    }
    

    它有同样的问题。战略应该相互联系。如果我将它们与界面而不是抽象类链接,那将更糟糕。接口将包含许多方法,但第一种形式的算法不需要其中的许多方法。此外,一般方法必须在所有具体策略中重复。我无法在界面中提供默认实现。

    但是,我不明白如何在这里使用作文。据我了解,战略模式已经使用了组合。类Context包括Strategy的实例作为字段。但也许是代表团。

    所以,这是我的问题:

    我可以摆脱所有上述问题(抽象类的方法太多,强连接,因此很难添加新形式的算法),但仍然使用条件语句只在一个地方,而不是在我需要某种形式的算法的所有情况下。

    UPD: 我想说明我如何调用一些方法,这些方法以SECOND形式的算法实现,但不需要第一种形式的算法:

    if (list.getCurrentLeaders().contains(ballIdx))
    

    方法getCurrentLeaders()的默认实现返回null。所以,如果我使用FIRST形式的算法调用它,那么我将得到一个错误。我明白这很糟糕。但是我该如何解决呢?

5 个答案:

答案 0 :(得分:1)

从一开始就需要根据用户选择的不同模式调用不同的算法,您可以创建一种工厂类来为整个代码提供算法。我认为,如果它只是一个算法,并且如果您使用的是Java 8,则可以将FunctionPredicateSupplier与地图结合使用以避免使用if语句,例如:

Map<String, Predicate<Whatever>> map = new HashMap<>();
map.put("mode_one", (w) -> true);
map.put("mode_two", (w) -> false);

然后简单地调用算法:

map.get("mode_one").test()

如果您需要提供与您发布的示例中不同的表单,则可以使用供应商而不是谓词。 根据您的简单要求,我认为实用功能将是最好的选择......

答案 1 :(得分:1)

如果你没有实现所有的方法(即如果你要在抽象类中有15个方法来实现,而你只需要实现10),那么你就违反了Liskov替换原则:

https://en.wikipedia.org/wiki/Liskov_substitution_principle

基本上,这是一件坏事。

尝试将非常用方法转换为传递给构造函数的其他类型的对象(在摘要中)。

答案 2 :(得分:1)

  

我听说组合比继承好得多。

并非总是 - 很多时候继承是正确的结构。您必须以has ais a条款来考虑它。足球队有一个收集球员。它还有教练,日程表,姓名等。所以Team : List<Player>不是正确的结构。

Car Vehicle,因此继承是正确的构造。

所以以这种方式思考你的设计:

我的课程是否有共同基础?是否有一个基类可以说ListForm1 ListBaseListForm2 ListBase。应该在案例类型中的那些类型有哪些共同的方法和属性?哪些方法和属性应该是虚拟的,以便我可以覆盖它们?

  

第一种形式的算法比第二种形式容易得多。在第一种形式中,我只有3种方法,在第二种形式中,我有15种方法。抽象类必须包括所有15种(和5种常用方法)。事实证明,12种方法没有使用第一种形式。

因此,您的基本类型可能只有3种方法,并且您可以根据需要在子类型中添加方法。请记住,链中可以有多个基本类型,但它是一个链,而不是一个树,这意味着您可以拥有一个拥有另一个父级的父级,但您不能拥有两个父级。

或者你可能有正交接口,因为你可以实现多个接口。

  

理论上,可能有一种新形式的算法,与其他两种方法的共同点更少,但它会带来10个新方法,所有这些方法都必须添加一个抽象类。

为什么呢?为什么新算法不能只定义自己需要的方法,只要客户端在继承链(或适当的接口)中选择适当的级别,以便它知道应该的方法实施。

  

if (list.getCurrentLeaders().contains(ballIdx))

     

方法getCurrentLeaders()的默认实现返回null。所以,如果我使用FIRST形式的算法调用它,那么我将得到一个错误。我明白这很糟糕。但是我该如何解决呢?

那么你需要检查这个特定的list是否实现了 实现该方法的接口(或继承基类)?

答案 3 :(得分:1)

您可以实施某种责任链模式。

interface IStrategy {
  void Run();
  bool CanHandle(IContext context);
}

class StrategyChecker {
  IStrategy GetStrategy(IContext context) {
    foreach(var strategy in strategies) {
      if(strategy.CanHandle(context)
        return strategy;
    }

    return defaultStrategy;
  }
}    

class Director {
  void Run() {
    strategyChecker.AddStrategy(strategy1);
    strategyChecker.AddStrategy(strategy2);

    var strategy = strategyChecker.GetStrategy(someContext);
    strategy.Run();
  }
}

抱歉c#伪代码。

答案 4 :(得分:0)

为什么不将IStrategy用作类型?

interface IStrategy {
    int execute(int a, int b); 
}

class Strategy1 implements IStrategy {}
class Strategy2 implements IStrategy {}

static class StrategyFactory {
    IStrategy Create(bool first) {
        return first ? new Strategy1() : new Strategy2();
    }
}

然后在您的用户代码中:

void doStuff()
{
    IStrategy myStrategy = StrategyFactory.Create(true);
    myStrategy.execute(1, 2);
}