2017-07-27 68 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 –