Oop 如何将抽象级别与接口分离?
我正在自动化仓库,并尝试为下一个任务创建域模型: 仓库里有很多产品。产品可以是液态的,也可以是杂货店的,或者是一件一件的。仓库中有两条包装线,用于包装液体产品或所有其他产品。逐件产品不需要包装 以下是我的模型:Oop 如何将抽象级别与接口分离?,oop,interface,domain-driven-design,abstraction,Oop,Interface,Domain Driven Design,Abstraction,我正在自动化仓库,并尝试为下一个任务创建域模型: 仓库里有很多产品。产品可以是液态的,也可以是杂货店的,或者是一件一件的。仓库中有两条包装线,用于包装液体产品或所有其他产品。逐件产品不需要包装 以下是我的模型: enum ProductType { Liquid, Grossery } interface IProduct { ProductType ProductType { get; } } interface IPackedProduct : IProduct
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);
}
}
这是包装经理
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();
}
}
}
问题是,如果我使用ipackline.Pack(ipproduct p)
我可能会将ILiquidProduct
的对象错误地传递到错误的包装行。但我需要所有打包行来实现iPackline
,以便能够以更常见的方式使用它们
如何避免这种情况 我认为有三种主要方法可以解决你的问题:
IProduct
,放弃编译时类型安全性,支持运行时检查。如果你走这条路,那么你至少应该明确指出,iPackline
可能拒绝包装产品
例如
dynamic
关键字使C#中的分派更容易):
painter.paint(triangle.getShape())
似乎您需要使用泛型,这样您就可以限定某个特定打包机可以打包的东西的种类。猜测语言,请参见您的
PackingManager
打破了开-关原则。为什么你需要一个通用/通用的包装经理
?我需要一个能决定使用哪种包装线的人。在其他情况下,逻辑将分布在整个应用程序中。关于GetPackingLineByProduct
——这里只是为了简单起见。在真正的应用程序中,我将注入一个工厂,它将构建我的iPackline
比方说PackingManager
这是应用程序的某种服务层。我将使用#1。谢谢。我已经这样创建了它:
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();
}
}
}
public interface IPackingLine {
IPackedProduct pack(IProduct product);
bool canPack(IProduct);
}
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);
}
}
//...