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 作为 args 而是 Milk 和 Alcohol,但我必须用完全 Liquid 参数覆盖抽象方法。所以当我写

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

孩子可以把酒精作为喝酒的理由。我可以使用 Exceptions 或 if() 来解决这个问题,但我请你建议我为这些关系设计一个更好的设计。当我将错误的参数传递给 toDrink() 方法(给孩子喝酒精或给成人喝牛奶)时,我想要它,当我尝试运行它时,我的 IDE 将它强调为错误和编译错误。

4

3 回答 3

1

你可以使用泛型来解决这个问题:

我建议在Liquidand之间创建一个类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 回答
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()ofAdultChild方法以分别接受扩展Alcohol和的类型Milk

现在,按照您的预期,下面的代码失败(编译错误)

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

但这一个有效

    child.toDrink(new Milk());
于 2013-06-19T11:14:08.980 回答
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 类中只能有一个实现。

于 2013-06-19T11:21:35.143 回答