Java 如何使所有生成器方法成为必需的?
我正在建设一个汽车类,有发动机,变速箱,离合器等。 我不想要一个包含7个参数的臃肿构造函数,所以我决定使用构建器模式。 所有零件都是必需的。 但是,我如何让Car类的用户使用所有零件的设置器,因为它们都是强制性的? 抛出异常Java 如何使所有生成器方法成为必需的?,java,Java,我正在建设一个汽车类,有发动机,变速箱,离合器等。 我不想要一个包含7个参数的臃肿构造函数,所以我决定使用构建器模式。 所有零件都是必需的。 但是,我如何让Car类的用户使用所有零件的设置器,因为它们都是强制性的? 抛出异常 public class Car { private Engine engine; private Chassis chassis; private GearBox gearBox; private Coupe coupe; pri
public class Car {
private Engine engine;
private Chassis chassis;
private GearBox gearBox;
private Coupe coupe;
private Exterior exterior;
private Interior interior;
private Clutch clutch;
public Car(Builder builder) {
engine = builder.engine;
chassis = builder.chassis;
gearBox = builder.gearBox;
coupe = builder.coupe;
exterior = builder.exterior;
interior = builder.interior;
clutch = builder.clutch;
}
public static class Builder {
private Engine engine;
private Chassis chassis;
private GearBox gearBox;
private Coupe coupe;
private Exterior exterior;
private Interior interior;
private Clutch clutch;
private Car build() {
return new Car(this);
}
public Builder setEngine(@NonNull Engine engine) {
this.engine = engine;
return this;
}
public Builder setChassis(@NonNull Chassis chassis) {
this.chassis = chassis;
return this;
}
public Builder setGearBox(@NonNull GearBox gearBox) {
this.gearBox = gearBox;
return this;
}
public Builder setCoupe(@NonNull Coupe coupe) {
this.coupe = coupe;
return this;
}
public Builder setExterior(@NonNull Exterior exterior) {
this.exterior = exterior;
return this;
}
public Builder setInterior(@NonNull Interior interior) {
this.interior = interior;
return this;
}
public Builder setClutch(@NonNull Clutch clutchs) {
this.clutch = clutchs;
return this;
}
}
}
我希望用户调用所有的生成器setter,而不是它们的可选子集。我该怎么做
有没有另一种方法来构造一辆汽车,而不需要一个需要这么多参数的巨大构造器
编辑:我看过了,但没有解决方案可以阻止大型构造函数。生成器适用于许多部件是可选的,或者您有许多不同的配置的情况。然后,使用
build()
方法确保特定配置有效。HTML生成器是有意义的,字符串生成器则不然
如果没有可选零件,则有以下选项:
- 摆脱构造器,使用需要所有部件的构造器。经典解决方案,可读性最低且难以扩展
- 您可以在
方法中为每个缺少的部分抛出异常。这需要编写很多代码,而且有点违背了模式build()
- 可以向生成器中添加具有多个参数的方法。这是上述两种情况的混合。您仍然在使用构建器模式(以便以后可以轻松添加更多配置),但您的API也可以更清楚地传达哪些部分是必需的 例如,您将来可能会得到一台发动机,它已经包含齿轮箱或需要一个特定的齿轮箱(即,当您使用此发动机时,您也会选择齿轮箱)。要实现这一点,您需要创建第二个生成器方法,该方法只需要请求引擎并自动确定齿轮箱
- 使用具有受保护方法的工厂来构建零件。工厂将确保为汽车提供所有零件。如果要替换零件,可以替代受保护的方法。如果您有很多默认设置,并且只有2-3个有用的配置,那么这将非常有效
- 使用多个构建器。不要用单个螺丝来制造所有东西,而是用更大的积木来制造你的汽车:推进、内饰、车身。使用构造器从这三个参数中创建汽车(三个参数很好)。现在您可以使用三个构建器来创建这三个。尝试在必需元素和可选元素之间找到平衡
- 链建设者如。这将强制用户填写所有部分(因为您只能调用链末尾的
)。这里的主要缺点是:需要编写大量代码,而且从用户角度来看很难遵循,因为代码分布在许多类中。这是一个例子;该项目将SQL语法实现为一个构建器链build()
Director应该调用interface builder上所需的所有方法(在您的案例中为“build engine、build coupe等”)。实现构建器接口的类必须重写所有方法,否则代码甚至无法编译。如果主要原因是使用流畅的API,而不是删除臃肿的构造函数,则可以将构建器链接在一起:
class Engine {}
class Door {}
class Car {
Car(Engine engine, Door door) {
}
}
class CarBuilder {
private Engine engine;
public CarWithEngineBuilder withEngine(Engine engine) {
this.engine = engine;
return new CarWithEngineBuilder();
}
class CarWithEngineBuilder {
private Door door;
public CarWithEngineAndDoor withDoor(Door door) {
this.door = door;
return new CarWithEngineAndDoor();
}
class CarWithEngineAndDoor {
public Car build() {
return new Car(engine, door);
}
}
}
}
class TestStuff {
{
Car c = new CarBuilder().withEngine(new Engine()).withDoor(new Door()).build();
}
}
或者,如果您主要关心的是构造函数的大小,那么可能构造函数正在告诉您一些事情,您可以查看该类,看到一些部分在逻辑上是“在一起”的。也就是说,
发动机
,齿轮
和制动器
是较大部件的一部分吗?汽车是否应该是驱动系统
和底盘
(包括外部
和内部
)。然后汽车
的构造器有一系列可管理的参数,就像驱动系统
和底盘
一样?回答得很好,但我想知道的是什么。选项3不会给代码的可读性带来同样的问题吗?我的意思是,你要么把参数加载到构造函数中,要么加载到生成器中的方法中。参数的数量不会改变。因此,选择2保持不变。但这与构建者模式的理念背道而驰,所以在这种情况下,重新考虑整个构建者模式不是最好的选择吗?@J.K:使用构建者模式的原因之一是为了防止丑陋。如果您愿意,我不会让build()
方法引发异常。一个好的不可变类将在返回新对象之前在其(私有)构造函数中强制其不变量。如果缺少必需的参数,则生成器调用的(私有)构造函数应抛出IllegalStateException
@MarkSmit:Correct。选项3不是完美的解决方案;如果你想留住建筑商,这是最好的折衷办法。也许他最好有一个工厂,有保护的方法来制造零件。然后他可以覆盖工厂以替换零件。@J.K.用创建发动机、齿轮箱等默认实例的方法替换setter。在build()
方法中调用它们。factory和builder之间的区别在于,factory知道如何在配置builder时进行构建,因为可能的配置太多。长构造函数很难阅读,更难更改。想象一下所有的地方