减少代码重复,无需子类继承

问题描述 投票:0回答:2

我正在研究子类化与接口和组合。当涉及到代码重复时,我最终对一些事情感到困惑。众所周知,在很多情况下,子类化和继承并不是正确的选择,但它在减少代码重复方面是有效的。

接口很强大,如果做得正确的话,可以提供很好的可读性,但我无法理解这样一个事实:它实际上并不能帮助我减少代码重复。我们最终可能会遇到子类化无效的情况。但是扩展程序的可能性很大,每当我们这样做时,试图维护开放封闭原则,我们最终会以荒谬的副本量进行接口的实现/实现粘贴代码,通过子类化可能可以避免(就代码重复而言)。

我们如何使用接口和组合建立良好的策略,避免一遍又一遍地编写相同的方法?这样我们就可以在保持模块化的同时坚持开闭原则。我们是否有任何指导方针来帮助我们快速有效地决定代码重复最终是否值得?

干杯

< /wallOfText>

java inheritance interface modularity open-closed-principle
2个回答
4
投票

面向对象建模是非常主观的,但我在这里唯一能做的就是旧的继承与组合讨论: https://www.thoughtworks.com/insights/blog/composition-vs-inheritance-how-choose

根据您的论证,我相信您经常尝试从具有相似代码的两个或多个类中提取超类,因此它们都可以共享相同的继承方法,而不仅仅是重复它们。尽管从技术上讲,这完全满足了您的需求,但您还应该注意继承语义,因为它将表示 is-a 关系(即,汽车 is-a 车辆、狗 is-a 哺乳动物、报告-screen is-a 只读屏幕)。由于 Java 不提供多重继承,因此如果类层次结构增长,您最终可能会受到限制和困惑。

因此,在开始提取超类以供重用之前,请记住,您还可以将这个code-i-want-to-reuse单元提取为part-of其他类(组合)。

抱歉我的概念性示例,但它是这样的狮子都是哺乳动物和猎人。它们自然应该继承Mammals超类(在哺乳动物中有很多可重用的代码)。由于并非所有哺乳动物都会狩猎,因此我们不想在 Mammals 类上定义新的 hunt() 方法。

此时,您可能正在考虑创建一个新的继承级别:哺乳动物<- HuntingMammals。但想一想:如果您继续对动物的每个独特方面进行此操作,您将在一个棘手且令人困惑的层次结构中拥有数十个类。除此之外,我们还知道一些爬行动物和鸟类也会狩猎,所以,我们最好将所有狩猎的东西隔离在别处。

作为继承的健康替代方案,我们可以定义一个单独的 Hunter 类。要重用它的内容,我们需要做的就是将 Hunter 对象作为 DogLion (字段)的成员。如果我们需要将狗和狮子一起视为猎人(多态),我们可以定义一个 CanHunt 接口来对它们进行分组。

检查下面的示例:

class Hunter {
   void hunt(){
       System.out.println("i'm hunting...");
   }
}

interface CanHunt{
   Hunter getHunter();
}

class Dog extends Mammals implements CanHunt{
   ...
   Hunter hunter = new Hunter();
   
   @Override
   Hunter getHunter(){
       return hunter;
   }      
   ...
}


class Lion extends Mammals implements CanHunt{
   ...
   Hunter hunter = new Hunter();
   
   @Override
   Hunter getHunter(){
       return hunter;
   }      
   ...
}

这里我们有一个多态示例代码,要求狗和狮子进行狩猎:

...
List<CanHunt> hunters = new LinkedList();
hunters.add(new Dog());
hunters.add(new Lion());

for(CanHunt h:hunters){
  h.getHunter().hunt(); //we don't know if it's a dog or a lion here...
}
...

希望这个简单的例子能给你一些启发。如果我们不断将其发展为更详细但更灵活的设计,它可能会变得相当复杂。例如,Hunter类可以是抽象的,具有不同的实现,因为狗的狩猎方式与狮子不同,但它们有一些共同的行为。


0
投票

我发现这个问题非常有趣,因为我们大多数人没有足够的时间来阅读和重新阅读我们可以继承的所有类,这可能导致我们编写非常低效的代码,有时甚至“重新发明轮子”与我们查看其他课程相比,结束会花费更多的时间。

我解决这个问题的建议是创建微服务,即执行特殊工作的小型应用程序,这样您就不必像现在一样使用继承,并且您将知道所获得的确切输出。此外,您还可以在其他应用程序中重复使用这些“微服务”。

顺便说一句,查看@AntoineDubuis推荐的书籍,我发现它们会非常有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.