Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to solve the "Growing If Statement" problem?

I've been doing some reading about design patterns and wanted some perspective. Consider the following:

Dim objGruntWorker as IGruntWorker

if SomeCriteria then
   objGruntWorker = new GoFor()
else if SomeOtherCriteria then
   objGruntWorker = new Newb()
else if SomeCriteriaAndTheKitchenSink then
   objGruntWorker = new CubeRat()
end if

objGruntWorker.GetBreakfast()
system.threading.thread.sleep(GetMilliSecondsFromHours(4))
objGruntWorker.GetLunch()

The above code grows each time a new Criteria arises. I've seen code like this all over the place and in ignorance wrote some of it myself. How should this be solved? Does this kind of anti-pattern have a more "formal" name? Thanks for your help!

Edit: Another consideration is I want to avoid having to recompile the existing implementations of IGruntWorker simply to add a new implementation.

like image 317
Achilles Avatar asked Jun 08 '10 13:06

Achilles


2 Answers

That sort of logic is often encapsulated using the Factory method pattern. (See the ImageReaderFactory example under Encapsulation.)

like image 100
Bill the Lizard Avatar answered Oct 24 '22 07:10

Bill the Lizard


The type of pattern that would suit the above solution would be the Factory Pattern. You have a situation where you don't need to know the concrete type of object you require, it just has to implement IGruntWorker. So you create a factory which takes in a criteria and based on that criteria you would return the specific IGruntWorker object. It is usually a good idea to map the criteria to some identifier i.e. an enumeration or constant for readability e.g.

public enum WorkerType
{
    Newbie,
    Average,
    Expert
}

public class WorkerFactory
{
    public static IGruntWorker GetWorker(WorkerType type)
    {
        switch (type)
        {
            case WorkerType.Newbie:
                 return new NewbieWorker();
            case WorkerType.Average:
                 return new AverageWorker();
            case WorkerType.Expert:
                 return new ExpertWorker();
        }
    }
}

So in your case you could have a small helper method that works out the correct type of Worker required based on the criteria. This could even be wrapped up in a read-only property which you just pass into the factory.

like image 32
James Avatar answered Oct 24 '22 06:10

James