Replace ordered if condition with design pattern

Viewed 45

I've a legacy class with lots of if conditions, like:

public MyType methodWithIfs() {
  if (condition1) {
    return new MyType(param1);
  }

  if (condition2) {
    return new MyType(param2);
  }
  ....
}

Every if condition returns a type of MyType.

Also there is a order in which these conditions are mentioned. Two conditions can be true but only first that matched the criteria should be executed based on order.

I was thinking of replacing these conditions with Conditional Dispatcher with Command design pattern

Since there is an order to be maintained, instead of using HashMap<Boolean, MyType>, I was thinking of using LinkedHashMap<Boolean, MyType>.

But this seems dodgy. Is there any cleaner way I can replace these conditions?

Thanks!

2 Answers

It's a perfect case for the factory pattern. From https://www.tutorialspoint.com/design_pattern/factory_pattern.htm:

In Factory pattern, we create object without exposing the creation logic to the client and refer to newly created object using a common interface.

Since in all cases we are returning MyType instance, there is no problem to use that methodWithIfs body as a factory method, which would return MyType instance created in line with rules which we should keep in specific cases.

public MyType createMyType(Object param1, Object param2) {
  if (condition1) {
    return new MyType(param1);
  }

  if (condition2) {
    return new MyType(param2);
  }
  ....
}

public MyType methodWithIfs(){
    return createMyTypeObj(param1, param2)
}

It's kinda important when we are talking about design patterns - things like 100-line long switch/case or ifs chain aren't simply internally bad. It's all about maintenance - creating code in line with rules that would provide that the code will be clean, readable and easy to maintain in the future.

One of the way is to use Chain of Responsibility pattern. As wiki says:

The chain-of-responsibility pattern is a behavioral design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain. A mechanism also exists for adding new processing objects to the end of this chain

So let's dive in code. I am sorry, I am not Java guy. Let me show an example via C#. I've provided comments how code would be look in Java.

So this is out model class which we want to create based on some conditions:

public class Vehicle
{
    public string _color;

    public int _doorsCount;

    public int _wheelCount;

    public Vehicle(string color)
    {
        _color = color;
    }

    public Vehicle(int doorsCount)
    {
        _doorsCount = doorsCount;
    }

    public Vehicle(int doorsCount, int wheelCount)
    {
        _doorsCount = doorsCount;
        _wheelCount = wheelCount;
    }
}

And this is parameter class which you use in your if else statements:

public class Parameter
{
    public string Parameter_1 { get; set; } // just simple variable in Java
    public string Parameter_2 { get; set; }
    public string Parameter_3 { get; set; }
}

And this is an abstraction of VehicleHandler which defines behaviour to to set next handler:

public abstract class VehicleHandler
{
    private VehicleHandler _nextVehicleHandler;

    public void SetSuccessor(VehicleHandler nextVehicleHandler)
    { 
        _nextVehicleHandler = nextVehicleHandler;
    }

    public virtual Vehicle Execute(Parameter parameter)
    { 
        if (_nextVehicleHandler != null)
            return _nextVehicleHandler.Execute(parameter);

        return null;
    }
}

and its concrete implementations of VehicleHandler:

public class FirstVehicleHandler : VehicleHandler // "inherits" in Java
{
    public override Vehicle Execute(Parameter parameter)
    {
        if (parameter.Parameter_1 != null)
            return new Vehicle("green");

        return base.Execute(parameter);
    }
}

public class SecondVehicleHandler : VehicleHandler // "inherits" in Java
{
    public override Vehicle Execute(Parameter parameter)
    {
        if (parameter.Parameter_2 != null)
            return new Vehicle(4);

        return base.Execute(parameter);
    }
}

public class ThirdVehicleHandler : VehicleHandler // "inherits" in Java
{
    public override Vehicle Execute(Parameter parameter)
    {
        if (parameter.Parameter_3 != null)
            return new Vehicle(4, 4);

        return base.Execute(parameter);
    }
}

And then you can call the above code like this:

VehicleHandler chain = new FirstVehicleHandler();
VehicleHandler secondVehicleHandler = new SecondVehicleHandler();
VehicleHandler thirdVehicleHandler = new ThirdVehicleHandler();

chain.SetSuccessor(secondVehicleHandler);
secondVehicleHandler.SetSuccessor(thirdVehicleHandler);

Parameter parameter = new Parameter();
parameter.Parameter_1 = "The color should be green";

Vehicle vehicle = chain.Execute(parameter); // color of vehicle is green
Related