2014-11-04 4 views
2

В моей программе у меня есть абстрактные классы Animal and Flower. Животные питаются цветами, но каждый Животные должны только есть определенный тип цветка (например, носороги едят только Розы, Черепахи едят тюльпаны).Подклассы в качестве аргументов абстрактного метода

Сейчас мой код в основном выглядит следующим образом:

public abstract class Animal { 
    abstract boolean eatFlower(Flower f); 
} 

public class Rhino extends Animal { 
    boolean eatFlower(Flower f) { 
     if(!(f instanceof Rose)) return false; 
     return (f.eaten = true); 
    } 
} 

public class Turtle extends Animal { 
    boolean eatFlower(Flower f) { 
     if(!(f instanceof Tulip)) return false; 
     return (f.eaten = true); 
    } 
} 

Я использую instanceof для обеспечения соблюдения этого различия, где каждое животное ест только один тип цветка. Я хотел бы сделать это, изменив подписи метода черепах и носорогов до eatFlower(Tulip t) и eatFlower(Rose r) соответственно, но я не думаю, что это возможно на Java.

Есть ли лучший способ, чем использовать instanceof, чтобы обеспечить соблюдение этого?

ответ

2

Да, есть лучший способ. Вероятно, вы не хотите применять этот параметр в параметре.

Причина, по которой существует различие между временем выполнения и полиморфизмом времени компиляции. Прямо сейчас, вы должны знать (все) типы цветов, которые животное может есть, когда вы компилируете код. Это не позволяет вам изменять эти данные без обновления кода и теряет достаточную абстракцию.

Контракт Animal заключается в том, что он ест какой-то тип Flower, но вы не знаете, что это сразу. Фактически, только это конкретное животное точно знает, какой тип цветка ему нравится. Возможно, у вас есть Rhino с непереносимостью до BlueRose, кто должен есть только RedRose s.

Если вы не знаете, что все Rhino s съедят все Rose s и готовы совершить это навсегда (или до вашей следующей крупной версии), вы не должны делать его частью интерфейса публичный контракт. В какой-то момент в ближайшем будущем s могут понять, что Daisies в равной степени восхитительны, и рождается подвид, который может есть и то, и другое. Как только что-то открыто, вы можете сделать его менее ограничительным.

Когда Rhino приходит на Flower, он должен выбрать, есть ли он, чтобы съесть этот особый цветок. Носорог не перечисляет все хорошие цветы, когда он просыпается каждое утро, поэтому вы, вероятно, не должны жестко закодировать их все в своем коде.

У вас есть два варианта, в зависимости от того, как вы хотите применить этот выбор. Вы можете проверить, что пройденный Flower - это instanceof известный тип, который требует, чтобы вы знали, что все хорошие типы - это время компиляции. Вы также можете добавить метод FlowerType getType() на номер Flower, назовите это, и сравните результаты с Set<FlowerType> goodFlowers`. Это позволяет вам изменять приемлемые цветы во время выполнения, если это необходимо.

Говоря в целом, несколько тестов instanceof (которые вы получите, если носороги могут когда-либо есть другой вид цветка) часто могут быть индикатором дефекта дизайна. Они могут нанести ущерб абстракции, тесно связав два не связанных друг с другом типа и могут быть заменены данными (из перечисления, базы данных, файла или другого источника).

2

Вы можете использовать дженерики. Что-то вроде этого:

public abstract class Animal<T extends Flower> { 
    abstract void eatFlower(T f); 
} 

public class Rhino extends Animal<Rose> { 
    void eatFlower(Rose f) { 

    } 
} 
Смежные вопросы