在Java中编译时使用继承约束检查组合

时间:2012-08-07 08:30:05

标签: java inheritance composition

我有一个关于Java继承和最佳实践的问题。组合物:

  

说你有一个由Apple和Lemon扩展的水果。

     

除了这些之外,你还有一个由AppleBasket扩展的篮子   和LemonBasket。

     

水果与他们的双向一对多关系   各自的篮子,所以水果有一个篮子,篮子有一个清单   水果。

现在我要做的是强制AppleBasket只在编译时使用苹果,同样适用于LemonBaskets。同样,Apple应该只有AppleBasket作为财产,同样对于Lemons。

我尝试过使用泛型,抽象方法和受保护变量,但我总是找不到某种方法的理由。重要的是我们不要破坏SOLID原则,例如,超类应该包含has-a和has-many属性以避免代码重复等等。

当有人试图将Lemon放在AppleBasket中时,这是导致编译错误的关键,反之亦然。

干杯, 安德烈亚斯

1 个答案:

答案 0 :(得分:0)

您可以通过Google搜索协方差和逆变来找到有关更复杂输入的有用信息。

如果您不介意使用Scala编译为可以与Java程序一起使用的字节码,Scala会为您提供一些很好的语法(Java稍后):

class Fruit
class Basket[T <: Fruit ] {
    def addToBasket(fruit:T) =  {}
}

class Apple extends Fruit
class Lemon extends Fruit

class AppleBasket extends Basket[Apple]

val applebasket = new AppleBasket

applebasket.addToBasket(new Apple)

applebasket.addToBasket(new Lemon)

此代码段的最后一行给出了编译时错误:

 $ scala Test.scala
C:\cygwin\home\user\Test.scala:18: error: type mismatch;
 found   : this.Lemon
 required: this.Apple
applebasket.addToBasket(new Lemon)
                        ^
one error found

我最近一直在和Scala一起玩,我在Java中考虑这个问题很困难,但在Java中我可能会做更多这样的事情:

class Fruit{}
class Apple extends Fruit{}
class Lemon extends Fruit{}
class Basket<T extends Fruit>{
    public void addToBasket(T foo) {}
}
class Blah {
    void doIt() {
        Apple a = new Apple();
        Basket b = new Basket<Apple>();
        b.addToBasket(a);
        Lemon l = new Lemon();
        b.addToBasket(l);
    }
}

b.addToBasket(l)行给出以下编译时类型错误:

The method addToBasket(Apple) in the type Basket<Apple> is not applicable for the arguments (Lemon)

另一个提供相同编译错误的选项(从注释中复制以使其更清晰):

//same definition of Fruit, Apple, and Basket, but with:
class AppleBasket extends Basket<Apple> {}
class Blah {
    void doIt() {
        Apple a = new Apple();
        Basket<Apple> b = new AppleBasket();
        b.addToBasket(a);
        Lemon l = new Lemon();
        b.addToBasket(l);
    }
}