Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use "Composite Design Pattern" with Ninject

Validation Rule Contract:

public interface IValidationRule
{
    bool IsValid();
}

Concrete Validation Rule:

public class MyClass : IValidationRule
{
    public bool IsValid()
    {
        return true;
    }
}

Composite:

public class ValidationRuleComposite : IValidationRule
{
    private readonly IEnumerable<IValidationRule> _validationRules;

    public ValidationRuleComposite(IEnumerable<IValidationRule> validationRules)
    {
        _validationRules = validationRules;
    }

    public bool IsValid()
    {
        return _validationRules.All(x => x.IsValid());
    }
}

When I ask the containter for IValidationRule I want to get ValidationRuleComposite. If I ask the container for a list of IValidationRule I want to get all implementations of IValidationRule except of the ValidationRuleComposite.

How can I achieve this with Ninject?

like image 877
Rookian Avatar asked Dec 11 '25 13:12

Rookian


1 Answers

First you want to set up the bindings for the IEnumerable<IValidationRule> that will be injected into the composite. You can just bind them individually:

// Bind all the individual rules for injection into the composite
kernel.Bind<IValidationRule>().To<MyClass>().WhenInjectedInto<ValidationRuleComposite>();
kernel.Bind<IValidationRule>().To<RuleTwo>().WhenInjectedInto<ValidationRuleComposite>();

Or you can also setup the IEnumerable fairly easy with the convention binding extensions, so that you don't have to add a separate binding for each individual concrete rule. Just be sure to add the Exlcuding clause for the composite class like so:

using Ninject.Extensions.Conventions;

// Bind all the non-composite IValidationRules for injection into ValidationRuleComposite
kernel.Bind(x => x.FromAssemblyContaining(typeof(ValidationRuleComposite))
    .SelectAllClasses()
    .InheritedFrom<IValidationRule>()
    .Excluding<ValidationRuleComposite>()
    .BindAllInterfaces()
    .Configure(c => c.WhenInjectedInto<ValidationRuleComposite>()));

In my example the composite and the rest of the concretes are in the same assembly, but obviously you can vary your convention binding if they're somewhere else.

Finally, we need to set up the binding so that everywhere else an IValidationRule is request, Ninject provides the composite. There doesn't seem to be an elegant method existing for this, so I wrote my own When clause to avoid the cyclical injection:

// Now bind the composite to the interface for everywhere except itself
kernel.Bind<IValidationRule>().To<ValidationRuleComposite>()
    .When(x => x.Target == null
          || x.Target.Member.ReflectedType != typeof(ValidationRuleComposite));
like image 184
Soldarnal Avatar answered Dec 14 '25 04:12

Soldarnal