如何在Builder设计模式中实现方法的条件可见性?

Pau*_*aul 6 java design-patterns

如何更改 Builder 设计模式中方法的可见性?

例如我有这个生成器:

public class Builder {

    public Builder a() {
        //
        return this;
    }

    public Builder b() {
        //
        return this;
    }

}
Run Code Online (Sandbox Code Playgroud)

用户可以使用 API 并执行以下操作:

new Builder().a().b();
new Builder().a();
new Builder().b();
new Builder().b().a();
Run Code Online (Sandbox Code Playgroud)

我只想允许他b()仅在a()被调用时访问方法:

new Builder().a().b();
new Builder().a();
Run Code Online (Sandbox Code Playgroud)

SQL 请求生成器就是一个简单的示例。when()之前不应该允许你打电话select()

怎么做呢?

Pau*_*aul 4

两种方法:StepBuilder模式,这里提到(感谢Eritrean),另一种是自定义模式,稍后描述。

\n
\n

步骤生成器

\n

在构建器类中,定义与构建应具有的“步骤”一样多的接口。接口中方法的返回类型返回到下一个方法应该可用的类型。

\n

这里b()只能在之后调用a()

\n
public class Builder {\n    /*\n     * next available methods are defined by \n     * the returned interface type\n     */\n    private static interface AStep {\n        BStep a();\n    }\n\n    private static interface BStep {\n       void b();\n    }\n\n    private static class Steps implements AStep, BStep {\n        BStep a() {\n            //\n            return this;\n        }\n\n        void b() {\n           //\n           return this;\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

使用抽象类的自定义方法(我称之为:AbstractBuilder

\n

由于我无法使用StepBuilder方法定义相同的方法名称,因此我尝试了其他方法。

\n
    \n
  • 我定义了一个 main Builder,其中包含第一个可调用方法(可见)、通用方法和build()方法(受保护,因为如果需要,它只能通过其他类使用)。

    \n
  • \n
  • 我定义了一个名为 的抽象类,AbstractBuilder它具有 type 属性Builder和设置该属性的构造函数。

    \n
  • \n
  • 我定义了与我的步骤一样多的构建器。所有这些构建器都会扩展AbstractBuilder,因此可以通过在实例上调用通用方法和结束方法(如果需要)Builder

    \n
  • \n
\n

它看起来像这样:

\n
public class AbstractBuilder {\n\n    protected Builder builder;\n\n    protected AbstractBuilder(Builder builder) {\n        this.builder = builder;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\xc2\xa0

\n
public class Builder {\n\n    public BStep a() {\n        //\n        return new BStep(this);\n    }\n\n    protected Object build() {\n        // \n        return null;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\xc2\xa0

\n
public class BStep extends AbstractBuilder {\n\n    protected BStep(Builder builder) {\n        super(builder);\n    }\n\n    public CStep b() {\n        //\n        return new CStep(builder);\n    }\n\n    public Object build() {\n        return builder.build();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\xc2\xa0

\n
public class CStep extends AbstractBuilder {\n\n    protected CStep(Builder builder) {\n        super(builder);\n    }\n    \n    public BStep and() {\n        //\n        return new BStep(builder);\n    }\n\n    public DStep c() {\n        //\n        return new DStep(builder);\n    }\n\n    public Object build() {\n        return builder.build();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\xc2\xa0

\n
public class DStep extends AbstractBuilder {\n\n    protected DStep(Builder builder) {\n        super(builder);\n    }\n    \n    public CStep and() {\n        //\n        return new CStep(builder);\n    }\n\n    public EStep d() {\n        // etc. ... return new EStep(builder);\n    }\n\n    public Object build() {\n        return builder.build();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

通过这种模式,您可以在每次调用后管理方法的可用性并使用“向后”循环:

\n
Builder builder = new Builder();\nbuilder.a().b().and().a().b().c().and().b().build();\n
Run Code Online (Sandbox Code Playgroud)\n