1

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

假设你有一个水果,它被苹果和柠檬扩展。

在这些旁边,您还有一个由 AppleBasket 和 LemonBasket 扩展的篮子。

Fruits 与其各自的篮子具有双向的一对多关系,因此 Fruits 有一个篮子,而篮子有一个水果列表。

现在我想做的事情是强制 AppleBasket 在编译时只包含 Apples,对于 LemonBaskets 也是如此。同样,Apple 应该只有一个 AppleBasket 作为财产,Lemons 也是如此。

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

当有人试图将 Lemon 放入 AppleBasket 时,产生编译器错误是关键,反之亦然。

干杯,安德烈亚斯

4

1 回答 1

0

通过谷歌搜索协变和逆变,您可能会找到一些有关更复杂类型的有用信息。

如果你不介意使用 Scala,它可以编译成字节码,你可以在 Java 程序中使用,Scala 为你提供了一些很好的语法来做这种事情(Java 稍后):

水果类
类篮子[T <:水果] {
    def addToBasket(水果:T) = {}
}

苹果类扩展水果
柠檬类扩展水果

类 AppleBasket 扩展了 Basket[Apple]

val applebasket = 新的 AppleBasket

applebasket.addToBasket(新苹果)

applebasket.addToBasket(新柠檬)

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

$ scala 测试.scala
C:\cygwin\home\user\Test.scala:18: 错误:类型不匹配;
 发现:this.Lemon
 必需:this.Apple
applebasket.addToBasket(新柠檬)
                        ^
发现一个错误

我最近一直在玩 Scala,我在 Java 中思考这个问题时遇到了麻烦,但在 Java 中我可能会做更多这样的事情:

类水果{}
Apple 类扩展 Fruit{}
柠檬类扩展水果{}
类篮子<T扩展水果>{
    公共无效 addToBasket(T foo) {}
}
类废话{
    无效 doIt() {
        苹果 a = 新苹果();
        篮子 b = 新篮子<苹果>();
        b.addToBasket(a);
        柠檬 l = 新柠檬();
        b.addToBasket(l);
    }
}

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

Basket<Apple> 类型中的方法 addToBasket(Apple) 不适用于参数 (Lemon)

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

//水果、苹果和篮子的定义相同,但有:
类 AppleBasket 扩展 Basket<Apple> {}
类废话{
    无效 doIt() {
        苹果 a = 新苹果();
        篮子<Apple> b = new AppleBasket();
        b.addToBasket(a);
        柠檬 l = 新柠檬();
        b.addToBasket(l);
    }
}
于 2012-08-07T08:51:57.893 回答