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


  假设您有一个水果,它可以通过苹果和柠檬来补充。
  
  在这些旁边,您还获得了一个AppleBasket扩展的购物篮
  和柠檬篮。
  
  水果与它们之间具有双向的一对多关系
  各个篮子,所以水果有一个篮子,篮子有清单
  水果


现在我想做的就是强制AppleBasket只能在编译时使用Apple,LemonBaskets也一样。同样,Apple应该仅具有AppleBasket作为属性,Lemons也应具有。

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

当有人试图将Lemon放入AppleBasket或反之时,这是获得编译器错误的关键。

干杯,
安德烈亚斯

最佳答案

通过对协方差和反方差进行谷歌搜索,您可能会发现一些有关更复杂类型的有用信息。

如果您不介意使用Scala编译为可与Java程序一起使用的字节码,则Scala会为您提供一些不错的语法来完成这种事情(稍后再介绍Java):

水果类
类别购物篮[T     def addToBasket(fruit:T)= {}
}

苹果延伸水果
柠檬延伸水果

class AppleBasket扩展购物篮[Apple]

val applebasket =新的AppleBasket

applebasket.addToBasket(新苹果)

applebasket.addToBasket(新柠檬)


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

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


最近,我一直在与Scala一起玩,在Java中很难考虑到这一点,但是在Java中,我可能会做更多这样的事情:

水果类{}
苹果扩展水果类{}
柠檬延伸水果{}
class Basket {
    公共无效addToBasket(T foo){}
}
布拉类{
    无效doIt(){
        苹果a =新的Apple();
        购物篮b =新的购物篮();
        b.addToBasket(a);
        柠檬l =新柠檬();
        b.addToBasket(l);
    }
}


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

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


产生相同编译错误的另一个选项(从注释复制以使其更清楚):

//水果,苹果和购物篮的定义相同,但具有:
class AppleBasket扩展了Basket {}
布拉类{
    无效doIt(){
        苹果a =新的Apple();
        Basket b =新的AppleBasket();
        b.addToBasket(a);
        柠檬l =新柠檬();
        b.addToBasket(l);
    }
}

10-02 04:32