简体   繁体   中英

Replace Multiple If\Else with Design Pattern

Based on various threads on SO (ex. Replacing if else statement with pattern ) I understand that I can replace multiple if\\else statements with the Command pattern.

My situation is a bit different.

I have a series of Commands and I need to execute each Command only if the previous command was unsuccessful.

For example, suppose I need to retrieve text from a hypothetical web page - I could scrape the text directly from the page using screen scraping or I could fetch the text from the API. I would only want to fetch the text from API if screen scraping was not successful. In other words I would only execute the "fetch" command if the "scrape" command didn't work.

In this case, I would test if the scraped String is empty or equal to null and then execute the second Command. If the second command is also unsuccessful I would execute the third Command and so on.

The important point is that we only execute subsequent commands if a certain condition is true/false. The condition is always the same for each Command but the number of commands might grow in the future.

I cannot implement this via the typically suggested route (using a Map and Command interface) bec this would not execute the next Command if the first one failed (it would also be unable to check if a Command was successful or not)

What design pattern could be used to solve this problem?

As others have said, use the Chain of Responsibility Pattern which can keep trying different implementations in serial until one succeeds.

Let's say your Command has this interface where a handled Request returns a Result object if it succeeds or null if it failed ( could also use a boolean or Optional or whatever you want)

public interface Command{

  Result handle( Request request);
}

Then your chained Command could wrap several other Commands and try each one until something works.

public class ChainedCommand implements Command {
    //could also be set in a constructor instead
    List<Command> commandChain = Arrays.asList( new ScrapperCommand(),
                                            new ApiCommand());


    public Result handle( Request request){

         Result result = null;
         Iterator<Command> iter = commandChain.iterator();
         while( result ==null && iter.hasNext()){
              result = iter.next().handle(request);
         }

         return result;
    }
}

People have suggested using the chain of responsibility pattern however as I was thinking of the problem it occurred to me I could use a variation of the Command pattern to solve this problem. It works like this.

Replace each if statement with a corresponding class which implements the Command interface. In our example, I would implement the classes ScreenScrapeTextCommand and FetchTextFromAPICommand . Since each class will implement the Command interface we will add the method execute() to each class (this method will actually execute the functionality we need such as screen scraping or fetching from API).

We'd then create a new class which contains all related commands. Let's call this class GetTextCommandCenter . The class would contain a list of Commands in the form of public List<Command> commandList; We'd then hard code commands by adding the first two classes to the list in the following manner:

commandList.add(new ScreenScrapeTextCommand();
commandList.add(new FetchTextFromAPICommand();

We could then replace the if\\else chain with the following:

public String replaceIfElseWithCommand()..

String text = null;
int commandIndex = 0;

while (text == null && text == someCondition)
{

text = new GetTextCommandCenter().commandList(commandIndex).execute();
commandIndex++;
}

return text;

}

As soon as a command is successful the the condition in the while loop will fail and method will return accordingly.

This way, we can easily add more Commands by adding more classes to CommandCenter class or change the precedence of individual commands quickly.

I think this is a simple and straightforward solution to my problem (but please place a comment if you think the chain of responsibility pattern is more suitable and why you think so)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM