Class 设计 - 手动铸造替代方案
Class design - manual cast alternatives
问题与下面的 类 有关。 Zookeeper1 和 Zookeeper2 是我可以使用的两个替代方案。将来我可以在 Zookeeper 中存储不同类型的动物。我应该能够得到那些 类。在第一种情况下,我将所有动物都存储在列表中(这意味着将来我可以轻松添加其他新动物),但是当我需要获取它时,我需要将 dog 与 (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();
}
}
想象一下,我在 class Dog
一无所知的情况下写了 class ZooKeeper1
并将其传递给您。然后您决定扩展 class 并添加方法 Dog getDog(AnimalId id)
。
您认为这会奏效吗?如果您看到推理中的差距,那么您就会明白为什么转换是个坏主意。
铸造并不是一个奇迹般的解决方案。唯一安全的使用方法是只转换已知类型的对象;例如,如果您将 Dog
实例存储在类型 Animal
的变量中,那么您肯定知道可以将 getAnimal(..)
的结果转换为类型 Dog
。
好的,所以在研究了 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());
}
}
问题与下面的 类 有关。 Zookeeper1 和 Zookeeper2 是我可以使用的两个替代方案。将来我可以在 Zookeeper 中存储不同类型的动物。我应该能够得到那些 类。在第一种情况下,我将所有动物都存储在列表中(这意味着将来我可以轻松添加其他新动物),但是当我需要获取它时,我需要将 dog 与 (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();
}
}
想象一下,我在 class Dog
一无所知的情况下写了 class ZooKeeper1
并将其传递给您。然后您决定扩展 class 并添加方法 Dog getDog(AnimalId id)
。
您认为这会奏效吗?如果您看到推理中的差距,那么您就会明白为什么转换是个坏主意。
铸造并不是一个奇迹般的解决方案。唯一安全的使用方法是只转换已知类型的对象;例如,如果您将 Dog
实例存储在类型 Animal
的变量中,那么您肯定知道可以将 getAnimal(..)
的结果转换为类型 Dog
。
好的,所以在研究了 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());
}
}