C#, Castle Windsor and The Composite design pattern
Asked Answered
D

2

6

I have designed a telemetry logger for few separate platforms using the composite pattern

public interface ILogger
{
    void Log();
}

public class A : ILogger
{
    public void Log(...);
}

public class B : ILogger
{
    public void Log(...);
}

public class Many : ILogger
{
    private readonly List<ILogger> m_loggers;

    public Many(IEnumerable<ILogger> loggers)
    {
        m_loggers = loggers.ToList();
    }

    public void Log()
    {
        m_loggers.ForEach(c => c.Log());
    }
}

Now i want to be able to get an instance of "Many" from Windsor container but have encountered a few problems:

  • if all ILoggers are in the container how can i make sure i get the "Many" implementation and not "A" or "B" ?

  • I tried following this example Castle Windsor: How do I inject all implementations of interface into a ctor? and use container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel)); to register a class with IEnumerable dependancy but if that class also implements IComponent wont it create a circular dependency ?

Is what I'm attempting even possible ?

Doubles answered 13/10, 2015 at 4:59 Comment(0)
P
5

First of all this is Composite Design Pattern not Component.

The way you do it in Castle Windsor in your case should look like this

container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
container.Register(Component.For<ILogger>().ImplementedBy<Many>());
container.Register(Component.For<ILogger>().ImplementedBy<A>());
container.Register(Component.For<ILogger>().ImplementedBy<B>());

This works because Castle Windsor have internal understanding of patterns like Composite or Decorator so no circular dependency will be created in this case. Just bare in mind that order of registration is important in this case.

More on registering different patterns in Castle Windsor can be found here.

Pericardium answered 13/10, 2015 at 8:34 Comment(0)
B
0

Is it possible with a factory method in the container registration?

 var container = new Castle.Windsor.WindsorContainer();
    container.Register(Component.For<A>());
    container.Register(Component.For<B>());
    container.Register(Component.For<ILogger>()
        .UsingFactoryMethod(k => new Many(k.Resolve<A>(), k.Resolve<B>())));

    var logger = container.Resolve<ILogger>();

After changing:

 public Many(params ILogger [] loggers)
    {
        m_loggers = loggers.ToList();
    }

Limited knowledge of the Windsor Container lead me to this, there is probably an improvement to this along the same lines of using a factory to initialize your object. The important thing is the configuration is within the container (Even if it is a little verbose)

Bolter answered 13/10, 2015 at 8:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.