java - 如何确保构建器模式完成?

标签 java design-patterns builder-pattern

编辑:我不担心以错误的顺序被调用,因为这是通过使用多个接口(interface)强制执行的,我只是担心终端方法被调用。


我正在使用构建器模式在我们的系统中创建权限。我选择了构建器模式,因为安全性在我们的产品中非常重要(它涉及未成年人所以 COPPA 等),我觉得权限必须是可读的,并且觉得可读性是最重要的(即使用流利的-style 构建器模式,而不是具有 6 个值的单个函数)。

代码如下所示:

 permissionManager.grantUser( userId ).permissionTo( Right.READ ).item( docId ).asOf( new Date() );

这些方法填充了一个私有(private)的支持 bean,在终端方法(即 asOf )将权限提交给数据库之后;如果该方法没有被调用,则什么也不会发生。有时开发人员会忘记调用终端方法,这不会导致编译器错误,并且在快速阅读/浏览代码时很容易错过。

我该怎么做才能避免这个问题?我不想返回需要保存的 Permission 对象,因为这会引入更多噪音并使权限代码更难阅读、遵循、跟踪和理解。

我考虑过在终端命令标记的支持上放置一个标志。然后,检查 finalize 方法中的标志,如果对象是在没有持久化的情况下创建的,则写入日志。 (我知道 finalize 不能保证运行,但这是我能想到的最好的。)

最佳答案

解决方案

构造此流畅 API 模式的一个好方法是,不只是从每个方法返回this,而是返回一个方法对象模式 实现了一个 Interface,它只支持列表中应该是 next 的方法,并让最后一个方法调用返回您需要的实际对象。

如果这是获取该对象实例的唯一方法,则必须始终调用最后一个方法。

Q6613429.java

package com.stackoverflow;

import javax.annotation.Nonnull;
import java.util.Date;

public class Q6613429
{
    public static void main(final String[] args)
    {
        final Rights r = PermissionManager.grantUser("me").permissionTo("ALL").item("EVERYTHING").asOf(new Date());
        PermissionManager.apply(r);
    }

    public static class Rights
    {
        private String user;
        private String permission;
        private String item;
        private Date ofDate;

        private Rights() { /* intentionally blank */ }
    }

    public static class PermissionManager
    {
        public static PermissionManager.AssignPermission grantUser(@Nonnull final String user)
        {
            final Rights r = new Rights(); return new AssignPermission() {

                @Override
                public AssignItem permissionTo(@Nonnull String p) {
                    r.permission = p;
                    return new AssignItem() {
                    @Override
                    public SetDate item(String i) {
                        r.item = i;
                        return new SetDate()
                    {
                        @Override
                        public Rights asOf(Date d) {
                            r.ofDate = d;
                            return r;
                        }
                    };}
                };}
            };
        }

        public static void apply(@Nonnull final Rights r) { /* do the persistence here */ }

        public interface AssignPermission
        {
            public AssignItem permissionTo(@Nonnull final String p);
        }

        public interface AssignItem
        {
            public SetDate item(String i);
        }

        public interface SetDate
        {
            public Rights asOf(Date d);
        }
    }
}

这加强了构造调用链,并且对代码完成非常友好,因为它显示了下一个接口(interface)是什么,并且它是唯一可用的方法。

这是一个更完整的例子,中间有一些可选的东西:

UrlBuilder.java

这提供了一种构造 URL 对象的万无一失的无检查异常方法。

将持久性与构造混合在一起就是混合关注:

创建对象和存储它是不同的关注点,不应混为一谈。考虑到 .build() 并不意味着 .store(),反之亦然,buildAndStore() 指出混合关注立即做不同地方的不同事物,你会得到你想要的保证。

将您对持久性代码的调用放在另一个方法中,该方法只接受一个完全构造的 Rights 实例。

关于java - 如何确保构建器模式完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6613429/

相关文章:

java - ExecutorService关闭不中断线程

c# - 如何创建和设置多态属性?

Java 对象引用问题?

java - builder 模式会不会做得太多?

java - 在eclipse java中设置构建路径

java - 在特定情况下,Hibernate 不会从带有子对象的集合中删除对象

java - 解码期间无效的 XML 字符

.net - 将 ASP.NET MVC 转换为 n 层架构

c# - DAO 只负责 CRUD 操作?

java - 自动生成 Java 接口(interface)的不可变类和匹配的构建器类