3 回答

TA貢獻2080條經(jīng)驗 獲得超4個贊
在我的搜索中,我沒有遇到任何人將此1稱為反模式。
但是,很明顯,如果您嘗試使用未專門實施以支持此操作模式的經(jīng)典構(gòu)建器來執(zhí)行此操作....它將無法正常工作。例如,Wikipedia 文章中關于 Builder 設計模式的示例 CarBuilderImpl
將狀態(tài)放入急切創(chuàng)建的Car
實例中。該build()
方法只是返回該對象。如果您嘗試以您建議的方式重用該構(gòu)建器,您最終會修改一個Car
已經(jīng)構(gòu)建的。
您還需要擔心另一個問題。在我們修改 WikipediaCarBuilder
示例以將實際車輪(而不是多個車輪)添加到Car
正在建造的汽車中時,我們必須擔心創(chuàng)建共享相同車輪的汽車。
您可以在構(gòu)建器實現(xiàn)中解決這些問題,但尚不清楚收益是否超過成本。
如果你將這種想法轉(zhuǎn)移到使用工廠方法來做這件事,你會得出一個稍微不同的結(jié)論。
如果您將其作為“一次性”進行,那可能沒問題。你有一個特定的需求,代碼很笨拙......但問題也是如此。
如果您需要對許多不同的參數(shù)或參數(shù)組合執(zhí)行此操作,則無法擴展。
如果創(chuàng)建的對象是可變的,那么這種方法在多線程環(huán)境中可能會出現(xiàn)問題,具體取決于您如何控制對用作模板的對象的訪問。
1 - 對于某事物是否為反模式,沒有明確的可衡量標準。這是一個見仁見智的問題。誠然,對于許多反模式來說,這種觀點會有廣泛的共識。

TA貢獻1793條經(jīng)驗 獲得超6個贊
每次你想通過一個小的修改來制作一個新的副本時,通過一個構(gòu)建器來構(gòu)建一個全新的實例似乎有點低效。更重要的是,聽起來您需要類不可變的地方與 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;
}
}
現(xiàn)在,當您希望 A 類擁有任何人都無法修改的副本時,只需使用復制構(gòu)造函數(shù)并僅公開該副本的只讀版本。
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條經(jīng)驗 獲得超4個贊
盡管您的靜態(tài)方法是否是反模式尚有爭議,但它肯定不會針對不同屬性的組合進行擴展。盡管如此,即使它不是反模式,我認為有更好的方法來完成你所需要的。
有一個傳統(tǒng)構(gòu)建器模式的變體,它不是創(chuàng)建一個新的空構(gòu)建器,而是接受一個已經(jīng)構(gòu)建的對象并創(chuàng)建一個已經(jīng)初始化的構(gòu)建器。以這種方式創(chuàng)建構(gòu)建器后,您只需更改builder 中的length屬性。最后,構(gòu)建對象。用純代碼(沒有龍目島,對不起)它可能是這樣的:
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);
}
}
}
現(xiàn)在有了所有這些基礎設施,您可以輕松地做您想做的事情:
CarDataTransferObj originalCar = ... // get the original car from somewhere
CarDataTransferObj newCar = CarDataTransferObj.builder(originalCar)
.withLength(newLength)
.build();
這種方法的優(yōu)點是它可以很好地擴展(它可以用來改變參數(shù)的任何組合)。也許所有這些構(gòu)建器的代碼看起來都是樣板,但我使用 IntelliJ 插件通過兩次擊鍵創(chuàng)建構(gòu)建器(包括接受構(gòu)建實例以創(chuàng)建初始化構(gòu)建器的變體工廠方法)。
添加回答
舉報