Java 将DTO转换为实体子类
我目前的情况是,我有一个Java 将DTO转换为实体子类,java,inheritance,design-patterns,Java,Inheritance,Design Patterns,我目前的情况是,我有一个抽象的模型,其中许多其他模型都继承自它。API使用一个“DTO”对象,它本质上是一个大对象,包含每个子类的所有可能字段,这是因为客户端调用了服务。我已经为它创建了一个解决方案,但感觉它有一些难闻的“气味”。以下是一个设置示例: public abstract class Person { public Long id; public Long name; } public class Employee extends Person { publi
抽象的模型,其中许多其他模型都继承自它。API使用一个“DTO”对象,它本质上是一个大对象,包含每个子类的所有可能字段,这是因为客户端调用了服务。我已经为它创建了一个解决方案,但感觉它有一些难闻的“气味”。以下是一个设置示例:
public abstract class Person {
public Long id;
public Long name;
}
public class Employee extends Person {
public Date startDate;
}
public class Student extends Person {
public Double gpa;
}
public class PersonDTO {
public Long id;
public String name;
public Date startDate;
public Double gpa;
public String type;
}
我想通过初始化将DTO转换为它的具体子类。通过在每个子类中创建工厂并重写方法,我已经解决了这个问题:
public class PersonFactory {
public Person getInstance(String type) {
if (type.equals("Student")) {
return new Student();
} else if (type.equals("Employee")) {
return new Employee();
}
return null;
}
}
public class Student extends Person {
public Double gpa;
/**
* Initializes the additional fields in the subclass
* from the PersonDTO.
*/
@Override
public void initialize(PersonDTO dto) {
this.gpa = dto.gpa;
}
}
因此,调用类将执行以下操作:
public Person createPerson(PersonDTO dto) {
Person person = new PersonFactory().getInstance(dto.type);
person.name = dto.name;
person.id = dto.id;
person.initialize(dto);
}
为了进一步说明这一点,模型超类(在本例中,Person
)大约有15个字段,子类最多可以有5个或6个字段,这使得使用构造函数很麻烦。我觉得使用initialize
方法是一种不好的做法,它将Person类与DTO类耦合(这也违反了规范)
理想情况下,我希望创建一个Mapper
或Translator
类,将DTO转换为具体的子类,但在初始化公共字段时,我一直遇到以下问题:
public class PersonMapper implements Mapper<PersonDTO, Person> {
public Person map(PersonDTO dto) {
if (dto.type.equals("Student")) {
Student person = new Student();
setupCommonFields(person, dto); // required to call this method
person.gpa = dto.gpa; // inside of every block
return person;
} else if (dto.type.equals("Employee")) {
Employee person = new Employee();
setupCommonFields(person, dto);
person.startDate = dto.startDate;
return person;
}
}
private void setupCommonFields(Person person, PersonDTO dto) {
person.id = dto.id;
person.name = dto.name;
}
}
公共类PersonMapper实现映射器{
公众人物地图(PersonDTO dto){
如果(数据类型等于(“学生”)){
学生人数=新学生();
setupCommonFields(person,dto);//调用此方法需要
person.gpa=dto.gpa;//每个块的内部
返回人;
}else if(dto.type.equals(“员工”)){
员工人数=新员工();
设置公共字段(个人、dto);
person.startDate=dto.startDate;
返回人;
}
}
私有无效设置公共字段(个人、个人到dto){
person.id=dto.id;
person.name=dto.name;
}
}
这似乎是一个很容易解决的问题,但我似乎找不到最完美的解决方案。有更好的解决方案吗?公共类PersonMapper实现了Mapper{
public class PersonMapper implements Mapper<PersonDTO, Person> {
public Person map(PersonDTO dto) {
Person person = createPerson(dto);
setupCommonFields(person, dto);
return person;
}
private Person createPerson(PersonDTO dto) {
if (person.type.equals("Student")) {
Student person = new Student();
person.gpa = dto.gpa;
return person;
} else if (person.type.equals("Employee")) {
Employee person = new Employee();
person.startDate = dto.startDate;
return person;
}
}
private void setupCommonFields(Person person, PersonDTO dto) {
person.id = dto.id;
person.name = dto.name;
}
}
公众人物地图(PersonDTO dto){
人员=创建人员(dto);
设置公共字段(个人、dto);
返回人;
}
私人createPerson(PersonDTO dto){
if(person.type.equals(“学生”)){
学生人数=新学生();
person.gpa=dto.gpa;
返回人;
}else if(person.type.equals(“Employee”)){
员工人数=新员工();
person.startDate=dto.startDate;
返回人;
}
}
私有无效设置公共字段(个人、个人到dto){
person.id=dto.id;
person.name=dto.name;
}
}
1)在您的PersonFactory
中,您返回未知类型的new Person()
。而Person
是一个抽象类。这不会编译2)您可以调用setupCommonFields(person,dto)在PersonMapper#map方法中返回person之前的code>method。你不需要在每个街区都调用它。在这种情况下,您必须消除每个块中的返回,这没关系。@NikhilPatil最后我不能调用setupCommonFields
,因为person
将超出范围。如果我将person
声明移动到方法的顶部,我将不得不将其声明为person
,从而避免设置子类上的字段,例如,person.startDate=dto.startDate
@NikhilPatil我意识到在map
方法的末尾有一个额外的return person
方法是无效的,这可能促使了你的建议。Casey,看看这个临时生成的映射器实现。虽然,我不得不说我不明白你从哪里得到了person.type.equals(“学生”)
中的person
,但我在范围内没有看到任何这样的变量。嘿,Dragan,我注意到你在映射方面帮助了一些人。你能看看这个吗?我不知道如何解决这个问题: