2015-05-30 3 views
1

Предположим, у меня есть интерфейс с несколькими реализациями базовыми:Украсьте каждый элемент разрешенное в коллекции с замок Виндзор

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(); 
    } 
} 

Наконец, у меня есть сервис который требует набора интерфейса:

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 иметь 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 

оказывается, что CollectionResolver I Виндзора s, поставляющий одну из всех реализаций IPrinter (что понятно) вместо того, чтобы признать, что ModifyingPrinter является декоратором и использует его для обертывания двух других реализаций.

Мой вопрос: Есть ли способ зарегистрировать эти классы, чтобы коллекция содержала только декорированные базовые реализации?

Я читал в другом месте где-то, что я могу создать перехватчик и зарегистрировать Printer1 и Printer2 с перехватчиком, но я хотел бы оставить шаблон декоратора, если смогу.

ответ

0

Как оказалось, 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)); 

Ответ должен был быть более явным в моей архитектуре.

0

Я вижу два пути для достижения ожидаемого результата:

  • Использовать decorator и перенесите метод Print в украшенном поведении. Это похоже на логическое поведение, так как вы можете не создавать IPrinter, который не имеет предполагаемого поведения, а скорее поведение декорирования.
  • используйте factory method, чтобы разрешить ваши IPrinters с помощью метода, который открывает принтер для отделки вокруг ожидаемого принтера. Я боюсь, что это может быть немного сложно выполнить, поскольку, если вы хотите использовать конфигурацию на основе соглашения, вам придется отфильтровать декоратор. Но он должен работать для ваших нужд.
Смежные вопросы