在有现有的类时,接口如何取代多重inheritance的需要
首先…对不起这个职位。 我知道有很多post在stackoverflow讨论多重inheritance。 但是我已经知道Java不支持多重inheritance,而且我知道使用接口应该是另一种select。 但我不明白,看到我的困境:
我必须对用Java编写的非常大而复杂的工具进行更改。 在这个工具中,有一个由许多不同类对象和一个链接的成员层次结构构成的数据结构。 无论如何…
- 我有一个类
Tagged
有多个方法,并根据对象的类返回一个对象标记。 它需要成员和静态variables。 - 另一个称为
XMLElement
类允许链接对象,最后生成一个XML文件。 我也需要这里的成员和静态variables。 - 最后,我有这么多的数据类,几乎所有的应该扩展
XMLElement
和一些Tagged
。
好吧,这是行不通的,因为只能扩展一个类。 我经常读到,所有使用Java的东西都可以,并且不需要多重inheritance。 我相信,但我不明白接口应该如何取代inheritance。
- 把所有数据类中的真实实现放在一起是没有意义的,因为它每次都是一样的,但是这对接口是必须的(我认为)。
- 我没有看到我怎么可以改变我的inheritance类之一到一个接口。 我在这里有variables,他们必须在那里。
我真的不明白,所以请有人解释我如何处理这个?
你应该赞成组合(和委派)而不是inheritance:
public interface TaggedInterface { void foo(); } public interface XMLElementInterface { void bar(); } public class Tagged implements TaggedInterface { // ... } public class XMLElement implements XMLElementInterface { // ... } public class TaggedXmlElement implements TaggedInterface, XMLElementInterface { private TaggedInterface tagged; private XMLElementInterface xmlElement; public TaggedXmlElement(TaggedInterface tagged, XMLElementInterface xmlElement) { this.tagged = tagged; this.xmlElement = xmlElement; } public void foo() { this.tagged.foo(); } public void bar() { this.xmlElement.bar(); } public static void main(String[] args) { TaggedXmlElement t = new TaggedXmlElement(new Tagged(), new XMLElement()); t.foo(); t.bar(); } }
其实,除了Java以外,我没有好的答案应该有多重inheritance。 接口应该能够替代多重inheritance的要求就像是重复足够的次数成为真实的大谎言。
争论是多重inheritance导致了所有这些问题(la-di-dah),但我一直听到那些从未使用过C ++的Java开发人员的观点。 我也不会记得C ++程序员说:“哎呀,我喜欢C ++,但是如果他们只能摆脱多重inheritance,那将会成为一种伟大的语言”。 人们在实践中使用它,而不是在实践中使用它。
你的问题是多重inheritance适当的经典案例。 任何重构代码的build议都是告诉你如何解决Java没有多重inheritance的问题。
所有关于“哦,代表团更好,la-di-dah”的讨论都将宗教与devise混为一谈。 没有正确的方法。 事情要么更有用,要么更less用,就是这样。
在你的情况下,多inheritance将是更有用和更优雅的解决scheme。
至于重构你的代码为一个不太有用的forms,以满足所有从未使用过多重inheritance的宗教人士,并相信“多重inheritance是不好的”,我想你将不得不降级你的代码,因为我没有看到Java“ “就这么快就这样。 有太多的人重复宗教口头禅到愚蠢的地步,我看不到它被添加到语言。
其实,我的解决scheme是“x扩展标签,XMLElement”,这将是所有。
…但是从上面提供的解决scheme中可以看出,大多数人认为这样的解决scheme会太复杂和混乱!
我宁愿冒险进入“x扩展a,b”领域,即使这是一个非常可怕的解决scheme,可能会压倒大多数Java程序员的能力。
上面提出的解决scheme更令人惊讶的是,这里的每个人都build议你将你的代码重构成“委托”,因为多重inheritance是坏的,如果他们遇到同样的问题,只要简单地做就可以解决问题:“x扩展a,b”并完成它,关于“代表vsinheritance”的所有宗教论点将消失。 整个辩论都是愚蠢的,只有被无知的程序员推向前进,这些程序员只能说明他们可以背诵一本书,他们能为自己思考得有多less。
如果你认为Java应该拥有它,你是100%正确的,多重inheritance将会有所帮助,不,你在代码中做错了什么。
首先,把所有数据类中的真实实现放在一起是没有意义的,因为它每次都是一样的,但这对于接口是必要的(我认为)。
如何使用聚合标签?
-
将
Tagged
类重命名为Tags
。 -
创build一个
Tagged
界面:接口标签{标签getTags(); }
-
让每个需要“标记”的类实现
Tagged
并让它有一个tags
字段,它是从getTags
返回的。
其次我没有看到我怎么能改变我的inheritance类到一个接口。 我在这里有variables,他们必须在那里。
没错,接口不能有实例variables。 然而,存储标签的数据结构不一定是IMO被标记的类的一部分。 在一个单独的数据结构中分解标签。
类似于Andreas_D的build议,但是使用了内部类。 这样你确实可以扩展每个类,如果需要的话,可以在你自己的代码中覆盖它。
interface IBird { public void layEgg(); } interface IMammal { public void giveMilk(); } class Bird implements IBird { public void layEgg() { System.out.println("Laying eggs..."); } } class Mammal implements IMammal { public void giveMilk() { System.out.println("Giving milk..."); } } class Platypus implements IMammal, IBird { private class LayingEggAnimal extends Bird {} private class GivingMilkAnimal extends Mammal {} private LayingEggAnimal layingEggAnimal = new LayingEggAnimal(); private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal(); @Override public void layEgg() { layingEggAnimal.layEgg(); } @Override public void giveMilk() { givingMilkAnimal.giveMilk(); } }
我想这样解决:为Tagged
和XMLElement
类提取接口(也许你不需要公共接口中的所有方法)。 然后,实现这两个接口,实现类有一个Tagged
(你实际具体的Tagged
类)和一个XMLElement
(你实际的具体的XMLElement
类):
public class MyClass implements Tagged, XMLElement { private Tagged tagged; private XMLElement xmlElement; public MyClass(/*...*/) { tagged = new TaggedImpl(); xmlElement = new XMLElementImpl(); } @Override public void someTaggedMethod() { tagged.someTaggedMethod(); } }
public class TaggedImpl implements Tagged { @Override public void someTaggedMethod() { // so what has to be done } }
public interface Tagged { public void someTaggedMethod(); }
(和XMLElement一样)
一种可能的方式;
1-您可以为常用function创build基类,如果您不需要实例化,则将其设置为抽象。
2-创build接口并在这些基类中实现这些接口。 如果需要具体实施,请将方法抽象化。 每个具体类都可以有它自己的impl。
3-在具体类中扩展抽象基类,并在该级实现特定的接口
只是想知道如果不能简单地使用内部(成员)类(LRM 5.3.7)? 像这样(基于上面的第一个答案):
// original classes: public class Tagged { // ... } public class XMLElement { // ... } public class TaggedXmlElement { public/protected/private (static?) class InnerTagged extends Tagged { // ... } public/protected/private (static?) class InnerXmlElement extends XMLElement { // ... } }
这样你有一个类TaggedXmlElement实际上包含了两个原始类的所有元素,而在TaggedXmlElement中你可以访问成员类的非私有成员。 当然,不会使用“超级”,而是调用成员类的方法。 或者,可以扩展其中一个类,并使另一个成员类。 有一些限制,但我认为他们都可以解决。
另一位开发人员build议,使用构图将是一种方法。 反对多重inheritance的主要论点是当你使用相同的方法声明(相同的方法名称和参数)从两个类扩展时创build的歧义。 但个人而言,我认为这是一大堆垃圾。 在这种情况下很容易出现编译错误,这与在同一个类中定义多个相同名称的方法没有多大区别。 像下面的代码片段可以轻松解决这个困境:
public MyExtendedClass extends ClassA, ClassB { public duplicateMethodName() { return ClassA.duplicateMethodName(); } }
另一个反对多重inheritance的观点是,Java试图让事情变得简单,以至于业余开发人员不会创build一个互相依赖的类的networking,从而产生一个混乱的,令人困惑的软件系统。 但是正如你所看到的,当它不可用时,它也会使事情复杂化和混淆。 另外,这个论点可以用于编码中的其他100个事情,这就是开发团队为什么要进行代码评论,风格检查软件和每晚构build的原因。
但是,在你的特殊情况下,你必须和解(见Shojaei Baghini的回答)。 它增加了一些锅炉板代码,但是它模拟了与多重inheritance相同的行为。
我在Android上运行类似的问题。 我需要扩展一个Button和一个TextView(都从Viewinheritance)与附加function。 由于没有访问他们的超类,我需要find另一个解决scheme。 我写了一个封装所有实现的新类:
class YourButton extends Button implements YourFunctionSet { private Modifier modifier; public YourButton(Context context) { super(context); modifier = new Modifier(this); } public YourButton(Context context, AttributeSet attrs) { super(context, attrs); modifier = new Modifier(this); } public YourButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); modifier = new Modifier(this); } @Override public void generateRandomBackgroundColor() { modifier.generateRandomBackgroundColor(); } } class Modifier implements YourFunctionSet { private View view; public Modifier(View view) { this.view = view; } @Override public void generateRandomBackgroundColor() { /** * Your shared code * * ...... * * view.setBackgroundColor(randomColor); */ } } interface YourFunctionSet { void generateRandomBackgroundColor(); }
这里的问题是,你的类需要相同的超类。 例如,您也可以尝试使用不同的类,但请检查它来自哪种types
public class Modifier{ private View view; private AnotherClass anotherClass; public Modifier(Object object) { if (object instanceof View) { this.view = (View) object; } else if (object instanceof AnotherClass) { this.anotherClass = (AnotherClass) object; } } public void generateRandomBackgroundColor(){ if(view!=null){ //...do }else if(anotherClass!=null){ //...do } } }
所以这里基本上是我的Modifier类封装所有实现的类。
希望这有助于某人。