我必须根据特定情况创建一个对象。我读到,解决方案可以是“工厂模式”,但就我而言,它有很多缺点。
例如:我有一个管理动物的应用程序。在某个时候,客户给我列出了必须创建的动物清单。使用工厂模式的解决方案应为:
//PRODUCTS
public interface Animal {
String getCall();
}
public class Dog implements Animal {
public String getCall() {
return "Bau";
}
}
public class Cat implements Animal {
public String getCall() {
return "Miao";
}
}
public class Cow {...}
public class Rooster{...}
public enum AnimalEnum {
Cat, Dog, Cow, Rooster
}
//FACTORY
public class AnimalFactory {
public Animal getAnimal (AnimalEnum type){
Animal retval = null;
switch (type){
case Cat:
retval = new Cat();
break;
case Dog:
retval = new Dog();
break;
case Cow:[...]
case Rooster[...]
}
return retval;
}
}
我认为这是一种代码气味。问题是我必须写案例证明,以检查客户想要哪种动物。此外,如果将来我想创建一个新的对象“ Tiger”,则必须更改所有工厂类。
我的问题是:有没有办法避免这种情况?是否有一种模式可以让我根据另一个参数创建对象,而不必像这样“级联if \ case-of”?
我当时在想使用命令模式,但最后我仍然遇到这种情况。
“代码气味”的概念及其对立的“干净的代码”可以追溯到Martin Fowler和Robert Martin,有关软件开发领域中olfactory, hygienic和moral simile的细微差别,请参见此帖子。
关于这个问题,您的想法是,这种枚举转换会带来臭味,这与马丁·福勒(Martin Fowler)最初的“ Refactoring: Improving the Design of Existing Code”版本一致,但他在2015 edition中撤回了这一观点。在这方面没有达成共识,在10万名声誉贡献者中也没有达成共识。 @ tim-biegeleisen宣称,2015年以后也不会发臭,@ mark-seemann insists that there is,根据他的意愿,只要宇宙存在就一定如此。
关于特定代码段的不满,您可以将实例创建移至Enum本身,从而避免使用switch语句,并且避免在增加枚举时忘记添加其他switch分支。
public enum AnimalEnum {
Cat(Cat::new),
Dog(Dog::new),
Cow(Cow::new),
Rooster(Rooster::new);
private final Supplier<Animal> createAnimal;
public Animal createInstance() {
return createAnimal.get();
}
AnimalEnum(Supplier<Animal> factory) {
this.createAnimal = factory;
}
}
[预计该提案将基于各个嗅觉器官的配置而引起争议,并且围绕臭味/干净的二分法,我想指的是this post,专门讨论这个问题,即枚举成员的功能是否会激怒我们的鼻子是否有正当理由。