5
\$\begingroup\$

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();
}
\$\endgroup\$
  • \$\begingroup\$ The over-the-counter remedy would be visitor pattern or making each document map itself, but the real useful answer would depend on who owns what classes, for example if different teams/vendors own document and mapper classes. Even if you own all of them which classes are in the same assembly (and are easy to modify together). \$\endgroup\$ – abuzittin gillifirca Feb 21 '14 at 8:41
2
\$\begingroup\$

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.

  1. Create and Add Document mapping routes to the selector
  2. 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.

\$\endgroup\$
  • \$\begingroup\$ there is a bug in the AddRoute method... i'll fix it in a few \$\endgroup\$ – Mark At Ramp51 Feb 22 '14 at 21:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.