1

I initially started a project with Facades and Polymorphism as a way to create simple extensible design following SOLID Principles. Here is a sample code:

public interface IInterface
{
    void FillList(List<InputPocoObject> listOfInputObjects, out List<OutputPocoObject> ListOfOutputObjects);
}

public class SampleClass : IInterface
{

    public void FillList(List<InputPocoObject> listOfInputObjects, out List<OutputPocoObject> ListOfOutputObjects)
    {
        //some data layer code 
        //and a for loop to fill OutputPocoObject object and add it to list
    }
}

I have number of classes such as above which are created in runtime with the help of factory( not shown here for the sake of simplicity)

Recently after couple of months I see that there are different requirements emerging in my project, which I attempted to solve by the help of Polymorphism and I see that I am stuck with violating DRY principles.

Here is a sample code of this situation:

public class SampleClass2 : IInterface
{

    public void FillList(List<InputPocoObject> listOfInputObjects, out List<OutputPocoObject> ListOfOutputObjects)
    {
        //some data layer code 
        //and a for loop to fill OutputPocoObject object and add it to list
        // there is a property in OutputPocoObject which is set to 1
    }
}


public class SampleClass3 : IInterface
{

    public void FillList(List<InputPocoObject> listOfInputObjects, out List<OutputPocoObject> ListOfOutputObjects)
    {
        //same code as above 
        //with only one difference that  property in OutputPocoObject is set to 5 here
    }
}

One Simple solution will be to add a control parameter to interface such as:

public interface IInterface
{
    void FillList(List<InputPocoObject> listOfInputObjects, out List<OutputPocoObject> ListOfOutputObjects, int controlParameter);
}

but I don't know whether this is such a better idea? Or whether it might introduce some complexity in my design?

  • Could you give so more detail as to what you are trying to achieve? The entire point of an interface is that you can replace the concrete class with something else that implements the interface, effectively giving you different functionality without breaking the contract. By modifying your interface, you're breaking the contract, so that suggests that you have more flexibility in design than it seems. From what you've shown, I don't see anything wrong with having a factory that returns IInterface, which wraps SampleClass2 or 3. The client doesn't care either way. – Sinaesthetic Jan 29 '14 at 3:37
  • @Sinaesthetic I was trying to follow DRY(Don't repeat Yourself) principle. In my existing classes there was 95% of code that was duplicated, which is bad and will eventually lead to more maintenance in case of any requirement changes. So, I solved it with the help of composition as shown in the answer. – shankbond Feb 18 '14 at 15:17
  • 1
    Aside from the question - why use a void method with an out parameter instead of making List<OutputPocoObject> the return value of FillList? – Dan Lyons Feb 18 '14 at 18:07
  • @DanLyons It is only a dummy method shown here. – shankbond Feb 19 '14 at 11:36
1

Create a class that converts InputPocoObject into an OutputPocoObject (an adapter class) and pass it - or multiple instances of it - into the FillList method.

  • Thanks for the quick reply. If I understood You, You are saying that I should encapsulate my filling logic into Adapter class, and pass this adapter class as a parameter in my fill method. But there is still that duplicated code as per my my question. Can You please show an example. – shankbond Nov 24 '13 at 17:16
  • updated Your answer with similar approach that I have used :) – shankbond Feb 18 '14 at 15:18
  • @shankbond I'm glad to hear that. Thanks for accepting my answer, too. Would you please include the solution you came up with in your question, though? Your edit of my answer was already rejected by moderators. That's because replying to someone in somebody's answer is confusing and not considered a valid edit by the rules of this site. – Konrad Morawski Feb 18 '14 at 15:45
  • added as a separate answer, I guess we can't add answer in the question also as per rules :) – shankbond Feb 18 '14 at 16:18
  • @shankbond yeah good point. Another answer is probably best – Konrad Morawski Feb 18 '14 at 16:29
1

There are many ways to solve your problem. The most obvious is to create abstract base class under SampleClass2 and 3. This abstract class will implement FillList in a way that is common between those two and will also call GetNumberX() abstract method, that will return number to assign and then will be implemented accordingly in SampleClass 2 and 3.

But I'm noticing you are repeating yourself in one more thing : actually having to write the loop. Why not just have :

public interface IConverter{
    void InitializeData(); //some data layer code 
    OutputPocoObject Convert(InputPocoObject in); // called for every converted object
}

And have the looping somewhere else.

1

In addition to Konrad's answer.

I have created a new class encapsulation the common part of SampleClass2, SampleClass3...

    public class CommonClass
    {
        public void CommonMapper_FillList(List<InputPocoObject> listOfInputObjects, out List<OutputPocoObject> ListOfOutputObjects)
        {
            //some data layer code 
        }
    }

Then with the help of Composition I have removed duplication in SampleClass2, SampleClass3...

    public class SampleClass2 : IInterface
    {
        private readonly CommonClass _commonClassInstance;
        public SampleClass2()
        {
            _commonClassInstance=new CommonClass();
        }
        public void FillList(List<InputPocoObject> listOfInputObjects, out List<OutputPocoObject> ListOfOutputObjects)
        {
            //for loop to fill OutputPocoObject object and add it to list
            //_commonClassInstance.CommonMapper_FillList method to fill common functionality
            // set property in which is different OutputPocoObject to 1
        }
    }

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.