2017-07-27 12 views
0

私は倉庫の自動化で、次のタスクのドメインモデルを作成しようとしています。インターフェイスで抽象度のレベルを分離するにはどうすればよいですか?

倉庫には多くの製品があります。製品は、液体または食料品、または部分ごとにすることができます。倉庫には、液体製品または他のすべての製品を梱包する2つの梱包ラインがあります。ピース・バイ・パーツ・プロダクトはパッキングを必要としません。ここで

は私のモデルは以下のとおりです。

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

ある問題がI'LL場合ということですIPackingLine.Pack(IProduct p)ILiquidProductのオブジェクトを誤って間違った梱包ラインに渡すことができます。しかし、より普遍的な方法でそれらを使用できるようにするには、すべての包装ラインをIPackingLineに実装する必要があります。

これを回避するにはどうすればよいですか?

+0

ジェネリックスを使用する必要があるようですので、特定のパッカーがパックできる種類のものを修飾することができます。言語を推測します(例: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/introduction-to-generics – jonrsharpe

+0

あなたの 'PackingManager'は、Open Close Principleを破ります。なぜ汎用/一般的な 'PackingManager'が必要ですか? –

+0

私は、使用する梱包ラインを決定する人が必要です。それ以外の場合、ロジックはアプリケーション全体に広がります。 'GetPackLineByProduct'に関してはここは簡単にするためのものです。実際のアプリケーションでは、私は 'IPackingLine'を構築するファクトリを挿入します –

答えて

1

私はあなたの問題を解決するために3つの主要な方法があると思う:どこでもIProduct

  1. 求人と実行時チェックの賛成でコンパイル時の型の安全性をドロップします。あなたがその道を辿る場合、少なくともIPackingLineが製品を梱包するのを拒否することを明示すべきです。

    など。

    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 –

関連する問題