Java重写抽象方法设计策略



我有这样的类:

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){}}

我想孩子和成人不把液体作为参数,但牛奶和酒精分别,但我必须覆盖抽象方法与确切的液体参数。所以当我写

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

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

您可以创建如下?

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){
    }
}

在上面的代码中,您绑定了AdultChild方法的toDrink(),以接受分别扩展AlcoholMilk的类型。

现在,正如您所期望的那样,下面的代码失败了(带有编译错误)

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

但是这个可以

    child.toDrink(new Milk());

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

我建议在LiquidMilk之间创建一个类:
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
    }
}

但是你的方法在思考上有一个缺陷:当一个孩子长大后,实例是一样的,但是类必须改变…

I want Child and Adult not to take Liquid as args but Milk and Alcohol respectively表示成人只喝酒精饮料,儿童只喝牛奶。因此,您可以使用泛型,每个Person子类型饮用的液体类型作为类型参数。

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类中只能有一个实现。

最新更新