我应该在DTO中使用构建器模式吗?

12
这可能是一个相当主观的问题,但我想知道更多的意见。 我使用Spring MVC构建了一个Rest API服务,并实现了DTO-Domain-Entity模式。 我想知道您对在DTO中实现Builder pattern的看法,例如:
public class UserResponseDTO
    extends AbstractResponseDTO {

    private String username;
    private Boolean enabled;

    public UserResponseDTO(String username, Boolean enabled) {
        this.username = username;
        this.enabled = enabled;
    }

    public String getUsername() {
        return this.username;
    }

    public Boolean getEnabled() {
        return this.enabled;
    }

    public static class Builder {

        private String username;
        private Boolean enabled;

        public void setUsername(String username) {
            this.username = username;
        }

        public void setEnabled(Boolean enabled) {
            this.enabled = enabled;
        }

        public UserResponseDTO build(){
            return new UserResponseDTO(username, enabled);
        }
    }
}

根据定义:

建造者设计模式的目的是将复杂对象的构建与其表示分离。通过这样做,相同的构建过程可以创建不同的表示形式。

在我大多数DTO案例中(甚至可以说全部),我没有更复杂的对象需要构建,就像这个案例一样。而且,老实说,如果我们在谈论DTO,则无法想出任何构建复杂对象的示例。

有助于使不可变对象更易于使用并清晰化代码的模式之一是建造者模式。

建造者模式提供了对象的不可变性。因此,我们可以认为DTO本身就是服务响应,不应该被更改,因为这是一种响应(至少这就是我的想法)。


那么你认为呢?我应该对DTO使用这种模式吗(考虑到这种情况,以及可能的大多数情况都不符合复杂对象原则)?


1
我认为在这里使用构建器或工厂并没有什么好处。然而,DTO通常是由DTO组装器(即工厂)组装的。我认为主要动机是关注点分离,DTO的责任是作为数据容器,而组装器的责任是将DTO组装起来。 - plalx
1
我喜欢建造者模式。我喜欢用它们来创建不可变对象。DTO的问题在于你不能让类是不可变的(至少在我们的情况下,这基本上会阻止喜欢POJO的Hibernate正常工作)。有时我会在DTO对象中添加构建器,但我的担心是没有办法通过代码强制使用它们。然后你最终会看到人们在其他地方编写对象创建逻辑。 - Marvo
1
我不会使用构建器来强制实现不可变性。更容易的方法是发布一个没有setter的接口。实现对象将具有在生成bean时使用的私有setter。客户端代码不需要访问实现类。@Marvo提到了Hibernate的好处。 - jgitter
1
这就是它的全部。人们不使用构建器来强制不可变性。但是,构建器对于强制正确实例化类以及避免难以阅读和使用的“望远镜构造函数”非常有用。但是,如果您无法更改类的设计以强制使用构建器(例如使其不可变并提供工厂或构建器),则可能会有人不熟悉代码编写自己的实例化代码。http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2 - Marvo
谢谢大家!我想我明白了。 - jscherman
1个回答

25

我的简短回答是这取决于个人喜好。如果你喜欢建造者模式的工作方式,请使用它。对于这样一个小案例,我认为无论如何都不重要。我的个人偏好是不在这里使用建造者,因为它似乎并没有增加太多价值。

我的更长回答是建造者模式旨在促进复杂对象的更轻松配置,而不必采用像伸缩构造函数之类的反模式。在这种情况下,两种选项都很小巧高效,不存在反模式。

顺便说一下,谈到个人喜好,我更喜欢使用修改后的建造者模式,使用流畅接口;每个方法返回建造者实例,以便可以将方法调用链接在一起(而不是单独的行)。这类似于您链接的文章中的Java示例。

我将修改您的构建器如下:

public static class Builder {

        private String username;
        private Boolean enabled;

        public Builder setUsername(String username) {
            this.username = username;
            return this; 
        }

        public Builder setEnabled(Boolean enabled) {
            this.enabled = enabled;
            return this;
        }

        public UserResponseDTO build(){
            return new UserResponseDTO(username, enabled);
        }
    }

因此,使用构建器的方式看起来会像这样:

UserResponseDTO ur = new Builder().setUsername("user").setEnabled(true).build();

再次强调,这只是个人偏好问题。


很好。在我看来,流畅的构建器模式更加清晰易懂。 - mothmonsterman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接