2012-06-27 32 views
4

重複使用前面的例子,想象一個動物園,新到達的動物必須由Zookeeper「處理」(想想將它們檢入動物園)。每隻動物的檢查過程取決於其類別分類(哺乳動物,鳥類等)。泛型的正確用法是什麼解決了這個編譯錯誤?

由於分類系統的基本差異,這些過程有所不同 - 例如,鳥類有翅膀,哺乳動物有牙齒。你可能也有一些過程的共同點,對所有的動物都是如此,但我在這裏忽略了它們。

下面是代碼:

Animal.java

public interface Animal { 

    public AnimalProcessor<? extends Animal> getAnimalProcessor(); 
} 

Mammal.java

public abstract class Mammal implements Animal { 

    @Override 
    public AnimalProcessor<Mammal> getAnimalProcessor() { 

     return new MammalProcessor(); 
    } 

    // Specific to mammals 
    public abstract int getToothCount(); 

} 

Bird.java

public abstract class Bird implements Animal { 

    @Override 
    public AnimalProcessor<Bird> getAnimalProcessor() { 

     return new BirdProcessor(); 
    } 

    // Specific to birds 
    public abstract float getWingspan(); 
} 

AnimalProcessor.java

public interface AnimalProcessor<T extends Animal> { 

    public void process(T critter); 
} 

MammalProcessor.java

public class MammalProcessor implements AnimalProcessor<Mammal> { 

    @Override 
    public void process(Mammal a) { 
     System.out.println("Tooth count is " + a.getToothCount()); 
    } 

} 

BirdProcessor.java

public class BirdProcessor implements AnimalProcessor<Bird> { 

    @Override 
    public void process(Bird a) { 
     System.out.print("Wingspan is " + a.getWingspan()); 
    } 

} 

Badger.java

public class Badger extends Mammal { 

    @Override 
    public int getToothCount() { 
     return 40; 
    } 
} 

Condor.java

public class Condor extends Bird { 

    @Override 
    public float getWingspan() { 
     return 2.9f; 
    } 
} 

ZooKeeper.java

import java.util.List; 

public class ZooKeeper { 

    public void processNewAnimals(List<Animal> newcomers) 
    { 
     for(Animal critter : newcomers) 
     { 
      AnimalProcessor<? extends Animal> ap = critter.getAnimalProcessor(); 

         // This line has a compilation error! 
      ap.process(critter); 
     } 
    } 
} 

MainClass.java

import java.util.LinkedList; 
import java.util.List; 

public class MainClass { 

    public static void main(String[] args) { 

     ZooKeeper keeper = new ZooKeeper(); 

     List<Animal> animals = new LinkedList<Animal>(); 

     animals.add(new Badger()); 
     animals.add(new Condor()); 

     keeper.processNewAnimals(animals); 

    } 
} 

沒有警告的任何地方,但ap.process(牛馬)不能編譯。 我知道這是因爲AnimalProcessor<Bird>而不是類型AnimalProcessor<Animal>但我看不出如何解決問題。撥打電話<T extends Animal>getAnimalProcessor()將返回一個合適的AnimalProcessor<T extends Animal>,但我不能在代碼中表達這一點。

也許我不應該把動物處理程序放在第一位?

當然,目標是能夠在不更改核心的情況下添加Reptile

+0

爲什麼動物的接口,而不是一個抽象類?一個接口應該是某種共享行爲。 – carmenism

+0

我接受你的觀點,並且在我的代碼中改變了它 - 但編譯錯誤仍然存​​在。 – pjm56

回答

5
public interface Animal<THIS extends Animal<THIS>> { 
    AnimalProcessor<THIS> getAnimalProcessor(); 
} 
public abstract class Mammal implements Animal<Mammal> { 

有點像Enum<E extends Enum<E>>

刪除該方法可能是一個更好的主意。

+0

我不相信我以前見過這種方法嗎?它有名字嗎? – pjm56

+0

對不起,刪除哪種方法? getAnimalProcessor()?在這種情況下,如何讓代碼的其餘部分發揮作用? – pjm56

+0

我應該指出,我故意添加了getAnimalProcessor方法,以便將兩個並行繼承層次結構(Animal vs AnimalProcessor)結合在一起。 – pjm56

2

AnimalProcessor。Java的:

public interface AnimalProcessor<T extends Animal> { 
    public void process(Animal critter); 
} 

MammalProcessor.java

public class MammalProcessor implements AnimalProcessor<Mammal> { 
    @Override 
    public void process(Animal a) { 
     System.out.println("Tooth count is " + ((Mammal)a).getToothCount()); 
    } 
} 
+0

謝謝伊賀 - 我可以看到這樣做工作,但希望能夠巧妙地使用泛型來避免沮喪,我認爲你無法忽視這一點的根本原因是getAnimalProcessor方法可以讓你取出一個動物的處理器,並有可能將它用於任何其他動物(它可能是錯誤的子類型),也許不可能在沒有在你確定類型匹配的地方使用強制轉換的情況下「擺放這個圓圈」。這個? – pjm56

+0

你已經被投票了! – pjm56

相關問題