Vasya Rogov
Vasya Rogov

Reputation: 164

Which OOP design pattern to use for different actions on an object based on its field values?

I have entity in database, say, MonthPlan:

class MonthPlan {
    private boolean approved;

    // other fields
}

There is also REST interface, which accepts external requests based on which program changes entity instances. For example, request

class EditMonthPlanRequest {
    private long amount;

    // other fields
}

is used to change month plan amount.

What I need is to execute different actions on MonthPlan entity based on value of approved field. For example, code for mentioned request could be as following

MonthPlan plan = getPlan(...);
if (plan.isApproved()) {
    // actions using data from EditMonthPlanRequest
} else {
    // other actions using data from EditMonthPlanRequest
}

There would be 5-6 different requests each with exactly two variants of actions based on value of approved field of edited entity. What OOP design pattern can I use for such use case to write more concise code?

Upvotes: 1

Views: 2017

Answers (4)

Kawser Habib
Kawser Habib

Reputation: 1422

In this scenario, the state pattern is more suitable.

State design pattern is used when an Object changes its behavior based on its internal state.

If we have to change behavior of an object based on its state, we can have a state variable in the Object and use if-else condition block to perform different actions based on the state. State pattern is used to provide a systematic and lose-coupled way to achieve this through Context and State implementations.

Try to implement based on your description:

public class StatePattern {

    public static void main(String[] args) {
        MonthPlan monthPlan = null; //= new MonthPlan(...)
        StateContext stateContext = new StateContext();
        if(monthPlan.isApproved()) {
            stateContext.setState(new Approved());
        }else {
            stateContext.setState(new NotApproved());
        }
    }
}

class MonthPlan {
    private boolean approved;

    public boolean isApproved() {
        return approved;
    }
    // other fields
}

interface State{
    public void doAction(StateContext ctx);
}

class StateContext{
    private State currentState;
    
    public StateContext() {
        //default Approved state, you can change if you want
        currentState = new Approved(); 
    }
    
    public void setState(State state) {
        currentState = state;
    }
    
    public void doAction() {
        currentState.doAction(this);
    }
    
}

class Approved implements State{
    @Override
    public void doAction(StateContext ctx) {
        //actions using data from EditMonthPlanRequest
    }
}

class NotApproved implements State{
    @Override
    public void doAction(StateContext ctx) {
         //other actions using data from EditMonthPlanRequest
    }
}

Upvotes: 1

jaco0646
jaco0646

Reputation: 17066

If you want to do OOP, then replace conditionals with polymorphism.

In this example, it means splitting MonthPlan in two.

  • class ApprovedMonthPlan extends MonthPlan
  • class UnapprovedMonthPlan extends MonthPlan

Each class handles EditMonthPlanRequest in its own way.

Upvotes: 0

GeertPt
GeertPt

Reputation: 17846

For this simple case, the Template Method pattern may apply:

abstract class AbstractRequest {

  public void execute(...){
    MonthPlan plan = getPlan(...);
    if (plan.isApproved()) {
      executeForApproved(plan);
    } else {
      executeForNonApproved(plan);
    }
  }

  protected abstract void executeForApproved(MonthPlan plan);

  protected abstract void executeForNonApproved(MonthPlan plan);
}

This way, you don't need to repeat the if statement and the getPlan(...) in each subclass:

class EditMonthPlanRequest extends AbstractRequest {
  private long amount;
  // other fields

  protected void executeForApproved(MonthPlan plan){
     ...
  }

  protected void executeForNonApproved(MonthPlan plan){
     ...
  }

}  

Upvotes: 0

lkatiforis
lkatiforis

Reputation: 6255

I do not think you need a design pattern in such a simple case. Each request will be processed by the corresponding method at Service layer.

Upvotes: 2

Related Questions