| Matthew's profileMatthew WrenPhotosBlogLists | Help |
|
February 08 Chain of Responsibility Hybrid II : ImprovementsFollowing on from my last post I have identified a flaw in the previous design. IMapperChain<A,C> baseMapper = new MapFrom<A>().To<B>(abMapper).To<C>(bcMapper);IMapper<A,X> axMapper = baseMapper.To<X>(cxMapper); IMapper<A,Y> ayMapper = baseMapper.To<Y>(cyMapper); X myX = axMapper.Map(new A());
This does not work. The reason is because each mapper passed to baseMapper.To overwrites the previously attached mapper. To overcome this in my latest version, each time I add a mapper, I clone the entire MapFrom object graph and attach the new MapTo to this clone. Since the last post, I have also made the following additions:
So, here is the next evolution of the mapping code: public interface IMapper<SOURCE, TARGET> { TARGET Map(SOURCE source); } public interface IProcessor<SOURCE> { void Process(SOURCE source); } public interface IMapperContext { IDictionary<string, string> State { get; } } public interface IMapperChain<ROOTSOURCE, TARGET> : IMapper<ROOTSOURCE, TARGET> { IMapperChain<ROOTSOURCE, NEWTARGET> To<NEWTARGET>(IMapper<TARGET, NEWTARGET> mapper); IProcessor<ROOTSOURCE> To(IProcessor<TARGET> process); } public interface IWorkflowChainable { void AddHandler<HANDLETYPE>(IWorkflowHandler<HANDLETYPE> handler); } public interface IWorkflowHandler<SOURCE> : ICloneable { void Handle(SOURCE source, IMapperContext context); } public abstract class ContextualMapper<SOURCE, TARGET> : IMapper<SOURCE, TARGET> { protected IMapperContext Context; public TARGET Map(SOURCE source, IMapperContext context) { Context = context; return Map(source); } public abstract TARGET Map(SOURCE source); } public abstract class ContextualProcessor<SOURCE> : IProcessor<SOURCE> { protected IMapperContext Context; public void Process(SOURCE source, IMapperContext context) { Context = context; Process(source); } public abstract void Process(SOURCE source); } public class MapperContext : IMapperContext { private readonly IDictionary<string, string> _state = new Dictionary<string, string>(); public IDictionary<string, string> State { get { return _state; } } } public class MapFrom<SOURCE> : ICloneable { private IWorkflowHandler<SOURCE> _handler; public MapFrom() { } private MapFrom(IWorkflowHandler<SOURCE> handler) { _handler = handler; } public IMapperChain<SOURCE, TARGET> To<TARGET>(IMapper<SOURCE, TARGET> mapper) { return new MapTo<SOURCE, SOURCE, TARGET>(mapper, this.Clone() as MapFrom<SOURCE>); } public IProcessor<SOURCE> To(IProcessor<SOURCE> process) { return new Processor<SOURCE, SOURCE>(process, this.Clone() as MapFrom<SOURCE>); } public void Handle(SOURCE source) { IMapperContext context = new MapperContext(); _handler.Handle(source, context); } internal void AddHandler<HANDLETYPE>(IWorkflowHandler<HANDLETYPE> handler) { if (_handler == null) { _handler = handler as IWorkflowHandler<SOURCE>; } else { IWorkflowChainable chain = _handler as IWorkflowChainable; if (chain != null) { chain.AddHandler<HANDLETYPE>(handler); } } } public object Clone() { if (_handler != null) { return new MapFrom<SOURCE>(_handler.Clone() as IWorkflowHandler<SOURCE>); } else { return new MapFrom<SOURCE>(); } } } public class MapTo<ROOTSOURCE, SOURCE, TARGET> : IWorkflowHandler<SOURCE>, IMapperChain<ROOTSOURCE, TARGET>, IWorkflowChainable { private MapFrom<ROOTSOURCE> _rootChain; private IMapper<SOURCE, TARGET> _mapper; private IWorkflowHandler<TARGET> _handler; private bool _terminateChain; private TARGET _value; private MapTo( IWorkflowHandler<TARGET> handler, IMapper<SOURCE, TARGET> mapper, MapFrom<ROOTSOURCE> rootChain) : this(mapper, rootChain) { _handler = handler; } public MapTo( IMapper<SOURCE, TARGET> mapper, MapFrom<ROOTSOURCE> rootChain) { _mapper = mapper; _rootChain = rootChain; _rootChain.AddHandler<SOURCE>(this); } public IMapperChain<ROOTSOURCE, NEWTARGET> To<NEWTARGET>(IMapper<TARGET, NEWTARGET> mapper) { return new MapTo<ROOTSOURCE, TARGET, NEWTARGET>(mapper, _rootChain.Clone() as MapFrom<ROOTSOURCE>); } public IProcessor<ROOTSOURCE> To(IProcessor<TARGET> process) { return new Processor<ROOTSOURCE, TARGET>(process, _rootChain.Clone() as MapFrom<ROOTSOURCE>); } public TARGET Map(ROOTSOURCE source) { _rootChain.Handle(source); return _value; } public void Handle(SOURCE source, IMapperContext context) { ContextualMapper<SOURCE, TARGET> contextualMapper = _mapper as ContextualMapper<SOURCE, TARGET>; if (contextualMapper != null) { _value = contextualMapper.Map(source, context); } else { _value = _mapper.Map(source); } if (_handler != null) { _handler.Handle(_value, context); } } public object Clone() { if (_handler != null) { return new MapTo<ROOTSOURCE, SOURCE, TARGET>( _handler.Clone() as IWorkflowHandler<TARGET>, _mapper, _rootChain); } else { return new MapTo<ROOTSOURCE, SOURCE, TARGET>(_mapper, _rootChain); } } public void AddHandler<HANDLETYPE>(IWorkflowHandler<HANDLETYPE> handler) { if (_handler == null) { _handler = handler as IWorkflowHandler<TARGET>; } else { IWorkflowChainable chain = _handler as IWorkflowChainable; if (chain != null) { chain.AddHandler<HANDLETYPE>(handler); } } } } public class Processor<ROOTSOURCE, TARGET> : IProcessor<ROOTSOURCE>, IWorkflowHandler<TARGET> { private IProcessor<TARGET> _process { get; set; } private MapFrom<ROOTSOURCE> _rootChain { get; set; } public Processor(IProcessor<TARGET> process, MapFrom<ROOTSOURCE> rootChain) { _process = process; _rootChain = rootChain; _rootChain.AddHandler<TARGET>(this); } public void Process(ROOTSOURCE source) { _rootChain.Handle(source); } public void Handle(TARGET source, IMapperContext context) { ContextualProcessor<TARGET> contextualProcess = _process as ContextualProcessor<TARGET>; if (contextualProcess != null) { contextualProcess.Process(source, context); } else { contextualProcess.Process(source); } } public object Clone() { return new Processor<ROOTSOURCE, TARGET>(_process, _rootChain); } } TrackbacksThe trackback URL for this entry is: http://mdwren.spaces.live.com/blog/cns!9C2D8683D2D11400!290.trak Weblogs that reference this entry
|
|
|