Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best design pattern for multiple if statements in an interface implementation

I have an IComposer interface in my c# project:

public interface IComposer
{
    string GenerateSnippet(CodeTree tree);
}

CodeTree is a base class that contains a List<CodeTree> of classes that inherit from CodeTree. For example:

public class VariablesDecleration : CodeTree
{
     //Impl
}

public class LoopsDecleration : CodeTree
{
     //Impl
}

I can have a few classes that implement IComposer and in each I have the GenerateSnippet that loops over the List<CodeTree> and basically do:

foreach (CodeTree code in tree.Codes)
{
    if (code.GetType() == typeof(VariablesDecleration))
    {
        VariablesDecleration codeVariablesDecleration = (VariablesDecleration) code;
        // do class related stuff that has to do with VariablesDecleration
    }
    else if (code.GetType() == typeof(LoopsDecleration))
    {
        LoopsDecleration codeLoopsDecleration = (LoopsDecleration) code;
        // do class related stuff that has to do with LoopsDecleration
    }
}

I have this foreach and if statements repeating in each class that implements IComposer.

I was wondering if there is a better design pattern to handle such a case. lets say tommrow I add a new class that inherits from CodeTree - I would have to go over all the classes that implement IComposer and modify them.

I was thinking about the Visitor Design Pattern - but wasn't sure and not exactly sure if and how to implement it. Does Visitor even the right solution for this case?

like image 701
developer82 Avatar asked Dec 21 '15 06:12

developer82


1 Answers

Move implementation related to the specific classes inside VariablesDecleration and LoopsDecleration, providing an abstract implementation in CodeTree. Then in your loops, simple call that method in CodeTree, without an if...else check.

public class VariablesDecleration : CodeTree
{
    //Impl
    public void SomeStuff()
    {
        //... specific to Variables
    }
}

public class LoopsDecleration : CodeTree
{
    //Impl
    public void SomeStuff()
    {
        //... specific to Loops
    }
}

public class CodeTree : ICodeTree
{
    void SomeStuff();
}

foreach (CodeTree code in tree.Codes)
{
    code.SomeStuff();
}

As per the comments, you might need something like this:

public interface IComposer
{
    string DoStuff();
}

public class LoopComposer1 : IComposer
{
    string DoStuff(){ .. }
}

public class VariableComposer1 : IComposer
{
    string DoStuff(){ .. }
}

public class ComposerCollection
{
    private IEnumerable<IComposer> composers;
    string GenerateSnippet()
    {
        foreach(var composer in composers)
        {
            composer.DoStuff();
        }
        ...
        ...
    }
}

Of course, now the relation has inverted, and your code tree or its creator has to define the composer collection for it.

like image 56
Narayana Avatar answered Sep 17 '22 19:09

Narayana