用温莎城堡装饰 collection 中解决的每个项目
Decorate each item resolved in a collection with Castle Windsor
假设我有一个包含多个基本实现的接口:
interface IPrinter
{
void Print();
}
class Printer1 : IPrinter
{
public void Print()
{
Console.WriteLine(GetType());
}
}
class Printer2 : IPrinter
{
public void Print()
{
Console.WriteLine(GetType());
}
}
我还有一个装饰器实现:
class ModifyingPrinter : IPrinter
{
private readonly IPrinter _printer;
public ModifyingPrinter(IPrinter printer)
{
_printer = printer;
}
public void Print()
{
Console.Write("Modified ");
_printer.Print();
}
}
最后,我有一个需要 collection 接口的服务:
class Service
{
private readonly IEnumerable<IPrinter> _printers;
public Service(IEnumerable<IPrinter> printers)
{
_printer = printer;
}
public void Print()
{
foreach (var printer in _printer)
{
printer.Print();
}
}
}
我想要的是 Service
在 collection 中有 Printer1
和 Printer2
,每个都用 ModifyingPrinter
装饰,这样输出Service.Print()
的是:
Modified Printer1
Modified Printer2
我尝试按如下方式注册 类:
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(
new CollectionResolver(container.Kernel, true));
container.Register(Component.For<IPrinter>()
.ImplementedBy<ModifyingPrinter>()
.LifestyleTransient());
container.Register(Component.For<IPrinter>()
.ImplementedBy<Printer1>());
container.Register(Component.For<IPrinter>()
.ImplementedBy<Printer2>());
container.Register(Component.For<Service>());
但这会导致以下输出:
Modified Printer1
Printer1
Printer2
似乎 Windsor 的 CollectionResolver
提供了 IPrinter
的所有实现中的每一个(这是可以理解的)而不是认识到 ModifyingPrinter
是一个装饰器并使用它来包装其他两个实现。
我的问题:有没有办法注册这些 类 以便 collection 只包含修饰的基础实现?
我在另一个 post 某处读到我可以创建一个拦截器并向拦截器注册 Printer1
和 Printer2
,但我想保留装饰器模式,如果我可以。
我看到有两种方法可以达到预期的效果:
- 使用 decorator 并在装饰行为中包装
Print
方法。这感觉像是一种合乎逻辑的行为,因为您可能不想创建一个 IPrinter
没有预期行为而是装饰行为的行为。
- 使用 factory method 通过在预期打印机周围新建装饰打印机的方法来解析您的 IPrinters。我担心这可能有点复杂,因为如果你想从基于约定的配置中受益,你将不得不过滤掉装饰器。但它应该可以满足您的需求
事实证明,Castle.Windsor 开箱即用无法满足我的要求。我尝试创建一个新的解析器来处理这种情况,但没有取得太大进展。
最后,我重组为使用真正的工厂来装饰类。
class PrinterModifierFactory : IPrinterModifierFactory
{
private Func<IPrinter, IPrinter> _decorate;
private IEnumerable<IPrinter> _printers;
public PrinterModifierFactory(Func<IPrinter, IPrinter> decorate,
IEnumerable<IPrinter> printers)
{
_decorate = decorate;
_printers = printers;
}
public IEnumerable<IPrinter> GetAll()
{
return _printers.Select(_decorate);
}
}
然后我修改了我的服务来简单地接收这个工厂的实例(当然是通过接口)而不是 IEnumerable<IPrinter>
。
class Service
{
private readonly IEnumerable<IPrinter> _printers;
private IPrinterModifierFactory factory;
public Service(IPrinterModifierFactory factory)
{
_factory = factory;
}
public void Print()
{
_Initialize();
foreach (var printer in _printers)
{
printer.Print();
}
}
void _Initialize()
{
if (_printers != null) return;
_printers = factory.GetAll().ToList();
}
}
(为简洁起见,我省略了 null
检查等细节。)
终于,在安装程序中,我可以注册工厂和装饰方法了。
container.Register(Component.For<IPrinterModifierFactory>()
.ImplementedBy<PrinterModifierFactory>());
Func<IPrinter, IPrinter> decorator = p => new ModifyingPrinter(p);
container.Register(Component.For<Func<IPrinter, IPrinter>>()
.Instance(decorator));
答案是在我的架构中更明确一点。
假设我有一个包含多个基本实现的接口:
interface IPrinter
{
void Print();
}
class Printer1 : IPrinter
{
public void Print()
{
Console.WriteLine(GetType());
}
}
class Printer2 : IPrinter
{
public void Print()
{
Console.WriteLine(GetType());
}
}
我还有一个装饰器实现:
class ModifyingPrinter : IPrinter
{
private readonly IPrinter _printer;
public ModifyingPrinter(IPrinter printer)
{
_printer = printer;
}
public void Print()
{
Console.Write("Modified ");
_printer.Print();
}
}
最后,我有一个需要 collection 接口的服务:
class Service
{
private readonly IEnumerable<IPrinter> _printers;
public Service(IEnumerable<IPrinter> printers)
{
_printer = printer;
}
public void Print()
{
foreach (var printer in _printer)
{
printer.Print();
}
}
}
我想要的是 Service
在 collection 中有 Printer1
和 Printer2
,每个都用 ModifyingPrinter
装饰,这样输出Service.Print()
的是:
Modified Printer1
Modified Printer2
我尝试按如下方式注册 类:
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(
new CollectionResolver(container.Kernel, true));
container.Register(Component.For<IPrinter>()
.ImplementedBy<ModifyingPrinter>()
.LifestyleTransient());
container.Register(Component.For<IPrinter>()
.ImplementedBy<Printer1>());
container.Register(Component.For<IPrinter>()
.ImplementedBy<Printer2>());
container.Register(Component.For<Service>());
但这会导致以下输出:
Modified Printer1
Printer1
Printer2
似乎 Windsor 的 CollectionResolver
提供了 IPrinter
的所有实现中的每一个(这是可以理解的)而不是认识到 ModifyingPrinter
是一个装饰器并使用它来包装其他两个实现。
我的问题:有没有办法注册这些 类 以便 collection 只包含修饰的基础实现?
我在另一个 post 某处读到我可以创建一个拦截器并向拦截器注册 Printer1
和 Printer2
,但我想保留装饰器模式,如果我可以。
我看到有两种方法可以达到预期的效果:
- 使用 decorator 并在装饰行为中包装
Print
方法。这感觉像是一种合乎逻辑的行为,因为您可能不想创建一个IPrinter
没有预期行为而是装饰行为的行为。 - 使用 factory method 通过在预期打印机周围新建装饰打印机的方法来解析您的 IPrinters。我担心这可能有点复杂,因为如果你想从基于约定的配置中受益,你将不得不过滤掉装饰器。但它应该可以满足您的需求
事实证明,Castle.Windsor 开箱即用无法满足我的要求。我尝试创建一个新的解析器来处理这种情况,但没有取得太大进展。
最后,我重组为使用真正的工厂来装饰类。
class PrinterModifierFactory : IPrinterModifierFactory
{
private Func<IPrinter, IPrinter> _decorate;
private IEnumerable<IPrinter> _printers;
public PrinterModifierFactory(Func<IPrinter, IPrinter> decorate,
IEnumerable<IPrinter> printers)
{
_decorate = decorate;
_printers = printers;
}
public IEnumerable<IPrinter> GetAll()
{
return _printers.Select(_decorate);
}
}
然后我修改了我的服务来简单地接收这个工厂的实例(当然是通过接口)而不是 IEnumerable<IPrinter>
。
class Service
{
private readonly IEnumerable<IPrinter> _printers;
private IPrinterModifierFactory factory;
public Service(IPrinterModifierFactory factory)
{
_factory = factory;
}
public void Print()
{
_Initialize();
foreach (var printer in _printers)
{
printer.Print();
}
}
void _Initialize()
{
if (_printers != null) return;
_printers = factory.GetAll().ToList();
}
}
(为简洁起见,我省略了 null
检查等细节。)
终于,在安装程序中,我可以注册工厂和装饰方法了。
container.Register(Component.For<IPrinterModifierFactory>()
.ImplementedBy<PrinterModifierFactory>());
Func<IPrinter, IPrinter> decorator = p => new ModifyingPrinter(p);
container.Register(Component.For<Func<IPrinter, IPrinter>>()
.Instance(decorator));
答案是在我的架构中更明确一点。