[英]builder pattern - methods with preconditions
為了進行測試 ,我有一個Factory
,它使用Builder
來生產Product
。 每個Product
都有一個狀態( Available
/ InUse
/ Disposed
的/ etc)。 我需要生產各種狀態的產品。
我的問題是,為了讓我產生一個Product
有,比方說, Disposed
狀態時,它首先必須是InUse
(必須使用創建new ProductBuilder().CheckIn().Dispose().Build();
不只是new ProductBuilder().Dispose().Build();
)
我( 或必須? )如何對構建器方法強制執行此先決條件,並使圈復雜度保持為1 (因此不需要進一步測試)。
我不想使用諸如if (product.Status == Product.INUSE) {...}
並為每種可能的情況拋出exceptions
(不同的狀態需要不同的前提條件)。
由於構建器是私有的,我是否需要強制執行此操作? 我是否僅依靠程序員知道方法的調用順序,並在每個構建器方法之前添加一些注釋? 我選擇其他模式(哪個?)。
public static class ProductFactory
{
private class ProductBuilder
{
private Product product;
public ProductBuilder()
{
product = new Product {Status = product.AVAILABLE};
}
public ProductBuilder Dispose()
{
product.Status = product.DISPOSED; return this;
}
public ProductBuilder CheckIn()
{
product.Status = product.INUSE; return this;
}
public Product Build()
{
return product;
}
}
public static Product CreateAvailable()
{
return new ProductBuilder().Build();
}
public static Product CreateInUse()
{
return new ProductBuilder().CheckIn().Build();
}
public static Product CreateDisposed()
{
return new ProductBuilder().CheckIn().Dispose().Build();
}
}
首先,您必須在多個接口之間分離這些方法( CheckIn
和Disposed
):
public interface IBaseBuilder
{
Product Build();
}
public interface IProductBuilder : IBaseBuilder
{
ICheckedInProductBuilder CheckIn();
}
public interface ICheckedInProductBuilder : IBaseBuilder
{
IDisposedProductBuilder Dispose();
}
public interface IDisposedProductBuilder : IBaseBuilder
{
}
這樣,給定一個初始的IProductBuilder
:
CheckIn
> Dispose
CheckIn
,就無法再次調用 Dispose
,就無法再次調用 Build
來創建產品。 為了使事情更容易實現,您可以讓一個類實現所有三個接口,然后使用主要IProductBuilder
接口將其注入其客戶端。 或者,您可以讓不同的類實現接口。 我將其保留為練習。
作為一個真實的示例,此技術已在Moq和FluentAssertions中廣泛使用以實現流利的API。
相關: 使我的課堂“流利”
除了返回ProductBuilder
,您還可以通過返回接口來抽象實現。 這樣,您可以使某些方法僅通過首先接收該接口才可用。
讓我用代碼解釋。 假設Disposed
功能僅在InUse
之后才可用,然后您可以執行以下操作:
public interface IInUseProductBuilder
{
IDisposedProductBuilder Dispose();
}
public interface IDisposedProductBuilder
{
IBuiltProductBuilder Build();
}
當您實現它時:
public class ProductBuilder : IInUseProductBuilder, IDisposedProductBuilder
{
public IDisposedProductBuiler Dispose()
{
product.Status = product.DISPOSED;
return this;
}
}
這樣,用戶將只能使用在該特定構建器上聲明的方法,您將根據您的工作流程公開這些方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.