1

Java の継承と合成のベスト プラクティスについて質問があります。

Apple と Lemon によって拡張される Fruit があるとします。

これらの隣には、AppleBasket と LemonBasket によって拡張される Basket もあります。

果物は、それぞれのバスケットと双方向の 1 対多の関係にあるため、果物にはバスケットがあり、バスケットには果物のリストがあります。

ここで私がやりたいことは、AppleBasket がコンパイル時に Apple のみを持つように強制することです。LemonBaskets についても同様です。同様に、Apple はプロパティとして AppleBasket のみを持つ必要があり、Lemons も同様です。

私はジェネリック、抽象メソッド、保護された変数を使用してみましたが、特定のアプローチを採用しない理由を常に見つけています。SOLID の原則を破らないことが重要です。たとえば、コードの重複を避けるために、スーパークラスに has-a および has-many プロパティを含める必要があります。

誰かが Lemon を AppleBasket の中に入れようとしたとき、またはその逆のときにコンパイラ エラーを発生させることが重要です。

乾杯、アンドレアス

4

1 に答える 1

0

共変性と反変性をグーグルで検索すると、より複雑なタイピングに関する有用な情報が見つかる場合があります。

Javaプログラムで使用できるバイトコードにコンパイルされるScalaを使用してもかまわない場合は、Scala'sを使用すると、この種のことを実行するための優れた構文が提供されます(Java以降)。

クラスフルーツ
クラスバスケット[T<:フルーツ] {
    def addToBasket(fruit:T)= {}
}

クラスAppleはFruitを拡張します
クラスレモンはフルーツを拡張します

クラスAppleBasketはBasket[Apple]を拡張します

valapplebasket=新しいAppleBasket

applebasket.addToBasket(新しいApple)

applebasket.addToBasket(新しいレモン)

このコードスニペットの最後の行は、コンパイル時のエラーを示しています。

$ scala Test.scala
C:\ cygwin \ home \ user \ Test.scala:18:エラー:タイプの不一致;
 見つかった:this.Lemon
 必須:this.Apple
applebasket.addToBasket(新しいレモン)
                        ^
1つのエラーが見つかりました

私は最近Scalaで遊んでいるので、Javaでこれについて考えるのに苦労していますが、Javaではおそらく次のようなことをするでしょう。

クラスFruit{}
クラスAppleはFruit{}を拡張します
クラスLemonはFruit{}を拡張します
クラスBasket<Textends Fruit> {
    public void addToBasket(T foo){}
}
クラスBlah{
    void doIt(){
        Apple a = new Apple();
        バスケットb=新しいバスケット<Apple>();
        b.addToBasket(a);
        レモンl=new Lemon();
        b.addToBasket(l);
    }
}

b.addToBasket(l)行では、次のコンパイル時タイプのエラーが発生します。

タイプBasket<Apple>のメソッドaddToBasket(Apple)は、引数には適用できません(レモン)

同じコンパイルエラーを発生させる別のオプション(コメントからコピーして明確にする):

// Fruit、Apple、Basketの定義は同じですが、次のようになります。
クラスAppleBasketはBasket<Apple>{}を拡張します
クラスBlah{
    void doIt(){
        Apple a = new Apple();
        バスケット<アップル>b= new AppleBasket();
        b.addToBasket(a);
        レモンl=new Lemon();
        b.addToBasket(l);
    }
}
于 2012-08-07T08:51:57.893 に答える