产品结构如下(简化):
public class ParentProduct { }
public sealed class ChildProduct1 : ParentProduct { }
public sealed class ChildProduct2 : ParentProduct { }
enum
除了这些类型之外,每种类型都有一个。还必须考虑到这一点enum
,并且所有ParentProduct
继承人都没有直接关系
public enum ProductType
{
Parent = 1,
Child1 = 2,
Child2 = 3,
}
处理程序的结构大致如下:
public interface IProductHandler<T> where T : ParentProduct
{
public Task Add(T product);
}
public sealed class ParentHandler : IProductHandler<ParentProduct>
{
public async Task Add(ParentProduct product)
{
// ...
}
}
public sealed class Child1Handler : IProductHandler<ChildProduct1>
{
public async Task Add(ChildProduct1 product)
{
// ...
}
}
public sealed class Child2Handler : IProductHandler<ChildProduct2>
{
public async Task Add(ChildProduct2 product)
{
// ...
}
}
现在需要创建一个工厂ProductType
来生产相应的处理程序。但在这个特定阶段,我不明白如何正确地重新组织结构以使其能够像这样工作:
public sealed class ProductFactory
{
public IProductHandler<T> GetHandler<T>(ProductType type) where T : ParentProduct =>
type switch
{
ProductType.Parent => new ParentHandler()
};
}
还值得考虑的是,必须在不使用显式类型转换as
和比较typeof
等方式的情况下完成要求。换句话说,这种格式不适合:
public interface IProductHandler
{
public Task Add<T>(T product) where T : ParentProduct;
}
或者像这样
public interface IProductHandler
{
public Task Add(ParentProduct product);
}
因为实现时需要明确转换类型。
更新:
在评论中他们询问我将如何使用它。项目中有多个这样的地方,主要是控制器动作和ViewComponent
。控制器中使用的示例代码:
public sealed class ProductController(ProductFactory factory) : ControllerBase
{
[HttpGet("{type}/{id:int}")]
public async Task<IActionResult> DetDetails([FromRoute] ProductType type, [FromRoute] int id)
{
IProductHandler handler = factory.GetHandler(type)
return Ok(await handler.GetDetails(id));
}
}
嗯,这很简单,一个逆变接口。
就这样,工厂的错误就消失了。
但如果我是你,我就会删除该列表。
例如,如果我们认为所有产品都有一个唯一的 ID,那么传递类型就是多余的信息,因为通过 ID 您将收到产品的特定实例,该实例已经有其自己的特定类型,并且您可以通过它确定处理程序的类型。嗯,这取决于你的想象。尽管我强烈地感觉到这些处理程序的整个想法是值得怀疑的,但产品应该能够自行序列化
product.GetDetails()
。也就是说,我会收到某个IProduct
,而不是IProductHandler
,并会对其调用序列化方法。