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?
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:
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.
Two approaches:
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
andImplementationForAbortedClient
implementSomeAbstraction
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.
My first cut would be to replace the if/else if structures with switch/case:
From there I'd probably extract each block as a method, and from there apply the Strategy pattern. Stop at whatever point feels right.