【问题标题】:Class design - manual cast alternatives类设计 - 手动铸造替代品
【发布时间】:2018-03-12 20:40:01
【问题描述】:

问题与以下课程有关。 Zookeeper1 和 Zookeeper2 是我可以使用的 2 个替代方案。我可以在 Zookeeper 中存储不同类型的动物。我应该能够获得这些课程。在第一种情况下,我将所有动物都存储在列表中(这意味着将来我可以轻松添加其他新动物),但是当我需要获取它时,我需要用 (Dog) 施放狗。在某个地方读到演员表是代码气味,所以我想看看是否有其他选择?其他解决方案会阻止投射,但每次添加新动物时都会出现添加新列表的问题。

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

【问题讨论】:

  • 这样的一般性问题很难回答。为什么你首先有 getDog 方法 - 为什么你没有 getCat 方法?肯定不行的是return (Dog)animals.get(animalId);,因为您事先没有进行任何类型检查,这种方法只会在一半的时间里崩溃......
  • @luk2302 而不是 getCat,我会使用 getAnimal,因为它没有特定于 Cat 的方法。该代码只是为了使其易于阅读而模拟(我想会有额外的检查以确保它是一只狗)。

标签: java oop inheritance class-design


【解决方案1】:

想象一下,我写了 ZooKeeper1 类,却不知道 Dog 类,然后把它传给了你。然后您决定扩展该类并添加方法Dog getDog(AnimalId id)

您希望这能正常工作吗?如果您看到推理中的差距,那么您就会明白为什么铸造是一个坏主意。

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

【讨论】:

    【解决方案2】:

    好的,所以在研究了 Java 中的异构容器之后,我想这将是迄今为止我最好的选择?有这类解决方案的 cmet 吗?

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-16
      • 1970-01-01
      • 2022-01-09
      • 1970-01-01
      • 1970-01-01
      • 2013-01-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多