所以我正在尝试实现拦截的概念,同时使用autofac。我没有做任何花哨的事情,比如实现动态拦截,每个类我都有具体的代码。
我的代码(不是我的真实代码,我在网上找到了它,但它证明了我的问题
public class DefaultProductService : IProductService
{
public Product GetProduct(int productId)
{
return new Product();
}
}
public class CachedProductService : IProductService
{
private readonly IProductService _innerProductService;
private readonly ICacheStorage _cacheStorage;
public CachedProductService(IProductService innerProductService, ICacheStorage cacheStorage)
{
if (innerProductService == null) throw new ArgumentNullException("ProductService");
if (cacheStorage == null) throw new ArgumentNullException("CacheStorage");
_cacheStorage = cacheStorage;
_innerProductService = innerProductService;
}
public Product GetProduct(int productId)
{
string key = "Product|" + productId;
Product p = _cacheStorage.Retrieve<Product>(key);
if (p == null)
{
p = _innerProductService.GetProduct(productId);
_cacheStorage.Store(key, p);
}
return p;
}
}
public class ProductManager : IProductManager
{
private readonly IProductService _productService;
public ProductManager(IProductService productService)
{
_productService = productService;
}
}
我的问题是,我希望我的ProductManager接收IProductService的“CachedProductService”,我希望我的CachedProductService接收IProductService的“DefaultProductService”。
我知道一些解决方案,但它们似乎都不正确。这样做的正确方法是什么?
谢谢! 迈克尔
答案 0 :(得分:1)
您可以使用named dependencies执行此操作
而不是说IProductService
的实现是DefaultProductService
,你将有两个以其名称区分的实现,如下所示:
builder.Register<DefaultProductService>().Named<IProductService>("DefaultProductService");
builder.Register<CachedProductService>().Named<IProductService>("CachedProductService");
文档中描述了一些不同的方法,用于指示要注入给定类的实现。这看起来最简单,最明确:
public class ProductManager : IProductManager
{
private readonly IProductService _productService;
public ProductManager([WithKey("CachedProductService")]IProductService productService)
{
_productService = productService;
}
}
老实说,我不喜欢它,因为它导致类依赖于容器。它不允许您将它与类本身完全分开。使用Windsor,您可以在向容器注册依赖项时告知它使用哪个命名依赖项。
但这应该有用。
答案 1 :(得分:1)
您要做的似乎不是拦截概念,而是装饰者概念。
在面向对象的编程中,装饰器模式是一种设计模式,它允许将行为静态或动态地添加到单个对象,而不会影响同一类中其他对象的行为。
来自Decorator pattern (Wikipedia)
Autofac 使用命名注册内置了对装饰器的支持。
首先,您必须将基本组件和装饰器声明为命名注册:
builder.RegisterType<DefaultProductService>().Named<IProductService>("base");
builder.RegisterType<CacheProductServiceAdapter>().Named<IProductService>("cache");
然后你可以注册你的装饰
builder.RegisterDecorator((c, inner) => c.ResolveNamed<IProductService>("cache", TypedParameter.From(inner)), fromKey : "base")
.As<IProductService>();
您还可以使用多个适配器:
builder.RegisterType<DefaultProductService>().Named<IProductService>("base");
builder.RegisterType<CacheProductServiceAdapter>().Named<IProductService>("cache");
builder.RegisterType<LoggingProductServiceAdapter>().Named<IProductService>("logging");
builder.RegisterDecorator((c, inner) => c.ResolveNamed<IProductService>("cache", TypedParameter.From(inner)), fromKey : "base", toKey:"cached");
builder.RegisterDecorator((c, inner) => c.ResolveNamed<IProductService>("logging", TypedParameter.From(inner)), fromKey : "cached")
.As<IProductService>();
有关详细信息,请参阅adapters and decorators from Autofac documentation。
答案 2 :(得分:0)
基于Scott的建议,我想我找到了一种方法,而不必在我的ProductManager类中引入对容器的依赖(我真的很讨厌必须这样做!)。我可以简单地实例化CachedProductService并告诉它使用哪个ProductService
string cmdText = @"INSERT INTO [Sales]
([Printers], [Ink], [Paper])
VALUES (@Printers,@Ink,@Paper);
SELECT @EmpID FROM (Emplopyee)";