在我正在进行的项目中,我必须多次创建他们的DTO中的不同对象。试图遵循不重复代码的原则,我试图创建一个像这样的通用类:
$cars->whereHas("finance", function ($query) {
$query->where('deposit', 1000)->where('term', 48)
->whereBetween('payment', 50, 200);
})->where('active', 1)->get();
但是,我无法直接实例化通用对象。
我想知道,我可以用什么方法来解决这个问题。
提前致谢
答案 0 :(得分:4)
你不能这样做,因为编译器和运行时都不能知道T和Tdto的具体类型,因此甚至不知道是否存在这样的构造函数。
但您可以改为Function<Tdto, T>
:
public List<T> tFromDto(List<Tdto> tdtoList, Function<Tdto, T> constructor){
List<T> tList = new ArrayList<>();
for(Tdto tdto : tdtoList){
tList.add(constructor.apply(tdto));
}
return tList;
}
您可以通过以下方式致电:
List<Foo> dtos = assemble.tFromDto(fooDTOs, Foo::new)
请注意,此方法不需要在泛型类中。它可以是通用的,可以是静态的(并使用流简化):
public static <T, D> List<T> fromDTOs(List<D> dtoList, Function<D, T> constructor){
return dtoList.stream().map(constructor).collect(Collectors.toList());
}
鉴于此方法的简单性,您甚至可以完全删除它。
答案 1 :(得分:0)
实际上,用非默认构造函数实现泛型对象是不可能的。
免责声明:我不是说这是最好的方法,特别是因为它涉及反思。您可能需要考虑使用JB Nizet建议的简化静态版本。然而,假设这只是一个最小的工作玩具示例,我将基于OP代码回答原始问题,并表明使用非默认构造函数构建通用对象确实是可能的。
<强> AssembleObjectFromDto.java:强>
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.lang.NoSuchMethodException;
import java.lang.InstantiationException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.out;
class AssembleObjectFromDto<T, Tdto>
{
public List<T> tFromDto(Class<T> clsT, Class<Tdto> clsTdto, List<Tdto> tdtoList)
throws NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException
{
List<T> tList = new ArrayList<>();
for(Tdto tdto : tdtoList)
tList.add(clsT.getConstructor(clsTdto).newInstance(tdto));
return tList;
}
public static void main(String[] args)
{
AssembleObjectFromDto<Obj, Dto> assembler = new AssembleObjectFromDto<>();
List<Dto> lstDto = Arrays.asList(new Dto(), new Dto(), new Dto(), new Dto());
try
{
List<Obj> lstObj = assembler.tFromDto(Obj.class, Dto.class, lstDto);
for(Obj o : lstObj)
System.out.println(o.getClass().getName());
}
catch(NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException ex)
{
System.out.println(ex);
}
}
}
<强> Dto.java:强>
class Dto {}
<强> Obj.java:强>
class Obj
{
private Dto dto;
public Obj(Dto dto)
{
this.dto = dto;
}
}
为了避免将前两个Class
参数传递给tFromDto(Class<T>, Class<Tdto>, List<Tdto>)
,可以使AssembleObjectFromDto
定义一个重载tFromDto(List<Tdto>)
的抽象类和两个抽象的getter来检索实际类型通用参数T
和Tdto
然后为所有必需类型专门化类。这应该使代码更具可读性,代价是有更多的类。此外,专业化应该易于使用代码生成工具自动化。
<强> AssembleObjectFromDto.java:强>
import java.util.List;
import java.util.ArrayList;
import java.lang.NoSuchMethodException;
import java.lang.InstantiationException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;
abstract class AssembleObjectFromDto<T, Tdto>
{
protected abstract Class<T> getProductClass();
protected abstract Class<Tdto> getAssemblerClass();
public List<T> tFromDto(List<Tdto> tdtoList)
throws NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException
{
return tFromDto(getProductClass(), getAssemblerClass(), tdtoList);
}
private List<T> tFromDto(Class<T> clsT, Class<Tdto> clsTdto, List<Tdto> tdtoList)
throws NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException
{
List<T> tList = new ArrayList<>();
for(Tdto tdto : tdtoList)
tList.add(clsT.getConstructor(clsTdto).newInstance(tdto));
return tList;
}
}
<强> AssembleObjFromDto.java:强>
import java.util.List;
import java.util.Arrays;
import static java.lang.System.out;
import java.lang.NoSuchMethodException;
import java.lang.InstantiationException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;
class AssembleObjFromDto extends AssembleObjectFromDto<Obj, Dto>
{
@Override
protected Class<Obj> getProductClass() { return Obj.class; }
@Override
protected Class<Dto> getAssemblerClass() { return Dto.class; }
public static void main(String[] args)
{
AssembleObjFromDto assembler = new AssembleObjFromDto();
List<Dto> lstDto = Arrays.asList(new Dto(), new Dto(), new Dto(), new Dto());
try
{
List<Obj> lstObj = assembler.tFromDto(lstDto);
for(Obj o : lstObj)
System.out.println(o.getClass().getName());
}
catch(NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException ex)
{
System.out.println(ex);
}
}
}
Dto.java,Obj.java: 与版本1相比保持不变。