Practical example: Applying the Template Method design pattern
3 min read
3 min read
As I already mentioned in my
previous post I'm currently doing domain objects to XSD generated object mapping. Monotonic, exactly, but I'm
approaching the end of the work.
Still, when doing such annoying work, I'm continuously striving to reduce the
amount of work by trying to find smarter, faster, more concise ways for doing this tedious work (in order to finish
earlier ;) ). Usually after a couple of hours common patterns/repetitions emerge as I learn the structure of the
underlying XSD. Refactorings then
usually help to proceed faster.
A template method defines the program skeleton of an algorithm. One or more of the algorithm steps are able to be overridden by subclasses to provide their own concrete implementation. This allows differing behaviors while ensuring that the overarching algorithm is still followed.In fact, the most interesting part when doing this kind of mapping work is to define an appropriate program skeleton for outlining the basic structure and here is where I used the Template Method pattern.
Source: Wikipedia
public class SomeDomainObjMapperI guess you already identified the common pattern. There are always one or more objects from the apps domain model (which we don't know in advance) and one XSD generated object to which data will be mapped and which will be returned. The mapping will be done by the Map(...) method which is specific to each Mapper.
{
private SomeDomainObj domainObj;
private SomeOtherDomainObj otherDomainObj;
private List<LogType> logs; //for collecting log entries about problems during mappings
public SomeDomainObjMapper(SomeDomainObj domainObj, SomeOtherDomainObj otherDomainObj)
{
this.domainObj = domainObj;
this.otherDomainObj = otherDomainObj;
}
public XSDGeneratedDomainObj Map(out List<LogType> mappingLogs)
{
XSDGeneratedDomainObj convertedType = new XSDGeneratedDomainObj();
convertedType.SomeProperty = domainObj.SomeOtherProperty;
...
//more complex mappings etc..
return convertedType;
}
...
}
public abstract class BaseMapper<TItem> where TItem: new()You see? This BaseMapper gives the basic structure, the skeleton. The specific mapping class will then look as follows:
{
protected List<LogType> logEntries;
public BaseMapper()
{
//initialization stuff
}
//will be called from "outside", the template method
public TItem Map(out List<LogType> logs)
{
TItem convertedType = new TItem();
//call to the specific mapping method
Map();
//assign the logs to be returned
logs = logEntries;
return convertedType;
}
protected abstract void Map();
...
}
public class SomeDomainObjMapper : BaseMapper<XSDGeneratedDomainObj>The Map() method will now just contain the mapping and nothing else. The logic of how it is called and what is done before/after mapping resides in the template.
{
private SomeDomainObj domainObj;
private SomeOtherDomainObj otherDomainObj;
private List<LogType> logs; //for collecting log entries about problems during mappings
public SomeDomainObjMapper(SomeDomainObj domainObj, SomeOtherDomainObj otherDomainObj)
{
this.domainObj = domainObj;
this.otherDomainObj = otherDomainObj;
}
protected void Map()
{
convertedType.SomeProperty = domainObj.SomeOtherProperty;
...
//more complex mappings etc..
}
...
}