是否有一种模式可以在不复制域对象属性的情况下使用 DTO?

2022-09-02 04:51:16

我想在我的视图模型中使用DTO来代替我的域对象,但是我很难证明必须为每个域对象维护两组属性的维护开销。

我想知道是否有人已经实现或知道一种模式,其中域对象的属性与对象的操作分开,而不必维护两组属性。

我的一个想法是让我的域对象只是属性,并将操作作为子类附加:

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(){

    }
}

这种方式仍然感觉有点笨拙,因为如果我想要域对象的完整表示,我必须传递PersonAction类。


答案 1

您可以使用仅公开对象数据的接口,而无需任何域方法。您仍然需要维护两个类,但这要容易得多,因为大多数更改都可以由您的IDE重构(例如Eclipse)。下面是一个示例:

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

这不是一个完美的解决方案,但它是一个非常干净的解决方案。

至于问题本身,我真的不介意将整个对象暴露给视图层。恕我直言,我不认为隐藏一些方法是值得的。团队应该有纪律来明智地使用对象,但这只是我的观点。


答案 2

这是另一个想法:

使用域对象并仅对要公开的方法进行批注。您可以这样做,以便它们需要通过限定访问类型作为 NONE 进行显式阐述,这样您就不会意外地暴露数据

例:

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

通过使用这种方法,您可以获得两全其美的优势。此外,还可以使用方法公开“元”信息,然后对方法进行批注(由于 XmlAccessType.NONE 而可用)。

我看到的最大缺点:

  1. 注释爆炸导致代码难以维护

  2. 具有多种方法的整体对象

    • 这可能非常适合视图使用,但并不适合内部代码
    • 导致 API 混淆
    • 看到 #1
  3. 在一天结束时,如果不组合来自多个域对象的信息,您可能无法表示所需的视图;无论如何,您仍然需要一个明确的DTO