| Matthew's profileMatthew WrenPhotosBlogLists | Help |
|
February 01 Chain of Responsibility Hybrid : Sequential MappersRecently I was faced with the simple task of persisting a domain object into a file in as XML, so that later I could re-hydrate the domain object from my file. So, here was my intention:
Points one to three are quite straight forwards, but it was when I came to point four that I had a think about the way in which this should be executed. Breaking down the sequence of processes:
Expressed another way:
Insignificant as it may seem, there is undeniably a pattern here:
Yes, crazy as it seems I am actually going to write three mappers instead of the original one. Why?
Traditionally we might want to use the chain of responsibility pattern to execute the workflow sequence here, but I decided instead to build a hybrid of this design pattern, so that I could declare my sequence of mappers using fluent interfaces, and also I wanted to yield a mapper that spanned the entire chain of mappers. So my aim is to be able to write something like: IMapper<A,D> mapper =
new MapFrom<A>()
.To<B>(abMapper)
.To<C>(bcMapper)
.To<D>(cdMapper);
So, my first implementation is as follows: public interface IMapper<SOURCE, TARGET> { TARGET Map(SOURCE source); } public interface IMapperChain<ROOTSOURCE, TARGET> : IMapper<ROOTSOURCE, TARGET> { IMapperChain<ROOTSOURCE, NEWTARGET> To<NEWTARGET>(IMapper<TARGET, NEWTARGET> mapper); } public interface IMappingHandler<SOURCE> { void Handle(SOURCE source); } public class MapFrom<SOURCE> { private IMappingHandler<SOURCE> _handler; public IMapperChain<SOURCE, TARGET> To<TARGET>(IMapper<SOURCE, TARGET> mapper) { _handler = new MapTo<SOURCE, SOURCE, TARGET>(mapper, this); return _handler as IMapperChain<SOURCE, TARGET>; } public void Handle(SOURCE source) { _handler.Handle(source); } } public class MapTo<ROOTSOURCE, SOURCE, TARGET> : IMappingHandler<SOURCE>, IMapperChain<ROOTSOURCE, TARGET> { private bool _terminateChain; private MapFrom<ROOTSOURCE> rootChain; private IMapper<SOURCE, TARGET> _mapper; private IMappingHandler<TARGET> _handler; private TARGET _value; public MapTo( IMapper<SOURCE, TARGET> mapper, MapFrom<ROOTSOURCE> rootChain) { _mapper = mapper; this.rootChain = rootChain; } public IMapperChain<ROOTSOURCE, NEWTARGET> To<NEWTARGET>(IMapper<TARGET, NEWTARGET> mapper) { _handler = new MapTo<ROOTSOURCE, TARGET, NEWTARGET>(mapper, rootChain); return _handler as IMapperChain<ROOTSOURCE, NEWTARGET>; } public TARGET Map(ROOTSOURCE source) { _terminateChain = true; rootChain.Handle(source); _terminateChain = false; return _value; } public void Handle(SOURCE source) { _value = _mapper.Map(source); if (!_terminateChain && _handler != null) { _handler.Handle(_value); } } } TrackbacksThe trackback URL for this entry is: http://mdwren.spaces.live.com/blog/cns!9C2D8683D2D11400!281.trak Weblogs that reference this entry
|
|
|