Pattern Binder – BinderDirector – C#

C Sharp icon

Very usefull in ressource aggregation, here you will find a code snippet that can be integrated in Inversion Of Control pattern using Interface Segregation Principle of SOLID designing principles.

public interface IBinder
    {

    }

    public interface IBinder<in T> : IBinder
    {
        void Bind(IEnumerable<T> bounds);
    }

    public interface IBinderDirector<T> 
    {
        IBinder<T>[] DataBinders { get; }

        void Bind(IEnumerable<T> bounds);
        void BindParallel(IEnumerable<T> bounds);
        void BindOnlySelected(IEnumerable<T> bounds, IEnumerable<Type> selecteds);
        void BindAllExcept(IEnumerable<T> bounds,IEnumerable<Type> excepts);
        void BindOnlySelectedParallel(IEnumerable<T> bounds,IEnumerable<Type> selecteds);
        void BindAllExceptParallel(IEnumerable<T> bounds,IEnumerable<Type> excepts);
    }


    public class BinderDirector<T> : IBinderDirector<T>
    {
        private readonly IBinder<T>[] _dataBinders;
        public IBinder<T>[] DataBinders => throw new NotImplementedException();

        public BinderDirector(IEnumerable<IBinder<T>> dataBinders)
        {
            _dataBinders = (dataBinders ?? Enumerable.Empty<IBinder<T>>()).ToArray();
        }

        public void Bind(IEnumerable<T> bounds)
        {
            var boundAsList = bounds.ToArray();
            foreach(var dataBinder in _dataBinders) dataBinder.Bind(boundAsList);
        }

        public void BindAllExcept(IEnumerable<T> bounds, IEnumerable<Type> excepts)
        {
            var boundArray = bounds.ToArray();
            var runnableDataBinders = _dataBinders.Where(m => excepts.Any(s => !s.IsAssignableFrom(m.GetType())));
            foreach (var dataBinder in runnableDataBinders) dataBinder.Bind(bounds);
        }

        public void BindAllExceptParallel(IEnumerable<T> bounds, IEnumerable<Type> excepts)
        {
            var boundArray = bounds.ToArray();
            var runnableDataBinders = _dataBinders.Where(m => excepts.Any(s => !s.IsAssignableFrom(m.GetType())));
            Parallel.ForEach(runnableDataBinders, (runnableDataBinder, index) => runnableDataBinder.Bind(bounds));
        }

        public void BindOnlySelected(IEnumerable<T> bounds, IEnumerable<Type> selecteds)
        {
            var boundArray = bounds.ToArray();
            var runnableDataBinders = _dataBinders.Where(m => selecteds.Any(s => s.IsAssignableFrom(m.GetType())));
            foreach (var dataBinder in runnableDataBinders) dataBinder.Bind(bounds);
        }

        public void BindOnlySelectedParallel(IEnumerable<T> bounds, IEnumerable<Type> selecteds)
        {
            var boundArray = bounds.ToArray();
            var runnableDataBinders = _dataBinders.Where(m => selecteds.Any(s => s.IsAssignableFrom(m.GetType())));
            Parallel.ForEach(runnableDataBinders, (runnableDataBinder, index) => runnableDataBinder.Bind(bounds));
        }

        public void BindParallel(IEnumerable<T> bounds)
        {
            var boundArray = bounds.ToArray();
            Parallel.ForEach(_dataBinders, dataBinder => dataBinder.Bind(boundArray));
        }
    }

Underneath you will find an example of concrete implementation. The thing which is interesant, is that the BinderDirector is a pure interpretation of the Interface Segregation Principle :

public interface IWithBindPropertiesA
    {
        string IdentifierA { get; }
        string ReturnedPropertyValueA { set; }
    }

    public interface IWithBindPropertiesB
    {
        string IdentifierB { get; }
        string ReturnedPropertyValueB { set; }
    }

    public class ConcreteImplementation : IWithBindPropertiesA, IWithBindPropertiesB
    {
        public new string IdentifierA { get; set; }

        public new string ReturnedPropertyValueA { get; set; }

        public new string IdentifierB { get; set; }

        public new string ReturnedPropertyValueB { get; set; }
    }


    public class BindPropertiesABinder : IBinder<IWithBindPropertiesA>
    {
        public void Bind(IEnumerable<IWithBindPropertiesA> bounds)
        {
            foreach(var bound in bounds)
            {
                bound.ReturnedPropertyValueA = bound.IdentifierA == "A"?"A":"unknown"; //In fact you can do what you want
            }
        }
    }
    public class BindPropertiesBBinder : IBinder<IWithBindPropertiesB>
    {
        public void Bind(IEnumerable<IWithBindPropertiesB> bounds)
        {
            foreach (var bound in bounds)
            {
                bound.ReturnedPropertyValueB = bound.IdentifierB == "B" ? "B" : "unknown"; //In fact you can do what you want
            }
        }
    }

    public static class Program
    {
        public static void Main(string[] argc)
        {
            var binderDirector = new BinderDirector<ConcreteImplementation>(new IBinder<ConcreteImplementation>[] {
                new BindPropertiesABinder(),
                new BindPropertiesBBinder()
            });
        }
    }