Problem
I have several generic methods that use the typeof
operator to determine the type of mapper class to create. Eventually this is going to get out of hand.
Can anyone suggest a better way to handle this? I have been reading up a bit and it seems like an abstract factory pattern or IOC would be a good pattern to use. I’m not familiar with IOC. Can someone provide an opinion on which would be better in this scenario?
internal UpdateStudentDocumentRequest MapDocToUpdateDocumentRequest<T>(T doc)
{
Type docType = typeof(T);
//V1
if
(
docType == typeof(IndV1201314Model) ||
docType == typeof(IndV1201415Model) ||
docType == typeof(DepV1201415Model)
)
{ return new V1DocMapper<Models.Verification.V1Base>().MapV1ToUpdateStudentDocumentRequest(doc as Models.Verification.V1Base); }
//V3
if
(
docType == typeof(IndV3201314Model) ||
docType == typeof(IndV3201415Model) ||
docType == typeof(DepV3201415Model)
)
{ return new V3DocMapper<Models.Verification.V3Base>().MapV3ToUpdateStudentDocumentRequest(doc as Models.Verification.V3Base); }
//FASchol
if (docType == typeof(FAScholModel))
{return new FAScholMapper().MapFAScholToUpdateStudentDocumentRequest(doc as FAScholModel);}
return new UpdateStudentDocumentRequest();
}
Solution
IOC vs Abstract factory is kind of an apples to oranges question. Abstract factory assumes you have a collection of related classes for which you don’t want to know any of details involved in creating instances of those classes. IOC doesn’t necessarily abstract you away from the creation, it just sort of moves it to another area of your code base. In your particular scenario, one way to simplify that code might be like this
public class DocumentMappingSelector
{
private Dictionary<Type, Type> mappingRoutes = new Dictionary<Type,Type>();
public void AddRoute(DocumentMappingRoute route)
{
if (this.mappingRoutes.ContainsKey(route.SourceType))
{
// you could throw an exception or replace the route here, for this
// example i'll just replace it
if (this.mappingRoutes[route.SourceType] != route.MapperType)
{
this.mappingRoutes[route.SourceType] = route;
}
else
{
this.mappingRoutes.Add(route.SourceType, route);
}
}
}
public DocumentMappingRoute SelectMappingRoute(Type sourceType)
{
DocumentMappingRoute result = null;
if (this.mappingRoutes.ContainsKey(sourceType))
{
result = this.mappingRoutes[sourceType];
}
return result;
}
}
public class DocumentMappingRoute
{
public DocumentMappingRoute(Type sourceTypeToBeMapped, Type mappingStrategyType, Action<object,UpdateStudentDocumentRequest> mappingProcessAction)
{
this.SourceType = sourceTypeToBeMapped;
this.MapperType = mappingStrategyType;
this.MappingProcess = mappingProcessAction;
}
Type SourceType { get; private set; }
Type MapperType { get; private set; }
Action<object,UpdateStudentDocumentRequest> PerformMapping { get; private set; }
}
internal UpdateStudentDocumentRequest MapDocToUpdateDocumentRequest<T>(T doc)
{
Type sourceType = typeof(T);
UpdateStudentDocumentRequest updateStudentDocumentRequestInstance = new UpdateStudentDocumentRequest ();
return selectorInstance.SelectMappingRoute(sourceType).MappingProcess(doc, updateStudentDocumentRequestInstance); // you might not need the updateStudentDocumentRequestIsntance paramter here
}
For give any errors, I didn’t type this in visual studio I just typed it in this editor.
- Create and Add Document mapping routes to the selector
- Get the mapping from the selector
Sorry this doesn’t show the full code. I ran short on time, but this should give you a general direction that will keep your code tight. Let me know if you have any questions.