Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good java design pattern for similar objects with branching logic

I want to refactor an existing class of almost 5000 lines but I'm having difficulty with the constructor. Right now it's something like the following(methods here are in reality 10-30 blocks of code )

public MyClass( MyObject o ) {
  if ( o.name.equalsIgnoreCase("a") ) {
    doSomething()
   } else  {
     doSomethingElse() 
   }
   commonCode()
   if (o.name.equalsIgnoreCase("a") ) {
     doSecondThing()
   } else {
     doOtherSecondThing() //almost identical to doSecondThing but with some extra steps that absolutely have to be done in this sequence
  }
 // more of the same

}

I considered using inheritance and breaking things up into functions that would be overridden where necessary but that feels messy to me. Is there a pattern that fits this use case? Incidentally any advice on refactoring legacy code would be more than welcome.

like image 645
LiamRyan Avatar asked Oct 27 '25 08:10

LiamRyan


2 Answers

You are exactly right. Refactoring like you described is called Replace Conditional with Polymorphism. Also you can look through on Chain-of-responsibility, Command or Strategy design patterns.

like image 198
Alex Avatar answered Oct 29 '25 23:10

Alex


If every object follows the following pattern:

if(conditionA)
    DoA();
else
    DoElse();
Common();
if(conditionA2)
    DoA2();
else if(conditionB2)
    DoB2();
else
    DoElse2();
Common2();

I'd advice you to have a common class that gathers handlers with conditions. This is roughly what I mean (Pseudo-code not java):

public interface IConditionalHandler 
{
    bool Condition();
    void Action();
}
public class ActionHandler
{
    private List<IConditionalHandler> m_FirstHandlers;
    private List<IConditionalHandler> m_SecondHandlers; //Or possibly use a list of lists
    public ActionHandler()
    {
        m_FirstHandlers = new ArrayList<>();
        m_FirstHandlers.add(new HandlerA1());
        m_FirstHandlers.add(new HandlerB1());
        m_SecondHandlers = new ArrayList<>();
        m_SecondHandlers.add(new HandlerA1());
        m_SecondHandlers.add(new HandlerB1());
    }
    void DoStuff()
    {
        for(IConditionHandler handler : m_FirstHandlers)
        {
             if(handler.Condition())
             {
                 handler.Action();
                 break;
             }
        }
        CommonA();
        for(IConditionHandler handler : m_SecondHandlers)
        {
             if(handler.Condition())
             {
                 handler.Action();
                 break;
             }
        }
    }
}

If you have lots of segment, a list of lists can include your common code as an exit-handler and contain all of the logic. You delegate the logic out to implementing classes, and shorten the actual code in your class. However, as far as efficiency goes you are going to kill both the instruction and data cache. If this isn't what you're looking for, then more than likely this is: Chain-of-Responsibility Pattern - Wikipedia

like image 34
Joachim Olsson Avatar answered Oct 29 '25 21:10

Joachim Olsson