2010-05-17 3 views
0

Я всегда сталкиваюсь с следующей проблемой проектирования, что я никогда не уверен, как наилучшим образом решить проблему. Она обычно начинается с иерархией животных в моем цирке:Вопрос о конструкции управления иерархией динамического подкласса

Animal 
    Cat 
    BigCat 
    Dog   
    Elephant 
    ... 

Теперь нужно каждое животное, чтобы пройти обучение, так что есть отдельный метод для каждого:

public interface Trainer { 
    void train(BigCat animal); 
    void train(Dog animal); 
    void train(Elephant animal); 
    // ... 
} 

Проблема заключается в том, что CircusDirector наплевать. Он просто бросает животных на Тренера, даже не глядя.

public class CircusDirector { 
    public void work() { 
     Trainer trainer = getTrainer(); 
     Animal animal = getAnimal(); 

     // ...and he doesn't know a frog from a pony, 
     // so he tries to just: 
     trainer.train(animal); 
    } 
} 

Теперь, тренер может получить дополнительный метод, как

void train(Animal animal); 

, где он будет использовать instanceof отправить животное в соответствующий метод, но это, кажется, некрасиво и не приходят рекомендуется. Есть ли лучшее решение с использованием дженериков?

ответ

2

Вы по существу реализовали половину visitor pattern. Вы можете иметь каждый из вашего животного обеспечивают acceptTrainer(Trainer t) метод, который затем вызвать t.train(this);

Ваш директор будет затем вызвать animal.acceptTrainer(trainer);

Кроме того, я думаю, что информация дженерики компилируется, так что вы не можете делать любые модные вещи, опираясь на их. Лучше всего ознакомиться с некоторыми шаблонами.

+0

Означает ли это, что каждый подкласс должен продолжать повторять метод acceptTrainer()? – Jake

+0

@ Jake: К сожалению, да, но, поскольку шаблонный шаблон идет, он довольно минимален. – GaryF

+0

@ Jake: методы, специфические для животных, не могут быть частью Тренера - это разрушает базовую инкапсуляцию. Методы обучения, связанные с животными, должны быть частью Animal, а не Trainer. Поэтому каждое Животное должно предоставить специальные методы обучения. acceptTrainer - это один из способов формирования API между директором, тренером и каждым экземпляром Animal. –

2

То, что вы описываете, выглядит так, что его можно решить довольно аккуратно с помощью the Visitor pattern или, точнее, с двойной отправкой.

Пусть ваши животные реализовать обучаемый интерфейс:

interface Trainable { 

    accept(Trainer trainer); 

} 

с реализацией как:

public Dog extends Animal implements Trainable { 

    //... other dog stuff 

    public accept(Trainer trainer) { 
    trainer.train(this); 
    } 

} 

А затем сохранить тренеру таким же образом. Все животные будут отправлены надлежащим образом.

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