Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid duplicated if statements

I have multiple services that implement interface with one method - execute(). Each service uses this method to execute some actions based on a String value, which, in original code, is enum, so those values are constants.

interface Service{
   public void execute();
}

class Service1 implements Service{
   //constructors
   public void execute(JSONObject payload, String payloadType){
      if(payloadType.equals("type1")){
       doSomething(payload);
      }
   }
}

class Service2 implements Service{
   //constructors
   public void execute(JSONObject payload, String payloadType){
      if(payloadType.equals("type1")){
       doSomething1(payload);
      }
      if(payloadType.equals("type2")){
       doSomething2(payload);
      }
   }
}

I want to avoid writing same if statements each time I create a new Service. Problem is, that each Service doesn't have to execute actions based on each string types. So Service1 executes action when type is equal to "type1", however Service2 executes actions based on "type1" and "type2".

I tried following solution:

class Main {
  public static void main(String[] args) {
    exec(new B(), "type2");
  }

  private static void exec(Service service, JSONObject payload, String payloadType){
      if(payloadType.equals("type1")){
       Init i = (Init)service;
       i.init(payload);
      }
      if(payloadType.equals("type2")){
       Action a = (Action)service;
       a.action(payload);
      }
  }
}

interface Service{

}

interface Init{
  public void init(JSONObject payload);
}

interface Action{
  public void action(JSONObject payload);
}

class A implements Service, Init{
  @Override
  public void init(JSONObject payload){
    doSomething(payload);
  }
}

class B implements Service, Init, Action{

  @Override
  public void init(JSONObject payload){
    doSomething1(payload);
  }

 @Override
   public void action(JSONObject payload){
    doSomething2(payload);
  }
}

The above code works, but I don't like using casting. I think it's not a good practice, also very unsafe. Could you suggest, what design pattern or other solution could I use here? I tried visitor, but I couldn't figure out the right implementation with this case.

UPDATE

Thanks for all the answers, they were very helpfull. I managed to achieve what I was looking for. Here's the code that finally works.

public class Main {

    public static B b = new B();
    public static A a = new A();

    public static void main(String[] args) {
        exec(b, "init");
    }

    private static void exec(Service service, String type){
        if(type.equals("init") && service instanceof Init){
            service.fillCarrier(new InitCarrier());
        }
        if(type.equals("action") && service instanceof Action){
            service.fillCarrier(new ActionCarrier());
        }
    }
}

interface Carrier<T>{
    public void set(T t);
}

class InitCarrier implements Carrier<Init>{
    public void set(Init init){
        init.init();
    }
}

class ActionCarrier implements Carrier<Action>{
    public void set(Action action){
        action.action();
    }
}

abstract class Service{
    public void fillCarrier(Carrier carrier){
        carrier.set(this);
    }
}

interface Init{
    public void init();
}

interface Action {
    public void action();
}

class A extends Service implements Init{
    
    @Override
    public void init(){
        System.out.println("init a");
    }
}

class B extends Service implements Init, Action{

    @Override
    public void init() {
        System.out.println("init b");
    }

    @Override
    public void action(){
        System.out.println("action");
    }
}

like image 249
Logan Avatar asked Oct 15 '22 22:10

Logan


1 Answers

To achieve this requirement, we need to pattern.

  1. Factory pattern.
  2. Strategy pattern.

TypeFactory creates an object based on the string we delivered. Each Type implementation implements a doSomething() method in its own way. (factory pattern is used here)

Type Strategy:

interface Type{
    public void doSomething();
}

class TypeOne implements Type{
    @Override
    public void doSomething() {
        System.out.println("Type One!");    
    }
}

class TypeTwo implements Type{
    @Override
    public void doSomething() {
        System.out.println("Type Two!");
        
    }
}

Type Factory:

class TypeFactory{
    Type type;
    public Type createType(String condition) {
        if (condition == null || condition.isEmpty()) {
            return null;
        }
        if ("type1".equals(condition)) {
            return new TypeOne();
        }
        else if ("type2".equals(condition)) {
            return new TypeTwo();
        }
        return null;
    }
}

Now to achieve the final goal, we need to declare a Service interface with an execute method. This execute method takes Type as an input parameter. Based on which type you actually pass, the corresponding doSometing method will be invoked. (strategy pattern used only)

interface Service{
    public void execute(Type type);
}

class ServiceOne implements Service{

    @Override
    public void execute(Type type) {
        System.out.print("Service One - ");
        type.doSomething();
        
    }
}

class ServiceTwo implements Service{

    @Override
    public void execute(Type type) {
        System.out.print("Service Two - ");
        type.doSomething();
        
    }
}

Main Class looks like this:

public class DesignPatternCombo {

    public static void main(String[] args) {
        
        Type typeOne = new TypeFactory().createType("type1");
        Type typeTwo =  new TypeFactory().createType("type2");
        
        Service serviceOne = new ServiceOne();
        serviceOne.execute(typeOne);
        
        Service serviceTwo = new ServiceTwo();
        serviceTwo.execute(typeOne);
        serviceTwo.execute(typeTwo);

    }

}

Expected output:

Service One - Type One!
Service Two - Type One!
Service Two - Type Two!
like image 88
Md Kawser Habib Avatar answered Oct 17 '22 13:10

Md Kawser Habib