将DTO转换为实体子类

时间:2016-02-27 14:15:34

标签: java inheritance design-patterns

我目前的情况是我有一个abstract模型,许多其他模型继承自该模型。 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类相结合(这也违反了Law of Demeter)。

理想情况下,我想创建一个MapperTranslator类,将DTO转换为具体的子类,但我在初始化公共字段时遇到了以下问题: / p>

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;
    }
}

这似乎是一个非常简单的问题需要解决,但我似乎无法想出最完美的解决方案。是否有更好的解决方案?

1 个答案:

答案 0 :(得分:2)

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;
    }
}