1

我正在使用 Builder 模式来更轻松地创建对象。但是,标准构建器模式示例不包括我的代码中需要的错误检查。例如,对象中的accessibilitydemandMean数组Simulator应该具有相同的长度。代码的简要框架如下所示:

public class Simulator {
    double[] accessibility;
    double[] demandMean;

    // Constructor obmitted for brevity

    public static class Builder {
        private double[] _accessibility;
        private double[] _demandMean;

        public Builder accessibility(double[] accessibility) {
            _accessibility = accessiblity.clone();
            return this;
        }

        public Builder demandMean(double[] demandMean) {
            _demandMean = demandMean.clone();
            return this;
        }

        // build() method obmitted for brevity
    }
}

又例如,在促销优化问题中,有多种促销载体(例如传单、展示)和促销模式,它们是一组促销载体(例如无、仅宣传单、仅展示、宣传单和展示)。当我创建 时Problem,我必须定义一组可用的车辆,并检查促销模式是否使用这些车辆的子集而不是其他一些不可用的车辆,以及促销模式是否相同(例如,没有两种“仅限传单”的促销模式)。代码的简要框架如下所示:

public class Problem {
    Set<Vehicle> vehicles;
    Set<PromoMode> promoModes;

    public static class Builder {
        Set<Vehicle> _vehicles;
        Set<PromoMode> _promoModes;
    }
}

public class PromoMode {
    Set<Vehicle> vehiclesUsed;
}

我的问题如下:

  1. 是否有解决这种情况的标准方法?
  2. 调用方法时应该在构造函数中还是在构建器中进行错误检查build()
  3. 为什么这是“正确”的方法?
4

3 回答 3

2

当您在创建对象时需要保留不变量时,如果任何参数违反不变量,则停止构造。这也是一种快速失败的方法。
当您有大量参数时,构建器模式有助于创建对象。
这并不意味着您不进行错误检查。只要参数违反对象不变量,
只需抛出适当的RuntimeException

于 2013-03-23T18:14:41.117 回答
2

您应该使用构造函数,因为它更好地遵循单一责任原则。检查不变量不是 Builder 的责任。唯一真正的工作是收集构建对象所需的数据。
此外,如果您决定稍后将类更改为具有公共构造函数,则不必移动该代码。

您绝对不应该检查 setter 方法中的不变量。这有几个好处:
* 您只需要检查一次
* 在您的代码等情况下,您不能更早地检查您的不变量,因为您是在不同时间添加两个数组。您不知道您的用户将按什么顺序添加它们,因此您不知道应该使用哪种方法来运行检查。

除非您的构建器中的 setter 进行了一些密集的计算(这种情况很少发生 - 通常,如果需要某种计算,无论如何都应该在构造器中进行),“早期失败”并没有多大帮助,特别是因为像你这样的流利的构建器无论如何都只使用一行代码来构建对象,所以任何 try 块都会以任何方式包围整行。

于 2014-02-27T20:57:26.587 回答
0

“正确”的方法实际上取决于情况 - 如果构造不同大小的数组是无效的,我会说最好在构造中进行处理,越早捕获无效状态越好。

现在,例如,如果您可以更改数组并放入不同的数组 - 那么在调用它们时这样做可能会更好。

于 2013-03-23T18:16:00.453 回答