2010-05-17 28 views
0

我總是傾向於遇到以下設計問題,我從來不確定如何最好地解決問題。它通常與動物的層次開始於我的馬戲團:有關動態子類層次結構處理設計的問題

Animal 
    Cat 
    BigCat 
    Dog   
    Elephant 
    ... 

現在,每個動物需要接受培訓,以便有針對每一個單獨的方法:

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

的問題是,馬戲團導演不給一個該死的。他只是把動物扔給訓練師,甚至沒有看。現在

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 2010-05-17 19:09:11

+0

@Jake:不幸的是,是的,但作爲樣板,它是相當小的。 – GaryF 2010-05-17 19:27:09

+0

@Jake:特定動物的方法不能成爲培訓師的一部分 - 破壞基本的封裝。特定動物的訓練方法必須是動物的一部分,而不是訓練師。所以每隻動物必須提供特定訓練方法。 acceptTrainer是在Director,Trainer和每個Animal實例之間形成API的一種方法。 – 2010-05-17 19:45:12

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

} 

然後保持教練同樣如此。所有的動物都會得到適當的調度。