开发者

Is there a pattern for using DTO's without having to duplicate the domain object's properties?

开发者 https://www.devze.com 2023-04-04 08:51 出处:网络
I\'d like to use DTO\'s in my view models in lieu of my domain objects, however I\'m having a hard time justifying the maintenance overhead of having to maintain two sets of properties for each domain

I'd like to use DTO's in my view models in lieu of my domain objects, however I'm having a hard time justifying the maintenance overhead of having to maintain two sets of properties for each domain object.

I was wondering if anyone has implemented or knows of a pattern where the properties of a domain object are separated from the object's actions without having to maintain two sets of properties.

One thought I had would be to have my domain object be only properties and attaching the actions as a subclass:

public class Person{
    private String firstName;
    private String lastName;

    public String getFirstName(){
        return this.firstName;
    }

    public String setFirstName(string firstName){
        this.firstName = firstName;
    }

    ...
}

public class PersonActions extends Person{
    public void save(){
        ...
    }

    public Person get(){

    }
}

This way still feels a b开发者_运维知识库it kludgy as I'd have to pass around a PersonAction class if I wanted a full representation of the domain object.


You could use an interface exposing only your object's data, without any domain methods. You'd still need to maintain two classes, but that would be a lot easier since most of the changes could be refactored by your IDE (Eclipse for example). Here's an example:

public interface PersonView {
    String getFirstName();
    String setFirstName();
}

public void Person implements PersonView {
    private String firstName;

    @Override // This annotation guarantees the interface is correct 
    public String getFirstName() {
        return firstName;
    }

    ...domain methods...
}

Is not a perfect solution, but it's a pretty clean one.

As for the problem itself, I for one don't really mind exposing the whole object to the view layer. IMHO, I don't think hiding some methods is worth the overhead. The team should have the discipline to use the objects wisely, but that's just my opinion.


Here is another idea:

Use the domain object and only annotate the methods you want exposed. You can make it so they require explicit exposition by Qualifying access type as NONE that way you don't have accidental data exposure

Example:

@Entity // hibernate
@XmlAccessorType(XmlAccessType.NONE) // for DTO
@XmlRootElement
public class Survey {
    @Column(name = "Title") // hibernate 
    @Basic // hibernate
    @XmlElement // for use as DTO
    private String title;

    @XmlElement(name = "report")
    public SurveyReport getSurveyReport() {
          // ... do some stuff here
    }
}

By using this approach you get the best of both worlds. Additionally, you can expose 'meta' information with methods and then annotate the method (available because of XmlAccessType.NONE).

The biggest drawbacks I see:

  1. Annotation explosion resulting in difficult to maintain code

  2. Monolithic object with many methods

    • Which may be great for view consumption but not really so appropriate for internal code
    • Leading to API confusion
    • see #1
  3. At the end of the day you may not be able to represent the view you want without combining information from multiple domain objects; leaving you right back to needing an explicit DTO anyways


Just make your model (Person) a property of your controller (PersonActions):

public class PersonActions {

    private Person person;

    public PersonActions() {
        person = new Person(); // Or get existing one from DAO in case of edit.
    }

    public void save() {
        somePersonDAO.save(person);
    }

    public Person getPerson() {
        return person;
    }

}

Based on your question history I understand that you're using Struts. In that case, it's good to know that JSP EL supports nested object properties, something like this to retrieve the values:

${personActions.person.firstName}
${personActions.person.lastName}

There's no need to flatten them by duplicating the properties in the controller.


One approach is to have a property in your View Model which is your DTO object.

Another approach is to duplicate the properties, but use something similar to AutoMapper to map between the objects.

In our latest project we have the DTO object as a property, but we also expose the individual properties in the View Model, which reference the properties in the DTO object.

0

精彩评论

暂无评论...
验证码 换一张
取 消