簡體   English   中英

構建器模式-帶有前提條件的方法

[英]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();
    }
}

首先,您必須在多個接口之間分離這些方法( CheckInDisposed ):

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM