首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >构建器模式和大量强制参数

构建器模式和大量强制参数
EN

Stack Overflow用户
提问于 2011-09-05 08:04:22
回答 8查看 43.5K关注 0票数 71

到目前为止,我使用的是构建器模式的following实现(与描述的here实现相反):

代码语言:javascript
运行
复制
public class Widget {
    public static class Builder {
        public Builder(String name, double price) { ... }
        public Widget build() { ... }
        public Builder manufacturer(String value) { ... }
        public Builder serialNumber(String value) { ... }
        public Builder model(String value) { ... }
    }

    private Widget(Builder builder) { ... }
}

这对于我遇到的大多数情况都很有效,我需要用各种必需的/强制的和可选的参数来构建一个复杂的对象。然而,我最近一直在努力理解当你的所有参数都是强制的(或者至少是绝大多数参数)时,该模式是如何带来任何好处的。

解决这个问题的一种方法是对传递给它们自己的类的参数进行逻辑分组,以减少传递给构建器构造函数的参数数量。

例如,而不是:

代码语言:javascript
运行
复制
Widget example = new Widget.Builder(req1, req2, req3,req4,req5,req6,req7,req8)
                           .addOptional(opt9)
                           .build();

按如下方式分组:

代码语言:javascript
运行
复制
Object1 group1 = new Object1(req1, req2, req3, req4);
Object2 group2 = new Object2(req5, req6);

Widget example2 = new Widget.Builder(group1, group2, req7, req8)
                            .addOptional(opt9)
                            .build();

虽然单独的对象简化了很多事情,但如果一个人不熟悉代码,也会让事情变得有点难以理解。我考虑的一件事是将所有参数移动到它们自己的addParam(param)方法中,然后对build()方法中所需的参数执行验证。

什么是最佳实践,有没有我没有考虑过的更好的方法?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2011-09-05 09:26:50

然而,我最近一直在努力理解当你的所有参数都是强制的(或者至少是绝大多数参数)时,该模式是如何带来任何好处的。

流畅的构建器模式仍然是有益的:

setter的可读性更强-它有效地允许命名参数,因此调用不只是一长串未命名的参数

  1. 它的无序-这允许您将参数分组到逻辑组中,或者作为单个生成器
  2. 调用的一部分,或者只是通过使用自然的顺序调用生成器setter方法,从而最大限度地利用此特定instantiation.

新建控件示例=

Widget.Builder(req1,req2,req3,req4,req5,req6,req7,req8) .addOptional(opt9) .build();

按如下方式分组:

Object1 group1 =新Object1(req1,req2,req3,req4);Object2 group2 =新Object2(req5,req6);Widget example2 =新Widget.Builder(group1,group2,req7,req8) .addOptional()();

虽然单独的对象简化了很多事情,但如果一个人不熟悉代码,也会让事情变得有点难以理解。我考虑的一件事是将所有参数移动到它们自己的addParam(param)方法中,然后对build()方法中所需的参数执行验证。

在合适或自然的情况下,我更喜欢混合动力车。它不必都在构造函数中,或者每个参数都有自己的addParam方法。Builder使您可以灵活地执行其中一个、另一个、中间或组合:

Widget.Builder构建器=新建资源(Widget.BUTTON);builder.withWidgetBackingService(url,Widget.Builder,id);builder.withWidgetStyle(bgColor,lineWidth,fontStyle);builder.withMouseover(“非必填”);小部件示例= builder.build();

票数 37
EN

Stack Overflow用户

发布于 2016-03-07 23:25:05

如果您有许多必需的参数,则可以使用Step Builder。简而言之:您为每个强制参数定义一个接口,构建器方法返回下一个强制构建器接口或可选方法的构建器本身。构建器仍然是一个实现所有接口的类。

代码语言:javascript
运行
复制
interface StepB {
    StepBuilder b(String b);
}

interface StepA {
    StepB a(String a);
}

final class StepBuilder implements StepA, StepB {
    private String a;
    private String b;
    private String c = "";

    private StepBuilder() {
    }

    static StepA with() {
      return new StepBuilder();
    }

    // mandatory, from StepA
    @Override
    StepB a(String a) {
        this.a = a;
        return this;
    }

    // mandatory, from StepB
    @Override
    StepBuilder b(String b) {
        this.b = b;
        return this;
    }

    // optional
    StepBuilder c(String c) {
        this.c = c;
        return this;
    }

    Product build() {
        return new Product(a, b, c);
    }
}

用法:

代码语言:javascript
运行
复制
StepBuilder.with().a("hello").b("world").build();

// or with the optional parameter c
StepBuilder.with().a("hello").b("world").c("!").build();

像Kotlin和Scala这样的语言在这里更方便,因为它们提供了带有默认值的命名参数。

票数 54
EN

Stack Overflow用户

发布于 2011-09-05 08:43:05

我最近一直在努力理解,当你的所有参数都是强制的时,这个模式有什么好处

该模式简化了不可变类的创建,并提高了代码的可读性。考虑下面的Person类(具有传统的构造函数和构建器)。

代码语言:javascript
运行
复制
public static class Person {

    private static final class Builder {
        private int height, weight, age, income, rank;
        public Builder setHeight(final int height) { this.height = height; return this; }
        public Builder setWeight(final int weight) { this.weight = weight; return this; }
        public Builder setAge(final int age) { this.age = age; return this; }
        public Builder setIncome(final int income) {    this.income = income; return this; }
        public Builder setRank(final int rank) { this.rank = rank; return this; }
        public Person build() { return new Person(this); }
    }

    private final int height;
    private final int weight;
    private final int age;
    private final int income;
    private final int rank;

    public Person(final int height, final int weight, final int age, final int income, final int rank) {
        this.height = height; this.weight = weight; this.age = age; this.income = income; this.rank = rank;
    }

    private Person(final Builder builder) {
        height = builder.height; weight = builder.weight; age = builder.age; income = builder.income; rank = builder.rank;
        // Perform validation
    }

    public int getHeight() { return height; }
    public int getWeight() { return weight; }
    public int getAge() { return age; }
    public int getIncome() { return income; }
    public int getRank() {  return rank; }

}

哪种构造方法更容易理解?

代码语言:javascript
运行
复制
final Person p1 = new Person(163, 184, 48, 15000, 23);
final Person p2 = new Person.Builder().setHeight(163).setWeight(184).setAge(48).
    setIncome(15000).setRank(23).build();

解决此问题的一种方法是对传入到各自类的参数进行逻辑分组

当然,这是cohesion的原则,无论对象构造语义如何,都应该采用它。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7302891

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档