0

I am currently creating Excel import modules for some complex data. I didn't plan it well and I have met code reuse issues. I have made first modules and I realized that next modules will need some methods from these I have already made. My first option was to solve it by simple inheritance hierarchy. Unfortunately I couldn't do it, because some subclasses needed functions from two superclasses, which means that I had to use multiple inheritance, which is not supported in language that I use (C#). The only other way to solve it that I could think of, was to create multiple interfaces and their implementations for each method that I had to reuse. I did it and whole structure looks now like this:

public interface IImportAssistant<TReturn, TSearchKey>
{
    bool TryGetNewOrChanged(TSearchKey searchKey, out TReturn object);
}

public interface IMaterialImportAssistant : IImportAssistant<Material, string>
{
}

public interface ICustomerImportAssistant : IImportAssistant<Customer, string>
{
}

public class MaterialImportAssistant : IMaterialImportAssistant
{
    public bool TryGetNewOrChanged(
    string materialId,
    Dictionary<string, Material> materialToIdMappings,
    Dictionary<string, MaterialServiceItemDto> materialFromServiceToIdMappings,
    out Material material)
    {
         bool materialFoundInService = materialFromServiceToIdMappings.TryGetValue(materialId, out MaterialFromServiceItemDto materialFromService);
         if (!materialFoundInService)
             throw new ImportValidationException("Material could not be found");

         bool materialFound = materialToIdMappings.TryGetValue(materialId, out material);
         if (materialFound)
         {
              if (material.Name == materialFromService.Name
                  && material.SupplyProducerName == materialFromService.SupplyProducerName
                  && material.SupplyProducerId == materialFromService.SupplyProducerId)
                     return false;

             material.Name = materialFromService.Name;
             material.SupplyProducerName = materialFromService.SupplyProducerName;
             material.SupplyProducerId == materialFromService.SupplyProducerId;

             return true;
         }
         else
         {
             material = new Material()
             {
                  Name = materialFromService.Name,
                  SupplyProducerName = materialFromService.SupplyProducerName,
                  SupplyProducerId == materialFromService.SupplyProducerId
             };

             return true;
         }
    }
}

public class CustomerImportAssistant : ICustomerImportAssistant
{
     //Code simmilar to material but with Customer entity
}

There are other implementations for each entity I had to put in my system from an excel file. As you can see method checks if entity exists in outside system, then checks if it already is in our database and if it has changed. It is simple method, but I didn't want to copy paste it in every import module, which has to check given entity. Now as I look at it and at over a dozen interfaces and their implementations, I wonder if I should make just one big interface and implementation for all these methods. The advantage that I can see, is less files with code and less dependency to inject in constructor classes. The disadvantage is that it would be like a function bag, which is against single class responsibility and general OOP guidelines. I am a beginner programmer and I think I know language tools well, but I lack at bigger perspective and my actions after-effects, hence impact on maintainability and expansibility of what I do. Could you tell me if there are other advantages or disadvantages of both soultions? Or maybe there is some other design pattern, which solves such cases? What are best practices in such situations?

  • Your code is not correct. One major thing I ran into is that materialFromService is not defined anywhere, which makes it hard to understand your code. – Jonathan van de Veen May 22 '18 at 9:51
1

Think functional, not object-oriented. Functional techniques provide a work-around to multiple inheritance. Your interface/implementation pairs are essentially the same as first class functions.

Collect all the common code into one method, then the variable code can either go into overridden methods (interfaces don't help much here) or provided via function or action parameters.

0

There is a third solution here. The difference between each implementation of the method in your example is the mapping of properties. Create a base type for your DTO's and your client classes with methods loading the data from the DTO's in the client object. You can then override methods in the derived classes to abstract away the mapping of properties between DTO's and client objects.

0

This code works like an ORM framework - here retrieving data. I'd use one instead. Then, I pay attention to R criteria of CRUD operations - here material/customer ID and expect to get actual Material/Customer object.

If ORM is not an option than reinvent the wheel. One way is to provide mapping files in JSON/XML/... format e.g. class="Material", property="name", ... that can be read by a general retrieving mechanism. A more integrated solution with C# may focus on C# attributes instead of mapping files. The enhancement to that would be reading properties from the model class. The end result:

Material material = yourORMakaImportAssistant.createQuery(typeof(Material), materialID);

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.