Java改进特定类的Builder模式

时间:2013-06-29 12:57:22

标签: java builder

目前我有这个实现Builder模式的类,为了便于阅读,我选择省略一些方法,更准确地说,我只显示username的构建方法。

package dao.constraint;

import java.util.Arrays;

public class AccountConstraint {
    private Constraint<Range<Integer>> accountIdConstraint;
    private Constraint<String> usernameConstraint;
    private Constraint<String> passwordConstraint;
    private Constraint<String> emailConstraint;

    private AccountConstraint(Builder builder) {
        this.accountIdConstraint = builder.accountIdConstraint;
        this.usernameConstraint = builder.usernameConstraint;
        this.passwordConstraint = builder.passwordConstraint;
        this.emailConstraint = builder.emailConstraint;
    }

    public Constraint<Range<Integer>> getAccountIdConstraint() {
        return accountIdConstraint;
    }

    public Constraint<String> getUsernameConstraint() {
        return usernameConstraint;
    }

    public Constraint<String> getPasswordConstraint() {
        return passwordConstraint;
    }

    public Constraint<String> getEmailConstraint() {
        return emailConstraint;
    }

    public Constraint[] getConstraints() {
        return Arrays.asList(this.getAccountIdConstraint(), this.getUsernameConstraint(), this.getPasswordConstraint(), this.getEmailConstraint()).toArray(new Constraint[4]);
    }

    public static class Builder {
        private Constraint<Range<Integer>> accountIdConstraint;
        private Constraint<String> usernameConstraint;
        private Constraint<String> passwordConstraint;
        private Constraint<String> emailConstraint;

        public Builder() {
            this.accountIdConstraint = null;
            this.usernameConstraint = null;
            this.passwordConstraint = null;
            this.emailConstraint = null;
        }

        public Builder username(final String username) {
            this.usernameConstraint = new Constraint<>(Operation.IS, true, username, "username");
            return this;
        }

        public Builder notUsername(final String username) {
            this.usernameConstraint = new Constraint<>(Operation.IS, false, username, "username");
            return this;
        }

        public Builder usernameLike(final String username) {
            this.usernameConstraint = new Constraint<>(Operation.LIKE, true, username, "username");
            return this;
        }

        public Builder usernameNotLike(final String username) {
            this.usernameConstraint = new Constraint<>(Operation.LIKE, false, username, "username");
            return this;
        }

        public AccountConstraint build() {
            return new AccountConstraint(this);
        }
    }
}

正如您所看到的,AccountConstraint.Builder.username(String s)AccountConstraint.Builder.notUsername(String s)之间存在非常微妙的差异。

我希望能够写出new AccountConstraint.Builder().not(username(s));之类的内容。但是,据我所知,如果在调用Java类中未定义username(String s),则这不是有效的Java语法。我不想再重复整个AccountConstraint.Builder()以达到username(String s)部分。任何解决方案?

第二个问题:AccountConstraint.getConstraints()可以改进或写得更简单吗?

问候。

3 个答案:

答案 0 :(得分:2)

在这种情况下,我发现非常优雅的是使用静态工厂方法编写实用程序类,如。

public static Constraint userName(...) { ... }

import static blabla.Utility.username;

然后,您可以在java中编写几乎声明性的人类可读查询。这与用于单元测试的hamcrest库非常相似,您可以在其中编写类似的内容。

Assert.assertThat(blabla, is(equalTo(nullValue()));

在这种情况下,Not应该实现Constraint并且只是否定嵌套(引用)约束,如下所示:

public static Constraint not(Constraint negated) { return new Not(negated); }

这导致代码如

PreparedStatement ps = new QueryBuilder()
 .select()
 .from(table("accounts")
 .where(not(username(equalTo("blabla")))
 .compile();

您可以为布尔组合添加静态工厂:

.where(and(
  .not(...),
  .not(or(...))

定义这样的约束(静态工厂方法而不是将它们添加到构建器中)因此使它们易于组合。

答案 1 :(得分:2)

你可以使not成为构建器的一个方法,设置一个标志,然后否定下一个约束。

private boolean negate = false;

public Builder not() {
    negate = true;
}

public Builder username(final String username) {
    this.usernameConstraint = new Constraint<>(Operation.IS, !negate, username, "username");
    negate = false;
    return this;
}

答案 2 :(得分:2)

关于你的第二个问题:

   public Constraint[] getConstraints() {
        return Arrays.asList(this.getAccountIdConstraint(), 
            this.getUsernameConstraint(),
            this.getPasswordConstraint(),
            this.getEmailConstraint())
            .toArray(new Constraint[4]);
    }

可以重写为:

   public Constraint[] getConstraints() {
        return new Constraint[] {
            this.accountIdConstraint,
            this.usernameConstraint,
            this.passwordConstraint,
            this.emailConstraint
        };
    }

但IMO,返回ListSet会比数组好。