Best design pattern/approach for a long list of if

2019-05-01 10:17发布

I have a "legacy" code that I want to refactor.
The code basically does a remote call to a server and gets back a reply. Then according to the reply executes accordingly.
Example of skeleton of the code:

public Object processResponse(String responseType, Object response) {
    if(responseType.equals(CLIENT_REGISTERED)) {  
       //code  
       //code ...
    }  
    else if (responseType.equals(CLIENT_ABORTED)) {
       //code  
       //code....
    }    
    else if (responseType.equals(DATA_SPLIT)) {
      //code
      //code... 
   }  
   etc  

The problem is that there are many-many if/else branches and the code inside each if is not trivial.
So it becomes hard to maintain.
I was wondering what is that best pattern for this?
One thought I had was to create a single object with method names the same as the responseType and then inside processResponse just using reflection call the method with the same name as the responseType.
This would clean up processResponse but it moves the code to a single object with many/many methods and I think reflection would cause performance issues.
Is there a nice design approach/pattern to clean this up?

3条回答
男人必须洒脱
2楼-- · 2019-05-01 10:23

The case you've describe seems to fit perfectly to the application of Strategy pattern. In particular, you've many variants of an algorithm, i.e. the code executed accordingly to the response of the remote server call.

Implementing the Stategy pattern means that you have to define a class hierachy, such the following:

public interface ResponseProcessor {
   public void execute(Context ctx);
}
class ClientRegistered implements ResponseProcessor {
   public void execute(Context ctx) {
      // Actions corresponding to a client that is registered
      // ...
   }
}
class ClientAborted implements ResponseProcessor {
   public void execute(Context ctx) {
      // Actions corresponding to a client aborted
      // ...
   }
}
// and so on...

The Context type should contain all the information that are needed to execute each 'strategy'. Note that if different strategies share some algorithm pieces, you could also use Templeate Method pattern among them.

You need a factory to create a particular Strategy at runtime. The factory will build a strategy starting from the response received. A possibile implementation should be the one suggested by @Sattar Imamov. The factory will contain the if .. else code.

If strategy classes are not to heavy to build and they don't need any external information at build time, you can also map each strategy to an Enumeration's value.

public enum ResponseType {
   CLIENT_REGISTERED(new ClientRegistered()),
   CLIENT_ABORTED(new ClientAborted()),
   DATA_SPLIT(new DataSplit());

   // Processor associated to a response
   private ResponseProcessor processor;

   private ResponseType(ResponseProcessor processor) {
      this.processor = processor;
   }
   public ResponseProcessor getProcessor() {
      return this.processor;
   }
}
查看更多
做自己的国王
3楼-- · 2019-05-01 10:27

Two approaches:

  1. Strategy pattern http://www.dofactory.com/javascript/strategy-design-pattern
  2. Create dictionary, where key is metadata (in your case metadata is responseType) and value is a function.

For example:

Put this in constructor

responses = new HashMap<string, SomeAbstraction>(); responses.Put(CLIENT_REGISTERED, new ImplementationForRegisteredClient()); responses.Put(CLIENT_ABORTED, new ImplementationForAbortedClient());

where ImplementationForRegisteredClient and ImplementationForAbortedClient implement SomeAbstraction

and call this dictionary via responses.get(responseType).MethodOfYourAbstraction(SomeParams);

If you want to follow the principle of DI, you can inject this Dictionary in your client class.

查看更多
祖国的老花朵
4楼-- · 2019-05-01 10:42

My first cut would be to replace the if/else if structures with switch/case:

public Object processResponse(String responseType, Object response) {
    switch(responseType) {
        case CLIENT_REGISTERED: {  
       //code ...
    }  
    case CLIENT_ABORTED: {
       //code....
    }    
    case DATA_SPLIT: {
      //code... 
   }  

From there I'd probably extract each block as a method, and from there apply the Strategy pattern. Stop at whatever point feels right.

查看更多
登录 后发表回答