关于继承Java类的性质的问题

时间:2010-08-12 07:21:15

标签: java oop inheritance composition

所以我认为我有一个非常基本的问题。假设您的项目com.bee.buzz中包含一个名为com.cow.moo的开源Java程序。

moo有很多很棒的课程,其中大部分是你不想碰的,但是有一些你做的。现在,在这一点上,最好的办法是扩展你想要修改的类,对吧? (我知道有很多关于扩展与实现的说法,但这些类都不是接口,所以这是不可能的。)

我的问题是,说这是moo中的课程:

package com.cow.moo;
public class Milk {
    private float currentMilk;
    public int getMilk() { /* Stuff */ }
    public float convertToGallons (float liquid) { /* More Stuff */ }
}

现在,我想在我的新课程中使用getMilk来扩展Milk。但是,Milk中的getMilk依赖于私有变量(如currentMilk)和其他我不会包含的函数(如convertToGallons。)如果我希望我的新函数正常工作,我是否必须包含其他变量和函数?我不想大量修改函数,只需添加一点就可以了。最好的方法是什么?

建立大型项目的一般提示也很有用。我认为这里的一些Java专家甚至不会花五秒钟来得出答案。谢谢你的时间。

5 个答案:

答案 0 :(得分:6)

一般建议赞成合成优于继承

说,你有一个接口和现有的实现,最适合你的需要,如

public interface MilkProvider { public float getMilk(); }
public class Milk implements MilkProvider { // same as you example }

并且需要另一个自定义实现,您可以像这样编写代码:

public class MyMilk implements MilkProvider {
  private MilkProvider milk; 

  public MyMilk(int someValue) {
    milk = new Milk(someValue);  // unfortunatly we can't get rid of a depencency
                                 // to the concrete class because we need to create
                                 // something. An existing factory could help, but
                                 // but usually there's none implemented.
  }

  public float getMilk() {
    float result = milk.getMilk();
    // do somethink with the result
    return float;
  }
}

答案 1 :(得分:1)

我认为在这种情况下,更好的解决方案将是多态(静态多态),或者您可以使用反射(不要使用这种方式)来访问私有变量。

答案 2 :(得分:1)

  

现在,我想在我的新课程中使用getMilk来扩展Milk。但是,Milk中的getMilk依赖于私有变量(如currentMilk)和其他我不会包含的函数(如convertToGallons。)如果我希望我的新函数能够正常工作,我是否必须包含其他变量和函数?

您不必包含 public 函数和变量。继承的核心概念是,作为子类,您可以免费获得子类中包含的所有父类的公共(和受保护)成员。所以你的子类(比如说HoneyMilk)可以从一开始就调用convertToGallons

在这种情况下覆盖getMilk要复杂得多,因为它依赖于私有变量(您的子类无法访问)。我的建议是将你的思维方式从把班级视为“白盒子”转变为“黑匣子”。我的意思是你应该实现被覆盖的getMilk版本,好像你实际上看不到Milk的源代码一样。虽然它可能看起来像一个迂回的解决方案(我的意思是,为什么我不能在这里调整这一行?!),这将迫使你只使用父类公开公开的子类来实现你的子类。它还强调抽象的重要性,这对于开发大型项目绝对至关重要。

答案 3 :(得分:0)

如果它们是公共的,你可以通过方法访问器(getters& setters)扩展类和访问实例变量。

您可以使用AOP (Aspect Oriented Programming)在运行时更改moo类,而无需更改其来源。

请仔细阅读一些Composition vs. Inheritance topics

希望这会对你有所帮助。

答案 4 :(得分:0)

除非你使用丑陋的Java反射,否则你将无法使用私有类成员。如果我是你(并且更改不是太重,在这种情况下我会分叉原始项目),我会考虑在运行时修改代码或静态使用方面编织(面向方面​​编程)。 AspectJ可能看起来好像有一个很好的学习曲线,但它是一个很好的工具,可以在你的工具箱中完美匹配你的需求。