我创建了一个Photo类,其中包含很多属性,例如大小,文件名,纬度/经度,位置等。
public class Photo {
public string FileName { get; set; }
public string Title { get; set; }
public double Size { get; set; }
public DateTime CapturedDate { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
public string LocationName { get; set; }
public byte[] Data { get; set; }
}
我想创建一个此类的对象并通过逐步的方法填充其属性,在该方法中,每个步骤都需要先执行某种操作,然后再在该对象上设置一些值。
在快速而又肮脏的解决方案中,我只是创建了一些无效方法来填充对象属性,但是我认为这是反模式。
var photo = new Photo();
photo.FileName = "Photo 1"
SetExifData(photo, photoStream);
SetLocationName(photo);
DoSomethingElse(photo);
void SetExifData(Photo photo, Stream photoStream) {
//Read exit data from the photo stream and update the object
photo.Latitude = "10,0";
photo.Longitude = "10,0";
photo.CapturedDate = ....
}
void SetLocationName(Photo photo){
//Call external API to get location name from lat/lng
photo.LocationName = "London"
}
void DoSomethingElse(Photo photo){
}
最好将此对象传递给某种管道或构建器。哪种模式适合这种情况?
答案 0 :(得分:0)
只有您告诉我的内容,构建器模式才是可行的方法。可以创建它来支持流畅的界面(如果足够满足您的管道需求),或者作为设置更专门的管道模式时的中间步骤。
class PhotoBuilder
{
// All properties goes here
private string Latitude { get; set; }
private string Longitude { get; set; }
...
public PhotoBuilder WithExifDataFromStream(Stream photoStream)
{
Latitude = ...;
Longitude = ...;
...
return this;
}
public Photo Build() => return new Photo(...);
}
我建议隐藏构建器中的所有状态,并仅在最后将对象创建为只读对象。它使推理更加简单。
一种不太吸引人的替代方法是将设置器隐藏为内部设置器,并从构建器中使用它们。出于纯粹的原因,我倾向于尽量远离此类内部部件,但YMMV。对于非常大的结构肯定有帮助。即使采用这种方法,我还是敦促您只在最后暴露对象,以保持生成器和对象本身的分离。还要确保您传出一个“不可变的”对象,即调用Build
后,请立即清除对该照片的所有引用,以免无意中更改了对象在构建后的状态。
空闲状态:
我发现最好对您开始使用的这种构建器中的逻辑进行严格限制。当然,这将取决于您的用例,但是在较大的系统中,某些逻辑经常会在许多地方使用,而且我不止一次头痛地从一个不太干净的接口中重构出多用途功能。可能。
在这种情况下,这可以转换为SetLocation(double longitude, double latitude, string locationName)
和WithCaptureDate(...)
。这将使该构建器可以在更多场景中使用,并允许您稍后在需要时在其之上创建特殊功能。
我发现它也有助于单元测试和编写。例如,您没有将构建器绑定到Location API。当然,这也可以通过依赖注入(ILocationResolver
或类似方法)来解决,但是您可能正在查看使单一职责原则无效的对象。
最后,它很大程度上取决于您所构建的系统以及该特定类的要求。在创建另一个包装程序时,我会犯错,该包装程序完成所有位置和流解析的工作,但这是来自那些主要处理大型互连系统的人,这些系统对功能复用和可组合性的要求很高。如果系统非常小,可能只会带来不必要的复杂性。