考虑以下类别:

@Getter
public class EmailVO {
    private final Long id;
    private final String firstName;
    private final String email;
    private final String address;

    @Slf4j
    @Component
    @Scope("prototype")
    public static class Builder {
        private Lead lead;

        private Long id;
        private String firstName;
        private String email;
        private String address;

        public Builder fromLead(Lead lead) {
            this.lead = lead;
            return this;
        }

        public EmailVO build() {
            if (lead == null) {
                log.error("Failed to build EmailVO: lead was not initialized");
                return new EmailVO(this);
            }

            User user = lead.getUser();
            id = user.getId();
            firstName = user.getFirstName();
            email = user.getEmail();
            address = user.getAddress();

            return new EmailVO(this);
        }
    }

    private EmailVO(Builder builder) {
        id = builder.id;
        firstName = builder.firstName;
        email = builder.email;
        address = builder.address;

        if (id == null ||
            firstName == null ||
            email == null ||
            address == null)
        {
            throw new IllegalStateException(); // Maybe some ohter Unchecked Exception would be better
        }
    }
}


据我所知,这将是一个适当的VO类实现,它仅允许从其构建器构建新实例,该实例也充分遵循了构建器模式(如果我错了,请纠正我)。

从SOLID的角度来看,此代码很好,因为构建器的单一职责是聚集数据以构建EmailVO,并且其构造器将负责使仅有效的实例生效。

现在,如果您关心代码的混乱和可读性(假设情况下的VO更大),则当构建器尝试在未初始化所需参数的情况下尝试构建时,构建器可能会失败,而不是让对象的构造函数失败,从而可能删除内部的许多null检查构造函数。在示例代码中,如果lead字段为null,则此验证可能引发异常,而不是让EmailVO的构造函数检查完整性,尽管这是构造函数的责任。

可以从EmailVO的构造函数中删除验证,然后让构建器来处理它吗?考虑到在这种情况下,构造函数为private使其对此类外部不可见。

尽管如果构建器未验证必需的参数,它可能会失败,这似乎违反了SOLID,这是其责任之一,那就是聚合必需的数据以构建EmailVO实例。

但是,一个让我大吃一惊的想法是将一个标志用作EmailVO.Builder类的成员字段,以表示是否成功聚集了必需的参数,然后EmailVO的构造函数只能检查(并信任)该标志。

最佳答案

考虑到您的EmailVO仅用于保存值,
我建议您最小化设置器和构造器中的登录名(@Christopher Schneider注释的变体)。

如果要验证
您可以将验证方法添加到EmailVO对象。

关于“错误值生成”问题,将验证添加到生成器。

EmailVO验证可能包括类似“这是有效构造的电子邮件地址”之类的内容。

另外,不要将构建器传递给EmailVO对象,只需具有该构建器使用的程序包访问构造器即可。确保构建器与EmailVO对象位于同一程序包中。

09-10 20:28