2

私はそのようなクラスを持っています:

abstract class Person{void toDrink(Liquid l);}

class Liquid{}
class Alcohol extend Liquid{}
class Milk extends Liquid{}


class Adult extends Person{void toDrink(Liquid l){}}
class Child extends Person{void toDrink(Liquid l){}}

Child と Adult には引数として Liquid を使用せず、Milk と Alcohol をそれぞれ引数として取りたいのですが、抽象メソッドを正確に Liquid 引数でオーバーライドする必要があります。だから私が書くとき

Person child = new Child();
child.toDrink(new Alcohol());

子供は飲酒の口実としてアルコールを摂取することができます。この問題は Exceptions または if() を使用して解決できますが、これらの関係のより良い設計についてアドバイスをお願いします。メソッド toDrink() (アルコールから子供へ、または牛乳から大人へ) に間違った引数を渡すと、IDE が実行しようとすると間違いとコンパイル エラーとして下線が引かれます。

4

3 に答える 3

1

以下のように作成できますか?

abstract class Person<T extends Liquid>{
    void toDrink(T l) {

    }
}

toDrink()上記のコードでは、拡張する型を受け入れるようにメソッドをバインドしていますLiquid

class Adult<T extends Alcohol> extends Person<T>{

    void toDrink(T l){

    }
}

class Child<T extends Milk> extends Person<T>{
    void toDrink(T l){

    }
}

toDrink()上記のコードでは、Adultおよびメソッドをバインドして、およびそれぞれChildを拡張する型を受け入れます。AlcoholMilk

さて、あなたの期待通り、以下のコードは失敗します(コンパイルエラーで)

    Person<Milk> child = new Child<Milk>();
    child.toDrink(new Alcohol()); // error here

しかし、これは機能します

    child.toDrink(new Milk());
于 2013-06-19T11:14:08.980 に答える
1

ジェネリックを使用してこれを解決できます。

Liquidと の間にクラスを作成することをお勧めしますMilk:

public abstract class NonAlcoholicLiquid extends Liquid {}
public class Milk extends NonAlcoholicLiquid {}

Person クラスをそれぞれ変更します

public abstract class Person<Drink extends Liquid> {
    void doDrink(Drink drink) {

    }
}


public class Adult<Drink extends Liquid> extends Person<Drink> {
    void doDrink(Drink drink){

    }
}

public class Child<Drink extends NonAlcoholicLiquid> extends Person<Drink> {
    void doDrink(Drink drink){

    }
}

この方法では、大人は牛乳を飲むことができますが、子供はノンアルコール飲料のみを飲むことができます ;)

アップデート:

あなたのコメントによると、当面はジェネリックをスキップできます。

public abstract class Person {
    public abstract void doDrink(Liquid drink);
}


public class Adult extends Person {
    void doDrink(Liquid drink) {
        if(!(drink instanceof Alcohol)) {
            throw new InvalidDrinkException("Adults may only drink Alcohol");
        }
        // do the adult's drinking stuff
    }
}

public class Child extends Person {
    void doDrink(Liquid drink){
        if(!(drink instanceof Milk)) {
            throw new InvalidDrinkException("Children may only drink Milk");
        }
        // do the child's drinking stuff
    }
}

しかし、あなたのアプローチには考え方に欠陥があります。子供が成長すると、インスタンスは同じですが、クラスは変更する必要があります...

于 2013-06-19T11:21:09.737 に答える
0

I want Child and Adult not to take Liquid as args but Milk and Alcohol respectively大人はアルコールのみ、子供は牛乳のみを飲むことを意味します。そのため、各 Person サブタイプがタイプ パラメーターとして飲む Liquid のタイプでジェネリックを使用できます。

abstract class Person<L extends Liquid> {
 void toDrink(L l) {
   //implementation here.
 }
}

class Liquid{}
class Alcohol extend Liquid{}
class Milk extends Liquid{}

 class Adult extends Person<Alcohol>{
    // You don't necessarily need to override the toDrink method.
 }

 class Child extends Person<Milk>{ }

toDrink()各サブクラスでメソッドをオーバーライドする必要はありません。抽象 Person クラスに実装できるのは 1 つだけです。

于 2013-06-19T11:21:35.143 に答える