Balraj Singh Balraj Singh - 4 months ago 5
Objective-C Question

Better approach to refactor conditional part of the code

I am trying to refactor a given piece of code as mentioned below:

ORIGINAL CODE:

Method(URL link)
{
if(ConditionA(link))
{
MehodA(link);
}else if(ConditionB(link))
{
MehodB(link);
}else if(ConditionC(link))
{
MehodC(link);
}else if(ConditionD(link))
{
MehodD(link);
}
}


the above code may grow as new condition may come in future. After refactoring I am able to divide the code into multiple classes each focused with single responsibility hence reducing the initial complexity as follows:

AFTER REFACTORING:

METHOD(URL link)
{
ConditionalHandlerClass obj = new ConditionalHandlerClass(link);
ConditionalHandlerClass.HandleLinkProcessing();
}

Class ConditionalHandlerClass
{
URL link;
IConditionalProcess process;

public ConditionalHandlerClass(URL _link)
{
link = _link;
}

public void HandleLinkProcessing()
{
if(ConditionA(link))
{
process = new ProcessA(link);
}else if(ConditionB(link))
{
process = new ProcessB(link);
}else if(ConditionC(link))
{
process = new ProcessC(link);
}else if(ConditionD(link))
{
process = new ProcessD(link);
}
process.Handle();
}
}

interface IConditionalProcess
{
void handle();
}


class ProcessA() : IConditionalProcess
{
void handle()
{
// Business Logic here
}
}

class ProcessB() : IConditionalProcess
{
void handle()
{
// Business Logic here
}
}

class ProcessC() : IConditionalProcess
{
void handle()
{
// Business Logic here
}
}

class ProcessD() : IConditionalProcess
{
void handle()
{
// Business Logic here
}
}


But i see that HandleLinkProcessing() method in class ConditionalHandlerClass will still keep on increasing as new condition keeps getting added.

Can you suggest how can i make this implementation better such that class like ConditionalHandlerClass should not be changed on addition of new flow of ConditionE() and MethodE() calls. Hence reducing complexity in once class even though the new conditions get added.

I am writing this code in objective c.

Answer

I think you're on the right track. Granted, the handling can be done an infinite number of ways (and with constructor injection via DI you don't need to deal with most if it) but here's one approach which composes reusable instances of a Handler class with conditional and execution logic...

public interface IConditional
{
    bool Evaluate(Url link);
}

public class ConditionA : IConditional
{
    public bool Evaluate(Url link)
    {
        return true; // your conditional logic here
    }
}

public class ConditionB : IConditional
{
    public bool Evaluate(Url link)
    {
        return true; // your conditional logic here
    }
}

public class ConditionC : IConditional
{
    public bool Evaluate(Url link)
    {
        return true; // your conditional logic here
    }
}

public class ConditionD : IConditional
{
    public bool Evaluate(Url link)
    {
        return true; // your conditional logic here
    }
}

public interface IProcessor
{
    void Process(Url link);
}

public class MethodA : IProcessor
{
    public void Process(Url link)
    {
        // whatever A does?
    }
}

public class MethodB : IProcessor
{
    public void Process(Url link)
    {
        // whatever B does?
    }
}

public class MethodC : IProcessor
{
    public void Process(Url link)
    {
        // whatever C does?
    }
}

public class MethodD : IProcessor
{
    public void Process(Url link)
    {
        // whatever D does?
    }
}

public class Handler
{
    private IConditional conditional;
    private IProcessor processor;

    public Handler(
        IConditional conditionalReference,
        IProcessor processorReference)
    {
        this.conditional = conditionalReference;
        this.processor = processorReference;
    }

    public bool Handle(Url link)
    {
        bool handled = false;
        if (this.conditional.Evaluate(link)
        {
            this.processor.Process(link);
            handled = true;
        }

        return handled;
    }
}

public class Program
{
    public static void Main()
    {
        Handler[] orderedHandlers = new []
        {
            new Handler(new ConditionA(), new MethodA()),
            new Handler(new ConditionB(), new MethodB()),
            new Handler(new ConditionC(), new MethodC()),
            new Handler(new ConditionD(), new MethodD()),
        };

        Url link = new Url("xxx");

        foreach(Handler handler in orderedHandlers)
        {
            if(handler.Handle(link))
            {
                break;
            }
        }
    }
}
Comments