Saturday, June 06, 2009

Dependency Injection and StructureMap (5)

In my preview articles, I have covered most commonly cases to describe dependency mappings. In this article, I'll conclude this series with chained registry strategy.

For many applications, there may be a lots of relationships between interfaces and implementations. You could define all those DMs in one Registry DSL library. However, I prefer to break them into several libraries and chain them together. The advantage of this strategy is to make the DM library easy to maintain and reusable.

The key in StructureMap Regisry DSL is to define a customized class based on Registry. Therefore, in each chained library, you should define your DMs in one or more Registry classes. The root library of the chain will call all the other libraries to get lists of Registry instances and add them to StructureMap framework.

For example, I have a console application, called as MyConsoleApp, which needs an implementation instance of IProcessControler. I'll create a SM library, SMForMyConsoleApp to define the DM, and it only defines the mapping relationship: how to create or map implementation class to IProcessController. The implementation class may need other implementations for other interfaces such as IDataReader, IDataProcessor and IDataWriter, but those mappings are from other chained libraries, where implementation mappings are defined.

The SMForForMyConsoleApp has two classes:

public static class SMForMyConsoleApp {
private static _registered = false;
public static void Initialize()
{
if (!_registered )
{
IEnumerable<Registry> listRegs = SMResgiry.GetRegs();
ObjectFactory.Initialize(x =>
{
// Get registry list from other Registry classes
// and add them to x
// ...

foreach (Registry reg in listRegs)
{
x.AddRegistry(reg);
}
}
}
}

public static T GetInstance<T>() where T: class
{
T instance = default(T);
if (typeof(T) == typeof(IProcessController>))
{
instance = ObjectFactory.GetInstance() as T;
}
return instance;
}
}


internal class SMRegistry: Registry {
// CTOR
public SMRegistry() {
// define the DMs
}

public static IEnumerable<Registry> GetRegs()
{
List<Registry> list = new List<Registry>();
// Add registry from other chained registry
// ...

list.Add(new SMRegistry()); // finally add this instance
return list;
}
}


The class SMForMyConsoleApp has two static methods. Initialize() is used to add all Registry instances to StructureMap framework. This method should be called in MyConsoleApp to initialize mappings. The second method GetInsance() is used to get mapped instance, for IProcessController in this example, and then start the process.

Other chained SMxxx libraries have similar structure. In this way, the console application's mapping library does not need to know the complete mapping relations. It will let sub/chain libraries to do the mapping. You can see, this is a very clean strategy with great flexibilities.

0 comments: