2017-07-27 119 views
0

我是自動化倉庫,我正在嘗試爲下一個任務創建域模型:如何分離具有接口的抽象級別?

倉庫有很多產品。產品可以是液體或雜貨,也可以是一件一件。倉庫中有兩條包裝線可以包裝液體產品或所有其他產品。逐件產品不需要包裝。

這裏是我的模型:

enum ProductType 
{ 
    Liquid, 
    Grossery 
} 

interface IProduct 
{ 
    ProductType ProductType { get; } 
} 

interface IPackedProduct : IProduct 
{ 
    bool IsPacked { get; } 
} 

interface ILiquidProduct : IProduct 
{ 

} 

interface IGrosseryProduct : IProduct 
{ 

} 

interface IPackingLine 
{ 
    IPackedProduct Pack(IProduct product); 
} 

interface IGrosseryPackingLine : IPackingLine 
{ 
    IPackedProduct Pack(IGrosseryProduct p); 
} 

class ProductPackingLine : IPackingLine 
{ 
    public IPackedProduct Pack(IProduct product) 
    { 
     Console.WriteLine("Packing {0} default packing line", product); 
     return new PackedProduct(product); 
    } 
} 

class LiquidsPackingLine : IPackingLine 
{ 
    public IPackedProduct Pack(ILiquidProduct product) // I want this <======================= 
    { 
     Console.WriteLine("Packing {0} by liquid packing line", product); 
     return new PackedProduct(product); 
    } 
} 

class GrosseryPackingLine : IPackingLine 
{ 
    public IPackedProduct Pack(IProduct product) 
    { 
     Console.WriteLine("Packing {0} by grossery packing line", product); 
     return new PackedProduct(product); 
    } 
} 

我使用的是這樣的:

IProduct milk = new LiquidProduct(ProductType.Liquid); 
IProduct pasta = new GrosseryProduct(ProductType.Grossery); 

var packer = new PackingManager(); 

IPackedProduct packedMilk = packer.Pack(milk); 
IPackedProduct packedPasta = packer.Pack(pasta); 

這裏是PackingManager

class PackingManager 
{ 
    public IPackedProduct Pack(IProduct product) 
    { 
     IPackingLine pl = GetPackingLineByProduct(product); 

     return pl.Pack(product); 
    } 

    private IPackingLine GetPackingLineByProduct(IProduct product) 
    { 
     switch (product.ProductType) 
     { 
      case ProductType.Liquid: 
       return new LiquidsPackingLine(); 

      case ProductType.Grossery: 
       return new GrosseryPackingLine(); 

      default: 
       throw new InvalidOperationException(); 
     } 
    } 
} 

的問題是,如果我會使用IPackingLine.Pack(IProduct p)我可以錯誤地將ILiquidProduct的對象傳遞給錯誤的包裝行。但我需要我所有的包裝線實施IPackingLine才能夠以更常見的方式使用它們。

如何避免這種情況?

+0

看來您需要使用泛型,因此您可以限定給定打包程序可打包的各種東西。猜測語言,參見例如https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/introduction-to-generics – jonrsharpe

+0

您的'PackingManager'打破了打開關閉原則。爲什麼你需要一個通用的/通用的'PackingManager'? –

+0

我需要某個人來決定使用哪一個包裝線。在其他情況下,邏輯將分散在整個應用程序中。關於'GetPackingLineByProduct' - 這只是爲了簡單起見。在真正的應用程序中,我會注入一個工廠,它將建立我'IPackingLine' –

回答

1

我認爲有解決你的問題3個主要方面:

IProduct到處
  1. 工作,並有利於運行時檢查的下降編譯時類型安全。如果你走下那條路,那麼你至少應該明確表示IPackingLine可能拒絕包裝產品。

    E.g.

    public interface IPackingLine { 
        IPackedProduct pack(IProduct product); 
        bool canPack(IProduct); 
    } 
    
  2. 使用某種雙重分發的(在dynamic關鍵字與重載方法,使這更容易在C#):

    public interface IPacker { 
         IPackedProduct pack(IProduct product); 
         IPackedProduct packLiquid(ILiquidProduct product); 
         IPackedProduct packGrossery(IGrosseryProduct product); 
        } 
    
        public interface IProduct { 
         IPackedProduct packWith(IPacker packer) 
        } 
    
        class LiquidProduct implements IProduct { 
         IPackedProduct packWith(IPacker packer) { 
          return packer.packLiquid(this); 
         } 
        } 
    
        //... 
    
  3. 如果可能的話,引入新的概念,將允許包裝線以同樣的方式對待任何一種產品。例如,假設您必須構建一個繪製正方形和三角形的應用程序。你可以有一個專門的畫家,但你也可以有一個單一的抽象形狀的畫家。例如。 painter.paint(triangle.getShape())

+0

我會去#1。謝謝。 –

+0

我已經像這樣創建了它:https://github.com/s-stude/ddd-examples/blob/master/WHAutomation_v1/Program.cs –