我自动化仓库,我正在尝试为下一个任务创建域模型:
仓库里有很多产品。产品可以是液体,杂货,也可以是一块一块。仓库中有两条包装线,用于包装液体产品或所有其他产品。逐件产品不需要包装。
以下是我的模特:
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 :(得分:1)
我认为有三种主要方法可以解决您的问题:
在任何地方使用IProduct
并删除编译时类型安全性,以支持运行时检查。如果你沿着这条路前进,那么你至少应该明确表示IPackingLine
可能拒绝包装产品。
E.g。
public interface IPackingLine {
IPackedProduct pack(IProduct product);
bool canPack(IProduct);
}
使用某种双重调度(带有重载方法的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);
}
}
//...
如果可能的话,引入新的抽象,使包装线能够以相同的方式处理任何类型的产品。例如,假设您必须构建一个绘制正方形和三角形的应用程序。你可以为每个人配备一个专门的画家,但你也可以拥有一个与抽象形状配合使用的画家。例如。 painter.paint(triangle.getShape())
。