Recently I have been working with some hierarchical object structures that are a composition of several other nested classes and elements, that we call “template objects”. To give you an idea of this, consider “Patient” class as a container that holds patient demographics in a hierarchical object structure.
These template objects are very robust and flexible, someone can go and design a template like above in a hierarchical structure with unlimited nesting and we have a tool that goes and generates these template objects automatically for us. e.g.
I have been developing some web based CRUD interface pages with these template objects / container classes. However I faced some problem with the hierarchical nature of the template objects. Speaking of the above template as an example, two major problems that slowed down the development are
1. If I wanted to populate current address of the Patient class I had to instantiate several nested classes of the template object and then finally was able to assign the value to the desired address property. e.g.
2. If I wanted to display the “current address” of the Patient to the page, I had to go through all sorts of null checking on several layers of the hierarchical object structure.
As you can realize, that any kind of get and set operation to a nested object turns into a big task for the developers and the more deeper nested the object is in the hierarchy the more codes has to be written to deal with it.
Before I suggest a solution to this problem , lets look at different ways to maintain/represent hierarchical objects in C#.NET.
This is the most common approach that we take, we create different dependent classes in separate physical file under same namespace.
Fig: classes in separate physical files.
However when we auto generate classes from templates there is high chances of class name conflicts. To overcome that scenario we can take one of the following approaches: Namespace separated class or Nested class.
Namespace separated class
In this approach every class can be maintained in separate physical files or all related classes can be dumped in one single physical file. However the key difference of this pattern to the above is every single class gets its own different namespace that also resembles the hierarchy. I made up the Namespace conventions to be the parent class name suffixed by the string “Ns”.
Fig: namespace separated classes.
When classes are stored in separate physical files, there is potential of physical filename conflict of the generated classes. This is easy to solve though, the related classes are sometimes grouped and stored in separate folders.
The other approach is to create nested classes like we have seen above in “Fig : nested template objects”. Normally when one class is entirely dependent upon another, we decide to implement it using a nested class. Nested classes are declared within the scope of an existing class and receive special benefits when accessing private and protected members of their parent class.
Inversion of control (IoC) slash Dependency Injection
Speaking about the problem that we identified earlier, here are some thoughts to solve the issues. I have some experiences with Inversion of control (IoC) slash Dependency Injection on test driven developments and I am aware the IoC frameworks provides simplified object creation, especially for hierarchical object structures and dependencies. I looked into this further to come up with a solution. For those who are new to DI and IoC, I would recommend you to read Martin Fowlers article : “Inversion of Control Containers and Dependency Injection pattern”.
In fact any of the following conditions justifies using the DI pattern.
- You want to decouple your classes from their dependencies so that these dependencies can be replaced or updated with minimal or no changes to your classes’ source code.
- You want to be able to write classes that depend on classes whose concrete implementation is not known at compile time.
- You want to be able to test your classes in isolation, without using the dependencies.
- You want to decouple your classes from being responsible for locating and managing the lifetime of dependencies.
So by using the DI, we can inverse the dependencies on the template object classes and make them less coupled. e.g. by getting the PatienDemographics injected as a constructor parameter on the Patient class we can inverse the dependency and now Patient class depends on someone else to pass in the dependency. We can decouple and make this more flexible by declaring an interface for PatientDemographics and then pass the IPatientDemographics instead, something like this.
Fig: refactored Patient class.
We continue to inverse the dependencies for all other template objects in the hierarchy e.g.
Fig : refactored classes.
The next thing to do, is to register all our dependencies in IoC container by passing the container an interface that the dependency implements, and the concrete class that will be instantiated for request of that interface. In other words during the registration we tell the IoC container what and how it should build or find or serve requested services. I will register my dependencies using StructuredMap here.
Fig : structuremap registry.
By default, as long as an object is being created by invoking its constructor function, StructureMap will try to create/resolve/find an object for non-primitive dependency in the requested concrete type. This is known as autowiring, IoC will take care of instantiating all necessary dependent objects automatically. If StructureMap doesn’t know how to find a requested dependency it throws exception. This solves our problem, here is how:
1. If I wanted to populate current address of the Patient class I do not need to worry about instantiatiating several nested classes of the template object, because that will be magically handled by the IoC and I will be able to assign the value to the desired address property with one line of code like the following.
2. If I wanted to display the “current address” of the Patient to the page, I do not need to go through all sorts of null checking on several layers of the hierarchical object structure, because IoC will automatically instantiate all dependent objects. I can go to the desired property directly and display the value when available.
You can see now clearly, how inversing dependencies and use of IoC container improves developers productivity significantly.
Before I finish I must also introduce the Common Service Locator library that contains a shared interface for service location which application and framework developers can reference. The library provides an abstraction over Ioc containters and service locators, which helps developers to use IoC without tying them down to a specific implementation. Currently service locator adapter implementations are available for StructureMap, Unity, Castle Windsor, Sprint.NET, Autofact, MEF and Linfu. The full list can be found here.
I hope this discussion will solve some programming nightmare with hierarchical object structure. Thank you for being with me so far and happy coding.