3 回答

TA贡献2080条经验 获得超4个赞
在我的搜索中,我没有遇到任何人将此1称为反模式。
但是,很明显,如果您尝试使用未专门实施以支持此操作模式的经典构建器来执行此操作....它将无法正常工作。例如,Wikipedia 文章中关于 Builder 设计模式的示例 CarBuilderImpl
将状态放入急切创建的Car
实例中。该build()
方法只是返回该对象。如果您尝试以您建议的方式重用该构建器,您最终会修改一个Car
已经构建的。
您还需要担心另一个问题。在我们修改 WikipediaCarBuilder
示例以将实际车轮(而不是多个车轮)添加到Car
正在建造的汽车中时,我们必须担心创建共享相同车轮的汽车。
您可以在构建器实现中解决这些问题,但尚不清楚收益是否超过成本。
如果你将这种想法转移到使用工厂方法来做这件事,你会得出一个稍微不同的结论。
如果您将其作为“一次性”进行,那可能没问题。你有一个特定的需求,代码很笨拙......但问题也是如此。
如果您需要对许多不同的参数或参数组合执行此操作,则无法扩展。
如果创建的对象是可变的,那么这种方法在多线程环境中可能会出现问题,具体取决于您如何控制对用作模板的对象的访问。
1 - 对于某事物是否为反模式,没有明确的可衡量标准。这是一个见仁见智的问题。诚然,对于许多反模式来说,这种观点会有广泛的共识。

TA贡献1793条经验 获得超6个赞
每次你想通过一个小的修改来制作一个新的副本时,通过一个构建器来构建一个全新的实例似乎有点低效。更重要的是,听起来您需要类不可变的地方与 A 类之类的地方隔离。为什么不尝试这样的事情:
public interface ICarDataTransferObject {
public Integer GetId();
public String GetColor();
public String GetManufacturer();
public String GetModel();
public String GetUUID();
public Integer GetDoorCount();
public EngineType GetEngineType();
public Integer GetLength();
public Integer GetSafteyLevel();
}
public class CarDataTransferObject Implements ICarDataTransferObject {
private Integer _id;
private String _color;
private String _manufacturer;
private String _model;
private String _uniqueIdNr;
private Integer _nrOfDoors;
private EngineType _engineType;
private Integer _length;
private Integer _safetyLevel;
public Integer GetId() { return _id; }
public void SetId(Integer id) { _id = id; }
public String GetColor() { return _color; }
public void SetColor(String color) { _color = color; }
public String GetManufacturer() { return _manufacturer; }
public void SetManufacturer(String manufacturer) { _manufacturer = manufacturer; }
public String GetModel() { return _model; }
public void SetModel(String model) { _model = model; }
public String GetUUID() { return _uniqueIdNr; }
public void SetUUID(String uuid) { _uniqueIdNr = uuid; }
public Integer GetDoorCount() { return _nrOfDoors; }
public void SetDoorCount(Integer count) { _nrOfDoors = count; }
public EngineType GetEngineType() { return _engineType; }
public void SetEngineType(EngineType et) { _engineType = et; }
public Integer GetLength() { return _length; }
public void SetLength(Integer length) { _length = length; }
public Integer GetSafteyLevel() { return _safetyLevel; }
public void SetSafteyLevel(Integer level) { _safteyLevel = level; }
public CarDataTransferObject() {}
public CarDataTransferObject(ICarDataTransferObject other) { ... }
public ReadOnlyCarDataTransferObject AsReadOnly() {
return ReadOnlyCarDataTransferObject (this);
}
}
}
public class ReadOnlyCarDataTransferObject Implements ICarDataTransferObject {
private ICarDataTransferObject _dto = null;
public Integer GetId() { return _dto.GetId(); }
public String GetColor() { return _dto.GetColor(); }
public String GetManufacturer() { return _dto.GetManufacturer(); }
public String GetModel() { return _dto.GetModel(); }
public String GetUUID() { return _dto.GetUUID(); }
public Integer GetDoorCount() { return _dto.GetDoorCount(); }
public EngineType GetEngineType() { return _dto.GetEngineType(); }
public Integer GetLength() { return _dto.GetLength(); }
public Integer GetSafteyLevel() { return _dto.GetSafteyLevel; }
public ReadOnlyCarDataTransferObject (ICarDataTransferObject other) {
_dto = other;
}
}
现在,当您希望 A 类拥有任何人都无法修改的副本时,只需使用复制构造函数并仅公开该副本的只读版本。
public class A {
ICarDataTransferObject _dto;
ReadOnlyCarDataTransferObject _readOnlyDTO;
public ICarDataTransferObject GetDTO() { return _readOnlyDTO; }
public A(ICarDataTransferObject dto) {
_dto = new CarDataTransferObject(dto);
_readOnlyDTO = new ReadOnlyCarDataTransferObject(_dto);
}
}
您通常在 .NET 应用程序中看到这种方法。

TA贡献1752条经验 获得超4个赞
尽管您的静态方法是否是反模式尚有争议,但它肯定不会针对不同属性的组合进行扩展。尽管如此,即使它不是反模式,我认为有更好的方法来完成你所需要的。
有一个传统构建器模式的变体,它不是创建一个新的空构建器,而是接受一个已经构建的对象并创建一个已经初始化的构建器。以这种方式创建构建器后,您只需更改builder 中的length属性。最后,构建对象。用纯代码(没有龙目岛,对不起)它可能是这样的:
public class CarDataTransferObj {
private Integer id;
private String color;
// other attributes omitted for brevity
private Integer length;
// Private constructor for builder
private CarDataTransferObj(Builder builder) {
this.id = builder.id;
this.color = builder.color;
this.length = builder.length;
}
// Traditional factory method to create and return builder
public static Builder builder() {
return new Builder();
}
// Factory method to create and return builder initialized from an instance
public static Builder builder(CarDataTransferObj car) {
Builder builder = builder();
builder.id = car.id;
builder.color = car.color;
builder.length = car.length;
return builder;
}
// getters
public static class Builder {
private Integer id;
private String color;
private Integer length;
private Builder() { }
public Builder withId(Integer id) { this.id = id; return this; }
public Builder withColor(String color) { this.color = color; return this; }
public Builder withLength(Integer length) { this.length = length; return this; }
public CarDataTransferObj build() {
return new CarDataTransferObj(this);
}
}
}
现在有了所有这些基础设施,您可以轻松地做您想做的事情:
CarDataTransferObj originalCar = ... // get the original car from somewhere
CarDataTransferObj newCar = CarDataTransferObj.builder(originalCar)
.withLength(newLength)
.build();
这种方法的优点是它可以很好地扩展(它可以用来改变参数的任何组合)。也许所有这些构建器的代码看起来都是样板,但我使用 IntelliJ 插件通过两次击键创建构建器(包括接受构建实例以创建初始化构建器的变体工厂方法)。
添加回答
举报