代码之家  ›  专栏  ›  技术社区  ›  Bojan Vukasovic

课堂设计-手动浇铸备选方案

  •  1
  • Bojan Vukasovic  · 技术社区  · 8 年前

    这个问题与下面的课程有关。Zookeeper1和Zookeeper2是我可以使用的两个备选方案。我将来可能会把不同类型的动物存放在动物园管理员的房间里。我应该能上那些课。在第一种情况下,我将所有动物都存储在列表中(这意味着将来我可以很容易地添加其他新动物),但我需要在需要时将狗和(狗)放在一起。读到一些关于强制转换是代码味道的地方,所以我想看看是否有其他选择?另一种解决方案可以防止施法,但在每次我添加新动物时都有添加新列表的问题。

    class AnimalId{}
    
    interface Animal{
        AnimalId getAnimalId();
        void breathe();
    }
    
    class Cat implements Animal{
        public AnimalId getAnimalId() { return null; }
        public void breathe() {}
    }
    
    class Dog implements Animal{
        public AnimalId getAnimalId() { return null; }
        public void breathe() {}
        public void bark(){}
    }
    
    class ZooKeeper1{
        Map<AnimalId, Animal> animals = new HashMap<>();    //future-proof
    
        void addAnimal(Animal a){
            animals.put(a.getAnimalId(), a);
        }
    
        void printAnimals(){
            animals.forEach((key, value) -> System.out.println(key));
        }
    
        Dog getDog(AnimalId animalId){
            return (Dog)animals.get(animalId);  //NOK - must type-cast!
        }
    
        public static void main(String[] args) {
            ZooKeeper1 zk1 = new ZooKeeper1();
            zk1.addAnimal(new Cat());
            zk1.addAnimal(new Dog());
            zk1.printAnimals();
            Dog d = zk1.getDog(new AnimalId());
            d.bark();
        }
    }
    
    class ZooKeeper2{
        Map<AnimalId, Cat> cats = new HashMap<>();
        Map<AnimalId, Dog> dogs = new HashMap<>();  //will need to add more lines in future
    
        void addCat(Cat c){
            cats.put(c.getAnimalId(), c);
        }
    
        void addDog(Dog d){
            dogs.put(d.getAnimalId(), d); //will need to add more lines in future
        }
    
        void printAnimals(){
            cats.forEach((key, value) -> System.out.println(key));
            dogs.forEach((key, value) -> System.out.println(key)); //will need to add more lines in future
        }
    
        Dog getDog(AnimalId animalId){
            return dogs.get(animalId);  //OK no type-cast
        }
    
        public static void main(String[] args) {
            ZooKeeper2 zk2 = new ZooKeeper2();
            zk2.addCat(new Cat());
            zk2.addDog(new Dog());
            zk2.printAnimals();
            Dog d = zk2.getDog(new AnimalId());
            d.bark();
        }
    }
    
    2 回复  |  直到 8 年前
        1
  •  0
  •   RWRkeSBZ    8 年前

    想象一下我写的课 ZooKeeper1 没有任何课堂知识 Dog 把它传给你。然后决定扩展类并添加方法 Dog getDog(AnimalId id) .

    你认为这会起作用吗?如果你看到了自己推理的差距,那么你就会明白为什么铸造是个坏主意。

    铸造并不是一个奇迹般的解决方案。使用它的唯一安全方法是只投射已知类型的对象;例如,如果存储 类型的变量中的实例 Animal ,那么您就可以确定 getAnimal(..) 至类型 .

        2
  •  0
  •   Bojan Vukasovic    8 年前

    好吧,在研究了Java中的异构容器之后,我想这是目前为止我拥有的最佳选择?对这种解决方案有何评论?

    interface Animal { AnimalId getId(); }
    class AnimalId { int id; AnimalId(int id){this.id = id;} public boolean equals(Object o){ return id==((AnimalId)o).id; } public int hashCode(){ return 1; } }
    class Cat implements Animal { AnimalId id; Cat(AnimalId id){this.id=id;} public AnimalId getId(){ return id; } public String catSpecific(){ return "CS"; } }
    class Dog implements Animal { AnimalId id; Dog(AnimalId id){this.id=id;} public AnimalId getId(){ return id; } public String dogSpecific(){ return "DS"; } }
    
    class Zoo {
        private Map<Class<? extends Animal>, Map<AnimalId, Animal>> animals = new HashMap<>();
    
        public <T extends Animal> void assignAnimal(T animal){
            animals.computeIfAbsent(animal.getClass(), k -> new HashMap<>()).put(animal.getId(), animal);
        }
    
        public <T extends Animal> T getAnimal(Class<T> type, AnimalId animalId){
            return type.cast(animals.get(type).get(animalId));
        }
    
        public static void main(String[] args) {
            Zoo zoo = new Zoo();
    
            AnimalId animalId = new AnimalId(1);
            Animal animal1 = new Cat(animalId);
            Animal animal2 = new Dog(animalId);
    
            zoo.assignAnimal(animal1);
            zoo.assignAnimal(animal2);
    
            Cat cat = zoo.getAnimal(Cat.class, animalId);
            Dog dog = zoo.getAnimal(Dog.class, animalId);
    
            System.out.println(cat.catSpecific());
            System.out.println(dog.dogSpecific());
        }
    }