3

所以我想我有一个非常基本的问题。假设您在项目 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 */ }
}

现在,假设我只想在扩展 Milk 的新类中使用 getMilk。但是,Milk 中的 getMilk 依赖于私有变量(如 currentMilk)和其他我不会包含的函数(如 convertToGallons。)如果我希望我的新函数正常工作,我是否必须包含这些其他变量和函数?我不想对功能进行大量修改,只需添加一点即可。最好的方法是什么?

一般来说,构建更大项目的技巧也会很有用。我认为这里的一些 Java 专家甚至不需要五秒钟就能得出答案。谢谢你的时间。

4

5 回答 5

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;
  }
}
于 2010-08-12T07:35:55.657 回答
1

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

于 2010-08-12T07:32:33.920 回答
1

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

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

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

于 2010-08-12T07:48:20.760 回答
0

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

您可以使用AOP(面向方面​​编程)在运行时更改 moo 类,而无需更改其源。

考虑阅读一些组合与继承主题

希望这会帮助你。

于 2010-08-12T07:34:54.453 回答
0

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

于 2010-08-12T07:36:55.513 回答