java – 这个怪物生成器是一个很好的Builder / Factory模式,用于抽取与setter混合的长构造函数?

这是一个关于将step builder patternenhancedwizard构建器模式结合到creational DSL中的人机界面问题。它使用流畅的界面,尽管它使用方法链接不是级联。也就是说,这些方法返回不同的类型。

我正在面对一个具有两个构造函数的怪物类,它们混合了int,Strings和一串Strings。每个构造函数都是10个参数长。它还有约40个可选的设置者;如果一起使用,其中一些会相互冲突。它的构造代码看起来像这样:

Person person = Person("Homer","Jay", "Simpson","Homie", null, "black", "brown", 
  new Date(1), 3, "Homer Thompson", "Pie Man", "Max Power", "El Homo", 
  "Thad Supersperm", "Bald Mommy", "Rock Strongo", "Lance Uppercut", "Mr. Plow");

person.setClothing("Pants!!");     
person.setFavoriteBeer("Duff");
person.setJobTitle("Safety Inspector");

这最终失败了,因为事实证明设置了最喜爱的啤酒和职位是不兼容的。叹。

重新设计怪物类不是一个选择。它被广泛使用。有用。我只是不想看到它直接构造了。我想写一些干净的东西,喂它。一些遵循其规则的事情,而不让开发人员记住它们。

与我一直在研究的美妙的建筑模式相反,这个东西不是味道或类别。在需要的时候,它需要一些时间和其他领域的一些领域,一些仅取决于之前设置的内容。构造器不伸缩。他们提供了两种替代方法来使课程进入相同的状态。他们长而丑。他们想要喂养他们是独立的。

一个流利的建设者一定会使长的构造函数更容易看。然而,大量的可选设置器将所需的设置器混合在一起。并且要求级联流利的构建器不能满足:编译时间执行。

构造函数强制开发人员显式添加必填字段,即使使其为空。当使用级联流利的构建器时,这会丢失。与设置者一样失败的方式。我想要一种保持开发人员建立的方法,直到每个必填字段被添加。

与许多建筑师模式不同,我之后不是不变的。我正在离开课堂,因为我发现它。我想知道构造的对象处于良好状态,只需要查看构建它的代码即可。无需参考文档。这意味着它需要通过有条件的步骤来让程序员。

Person person = PersonBuilder

 // -- These have good default values, may be skipped, and don't conflict -- //
.doOptional()
    .addClothing("Pants!!")   //Could also call addTattoo() and 36 others

 // -- All fields that always must be set.  @NotNull might be handy. -- //
.doRequired()                 //Forced to call the following in order
    .addFirstName("Homer")
    .addMiddleName("Jay")
    .addLastName("Simpson")
    .addNickName("Homie")
    .addMaidenName(null)      //Forced to explicitly set null, a good thing
    .addEyeColor("black")
    .addHairColor("brown")
    .addDateOfBirth(new Date(1))
    .addAliases(
            "Homer Thompson",
            "Pie Man",
            "Max Power",
            "El Homo",
            "Thad Supersperm",
            "Bald Mommy",
            "Rock Strongo",
            "Lance Uppercut",
            "Mr. Plow")

 // -- Controls alternatives for setters and the choice of constructors -- //
.doAlternatives()           //Either x or y. a, b, or c. etc.
    .addBeersToday(3)       //Now can't call addHowDrunk("Hammered"); 
    .addFavoriteBeer("Duff")//Now can’t call addJobTitle("Safety Inspector");  

.doBuild();                 //Not available until now

人可以在addBeersToday()之后构建,因为在这一点上,所有的构造函数信息都是已知的,但直到doBuild()才被返回。

public Person(String firstName, String middleName, String lastName,
               String nickName, String maidenName, String eyeColor, 
               String hairColor, Date dateOfBirth, int beersToday, 
               String[] aliases);

public Person(String firstName, String middleName, String lastName,
               String nickName, String maidenName, String eyeColor, 
               String hairColor, Date dateOfBirth, String howDrunk,
               String[] aliases);

这些参数设置的字段绝对不能保留默认值。 beersToday和howDrunk设置相同的字段不同的方式。 favoriteBeer和jobTitle是不同的字段,但是会引起与类的使用冲突,所以只能设置一个。它们由setter处理而不是构造函数。

doBuild方法返回一个person对象。这是唯一的一个,人是唯一的返回类型。当人完全初始化时。

在界面的每个步骤中,返回的类型并不总是相同的。改变类型是如何通过步骤来指导开发人员。它只提供有效的方法。在完成所有需要的步骤之前,doBuild()方法是不可用的。

The do/add prefixes are a kludge to make writing easier because the changing return type
mismatches with the assignment and makes intelisense recommendations become alphabetical
in eclipse. I’ve confirmed intellij doesn’t have this problem. Thanks NimChimpsky.

这个问题是关于界面的,所以我接受不提供实现的答案。但如果你知道一个,请分享。

如果你建议一个替代模式,请显示它正在使用的界面。使用示例中的所有输入。

如果你建议使用这里介绍的界面,或者有些微小的变化,请保护它不要像this这样的批评。

我真正想知道的是,如果大多数人喜欢使用这个界面建立或其他。这是人机接口的问题。这是否违反了PoLA?不要担心实施有多困难。

但是,如果您对实现好奇:

A failed attempt(没有足够的状态或了解有效vs不违约)

A step builder implementation(对于多个构造函数或替代方案,不够灵活)

An enhanced builder(静音,但具有灵活状态)

Wizard builder(提供分叉但不记得选择构造函数的路径)

Requirement:

  • The monster (person) class is already closed to modification and extension; no touchy

Goals:

  • Hide the long constructors since the monster class has 10 required parameters
  • Determine which constructor to call based on alternatives used
  • Disallow conflicting setters
  • Enforce rules at compile time

Intent:

  • Clearly signal when default values are not acceptable
一个静态内部建设者,由josh bloch着名的有效的java。

必需的参数是构造函数args,可选的是方法。

一个例子。调用只需要用户名:

RegisterUserDto myDto = RegisterUserDto.Builder(myUsername).password(mypassword).email(myemail).Build();

和底层代码(省略明显的实例vars):

private RegisterUserDTO(final Builder builder) {
        super();
        this.username = builder.username;
        this.firstName = builder.firstName;
        this.surname = builder.surname;
        this.password = builder.password;
        this.confirmPassword = builder.confirmPassword;
    }


    public static class Builder {
        private final String username;

        private String firstName;

        private String surname;

        private String password;

        private String confirmPassword;

        public Builder(final String username) {
            super();
            this.username = username;
        }

        public Builder firstname(final String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder surname(final String surname) {
            this.surname = surname;
            return this;
        }

        public Builder password(final String password) {
            this.password = password;
            return this;
        }

        public Builder confirmPassword(final String confirmPassword) {
            this.confirmPassword = confirmPassword;
            return this;
        }

        public RegisterUserDTO build() {
            return new RegisterUserDTO(this);
        }
    }
http://stackoverflow.com/questions/22909717/is-this-monster-builder-a-good-builder-factory-pattern-for-abstracting-long-co

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:java – 这个怪物生成器是一个很好的Builder / Factory模式,用于抽取与setter混合的长构造函数?