我有一个这样的枚举:
public static enum TestEnum {
// main
ENUM_A (1, "test1", TestADto.class),
ENUM_B (2, "test2", TestBDto.class),
ENUM_C (3, "test3", TestCDto.class),
...
private Class<? extends Dto> dtoClass;
public Class<? extends Dto getDtoClass() {
return dtoClass;
}
...
}
所有这些dto类都扩展了相同的abstract(dto)类:
public abstract class AbstractDto {
private String foo;
private int bar;
...
AbstractDto(AbstractClassNeededForInitialization o) {
this.foo = o.getFoo();
this.bar = o.getBar();
}
... some functions here ...
}
这将是TestADto的示例Dto实现:
@Getter
@Setter
public class TestADto extends AbstractDto {
private String anotherFoo;
private int anotherBar;
...
public TestADto(AbstractClassNeededForInitialization o) {
super(o);
}
... some functions here ...
}
是否有可能(即使用Java 8)在枚举引用类中创建这些的具体实例,而不需要知道它具体是什么?
让我说我在某个功能中的某个点并且我有一个Enum_A。现在我想创建一个dto实例(TestADto.class)。对此最好的方法或模式是什么?
想象一个包含100个以上条目的枚举,每个条目都有不同的dto,它扩展了相同的抽象dto或实现了一个接口。
如何在不编写大量if else或switch语句的情况下创建这些具体对象,或者逐个处理它。
我读过有关反射和代理的内容,但不确定这是否是正确的方式。或者目前的状态是否已经有了一种糟糕的设计? 我想要达到的一切是将dto名称分配给枚举,以便稍后在某些特定点创建它。但如果可能的话,不要创造一个巨大的条件......
@Edit
我忘了提到创建每个dto的实例需要有传递给构造函数的对象。传递给构造函数的这个对象也实现了一个接口。
答案 0 :(得分:8)
如果需要为DTO子类调用空构造函数,可以在存储在字段中的枚举构造函数中提供Supplier
:
...
ENUM_A (1, "test1", TestADto::new),
ENUM_B (2, "test2", TestBDto::new),
ENUM_C (3, "test3", TestCDto::new);
private Supplier<Dto> supplierDto;
TestEnum(int i, String name, Supplier<Dto> supplierDTO){
this.supplierDto = supplierDTO;
...
}
...
然后,您可以通过调用supplierDto.get();
编辑后:
我忘了提到创建每个dto的实例需要有 传递给构造函数的对象。
Supplier<Dto>
不再适用,因为它不适合与提供一个参数的构造函数一起使用。
假设您的构造函数是这样的:
public class TestADto{
...
private MyInterface myInterface;
public TestADto (MyInterface myInterface){
this.myInterface = myInterface;
}
...
}
你可以在枚举构造函数中声明一个Function <MyInterface, Dto>
参数来匹配这个构造函数。
...
ENUM_A (1, "test1", TestADto::new),
ENUM_B (2, "test2", TestBDto::new),
ENUM_C (3, "test3", TestCDto::new);
private Function <MyInterface, Dto> dtoConstructor;
TestEnum(int i, String name, Function <MyInterface, Dto> dtoConstructor){
this.dtoConstructor = dtoConstructor;
...
}
public Dto createInstance(MyInterface myInterface){
return myInterfaceToDtoFunction.apply(myInterface);
}
...
答案 1 :(得分:7)
David几乎就在那里,但你说构造函数需要一个参数,所以我就这样做了。出于本示例的目的,我假设您的构造函数采用String:
ENUM_A (1, "test1", TestADto::new),
ENUM_B (2, "test2", TestBDto::new),
ENUM_C (3, "test3", TestCDto::new);
private final Function<String, Foo> constructor;
TestEnum(int i, String name, Function<String, Foo> constructor){
this.constructor = constructor;
}
public Dto getInstance(final String argument)
{
return constructor.apply(argument);
}
答案 2 :(得分:1)
最简单的方法是对您手头上的getDtoClass()
实例的TestEnum
方法返回的Class对象使用反射。方法Class#newInstance()
将创建您拥有的任何类对象的实例。
这个解决方案假设在枚举中引用的所有类中都有一个零参数构造函数 - 感谢@Michael指出这一点。如果不是这种情况,您仍然可以使用反射,但可能需要查看Constructor
访问器类,它可以更强大地访问类中的所有构造函数。这个nice tutorial更详细地解释了构造函数的优点。
在需要时使用反射也具有本质上懒惰的明显优势。该实例仅在需要时创建,而不是在初始化枚举类时实例化所有类。
答案 3 :(得分:0)
让我们考虑一下AbstractDTO是所有DTO类扩展的类。 然后在您的枚举中,而不是存储对DTO类的引用,存储对目标DTO的对象的引用。如下所示的东西
public static enum TestEnum {
ENUM_A (1, "test1", new TestADto()),
ENUM_B (2, "test2", new TestBDto()),
ENUM_C (3, "test3", new TestCDto()),
...
private AbstractDTO dto;
TestEnum (arg1,arg2, AbstractDTO desiredDTO) {
this.dto = desiredDTO;
}
public AbstractDTO getDto() {
return dto ;
}
}