My current situation is that I have an abstract
model, in which many other models inherit from. The API consumes a "DTO" object, that is essentially one big object that contains all of the possible fields for each subclass, due to the client calling the service. I've created a solution for this, but it feels like it has some bad "smells". Here is an example of the setup:
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;
}
I want to convert the DTO to its concrete subclass with initialization. I've solved that by creating a factory and overriding a method in each of the subclasses:
public class PersonFactory {
public Person getInstance(String type) {
if (type.equals("Student")) {
return new Student();
} else if (type.equals("Employee")) {
return new Employee();
}
return new Person();
}
}
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;
}
}
So the calling class will do the following:
public Person createPerson(PersonDTO dto) {
Person person = new PersonFactory().getInstance(dto.type);
person.name = dto.name;
person.id = dto.id;
person.initialize(dto);
}
To put this into perspective a little more, the model superclass (in this example, Person
) has about 15 fields, and the subclasses can have up to 5 or 6, making using a constructor cumbersome. I feel like having the initialize
method is a bad practice, and couples the Person class to the DTO class (which I'd like neither class to know about the other).
Ideally, I'd like to create a Mapper
or Translator
class, that will translate the DTO into the concrete subclass, but I keep running into the following issue with initializing the common fields:
public class PersonMapper implements Mapper<PersonDTO, Person> {
public Person map(PersonDTO dto) {
if (person.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 (person.type.equals("Employee")) {
Employee person = new Employee();
setupCommonFields(person, dto);
person.startDate = dto.startDate;
return person;
}
return person;
}
private void setupCommonFields(Person person, PersonDTO dto) {
person.id = dto.id;
person.name = dto.name;
}
}
This seems like a clearly simple problem to solve, but I can't seem to come up with the most perfect solution. Is there a better-designed solution for this?
Aucun commentaire:
Enregistrer un commentaire