构建器模式和大量必需参数

spe*_*dRS 57 java parameters design-patterns builder

到目前为止,我使用构建器模式的以下实现(与此处描述的实现相反):

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) { ... }
}
Run Code Online (Sandbox Code Playgroud)

这适用于我遇到的大多数情况,我需要使用各种必需/强制和可选参数来构建复杂对象.然而,最近我一直在努力了解当所有参数都是强制性的(或至少绝大多数参数)时,模式是如何有益的.

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

例如,而不是:

Widget example = new Widget.Builder(req1, req2, req3,req4,req5,req6,req7,req8)
                           .addOptional(opt9)
                           .build();
Run Code Online (Sandbox Code Playgroud)

分组如下:

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();
Run Code Online (Sandbox Code Playgroud)

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

什么是最佳实践,是否有更好的方法可以解决这个问题?

dea*_*mon 36

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

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

  • 此步骤构建器实现的唯一缺点(就像使用 builder() 参数 impl 一样)是需要按特定顺序指定参数。修复这个问题需要每个构建器 2^n 个类(n 是强制参数的数量)。如果生成了生成器,这不是问题,但绝对不是您想要使用超过 3 个强制参数手动编写的内容。 (5认同)

Ber*_*t F 28

然而,最近我一直在努力了解当所有参数都是强制性的(或至少绝大多数参数)时,模式是如何有益的.

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

  1. 它更具可读性 - 它有效地允许命名参数,因此调用不仅仅是一长串未命名的参数

  2. 它是无序的 - 这允许您将参数组合成逻辑组,作为单个构建器设置器调用的一部分,或者只是让您使用自然顺序来调用最能够理解此特定实例的构建器setter方法.


Widget example = new Widget.Builder(req1, req2, req3,req4,req5,req6,req7,req8)
                               .addOptional(opt9)
                               .build();
Run Code Online (Sandbox Code Playgroud)

分组如下:

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();
Run Code Online (Sandbox Code Playgroud)

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

在适当或自然的时候,我会赞成混合动力.它不必全部在构造函数中,或者每个param都有自己的addParam方法.Builder可让您灵活地执行其中一个,中间或组合:

Widget.Builder builder = new Widget.Builder(Widget.BUTTON);

builder.withWidgetBackingService(url, resource, id);
builder.withWidgetStyle(bgColor, lineWidth, fontStyle);
builder.withMouseover("Not required");

Widget example = builder.build();
Run Code Online (Sandbox Code Playgroud)