Marko Apfel - Afghanistan/Belgium/Germany

Management, Architecture, Programming, QA, Coach, GIS, EAI

  Home  |   Contact  |   Syndication    |   Login
  187 Posts | 2 Stories | 201 Comments | 4 Trackbacks

News



Twitter | LinkedIn | Xing

Archives

Post Categories

Image Galleries

BizTalk

C#

Enterprise Library

SAP

SQL Server

Technologie

If different implementations for the same interface are specified without named keys, then a resolving is made in order of the configurations. So the first fitting implementation is taken.

Different implementations for the same interface is a typical scenario for patterns like “chain of responsibility” and “decorator”. If you want to describe such a chain you could use the next handler as a constructor- parameter in the actual one.

Demo source code

Lets have a look at code.

Interface for one handler/processor/part from the “chain of responsibility” (cor):

public interface ICorHandler<T>
{
	void Process(T data);
	CorHandler<T> NextLink { get; set; }
}

and a “default” implementation for this interface:

public abstract class CorHandler<T> : ICorHandler<T>
{
	protected CorHandler(CorHandler<T> nextLink)
	{
		NextLink = nextLink;
	}

	public void Process(T data)
	{
		if (IsResponsible(data))
		{
			ProcessCore(data);
		}
		else
		{
			CallNextHandler(data);
		}
	}

	private void CallNextHandler(T data)
	{
		if (null != NextLink)
		{
			NextLink.Process(data);
		}
		else
		{
			ProcessEndOfChain(data);
		}
	}

	protected virtual void ProcessEndOfChain(T data)
	{
		string message = string.Format("End from chain of responsibility reached. {0}Type info='{1}'", 
			                            Environment.NewLine, MethodBase.GetCurrentMethod().DeclaringType);
		Trace.WriteLine(message);
	}

	public CorHandler<T> NextLink { get; set; }

	protected abstract bool IsResponsible(T data);
	protected abstract void ProcessCore(T data);
}

an two sample implementations which only checks the type of a given data as the filter-criteria:

public class CorHandlerOne : CorHandler<IData>
{
	public CorHandlerOne(CorHandler<IData> nextLink)
		: base(nextLink)
	{
	}
 
	public CorHandlerOne() : base(null)
	{
	}
 
	protected override bool IsResponsible(IData data)
	{
		return typeof (DemoDataOne) == data.GetType();
	}
 
	protected override void ProcessCore(IData data)
	{
		Console.WriteLine("This is for 'CorHandlerOne'");
	}
}
 
public class CorHandlerTwo : CorHandler<IData>
{
	public CorHandlerTwo() : base(null)
	{
	}
 
	public CorHandlerTwo(CorHandler<IData> nextLink)
		: base(nextLink)
	{
	}
 
	protected override bool IsResponsible(IData data)
	{
		return typeof (DemoDataTwo) == data.GetType();
	}
 
	protected override void ProcessCore(IData data)
	{
		Console.WriteLine("This is for 'CorHandlerTwo'");
	}
}

Configuration order and resolving effects

Now we use the castle windsor fluent configuration.

And the resolving effect is proved with the following code:

IData data = new DemoDataOne();
corHandler.Process(data);
 
Console.WriteLine("***");
 
data = new DemoDataTwo();
corHandler.Process(data);

Ascending order without resolving key

container.Register(Component.For<ICorHandler<IData>>().ImplementedBy<CorHandlerOne>().Named("one").Parameters(Parameter.ForKey("nextLink").Eq("${two}")));
container.Register(Component.For<ICorHandler<IData>>().ImplementedBy<CorHandlerTwo>().Named("two"));
 
var corHandler = container.Resolve<ICorHandler<IData>>();

We get the result:

This is for 'CorHandlerOne'
***
This is for 'CorHandlerTwo'

So the resolving is along the configuration order – CorHandlerTwo is the succsessor of CorHandlerOne.

Descending order without resolving key

container.Register(Component.For<ICorHandler<IData>>().ImplementedBy<CorHandlerTwo>().Named("two"));
container.Register(Component.For<ICorHandler<IData>>().ImplementedBy<CorHandlerOne>().Named("one").Parameters(Parameter.ForKey("nextLink").Eq("${two}")));

var corHandler = container.Resolve<ICorHandler<IData>>();

We get the result:

End from chain of responsibility reached. 
Type info='EsriDE.Trials.ChainOfResponsibility.CorHandler`1[T]'
***
This is for 'CorHandlerTwo'

So the resolving is along the configuration order – CorHandlerTwo is the succsessor of CorHandlerOne, but the “entry-point” for castle windsor is CorHandlerTwo because it is specified before CorHandlerOne. And so this implementation starts the filtering in the chain. However - CorHandlerTwo has no succsessor and so the message “End from chain of responsibility reached” is outputted.

Descending order with resolving keys

Now we introduce a key for the resolving. So we have deformed the “entry-point”.

var corHandler = container.Resolve<ICorHandler<IData>>(“one”);

We get the result like in the first sample:

This is for 'CorHandlerOne'
***
This is for 'CorHandlerTwo'

posted on Tuesday, May 3, 2011 5:46 AM