Matt
Matt

Reputation: 793

Improve code with several booleans conditions java

I got a big problem to deal with, my code is too long and full characters. I removed a lot, using methods and using some proper design patterns... But it is still too "crowded".

I get a string from the user, a question like:

"How are you Josh?"
"Who is Josh's mother?"

I need to analyze that question so see it's content and to System.out.print() the answer.

so a long serie of "if/else if" starts e.g

if (question.startsWith("How") && question.endsWith("Josh?"))
{
     //do a lot of things here.

     System.out.print(actualHealth);
} 

else if (question.startsWith("Who") && question.endsWith("mother?"))
{
     //do a lot of things here.

     System.out.print(getParents().getMother());
} 

*
*
*   //Lot of "else if" here to recognize the question meaning. 
*
*

else
{
     System.out.print("question not recognized");
} 

I called this class AnswersFactory as referred to the Design Pattern "Factory Pattern" because the question, is "asked" in another class. But I suppose it's a wrong way to consider it a design pattern.

How to simplify all those conditions even if they seem impossible to simplify, or at least make the code seem more organized? Is there a good design pattern to follow?

My code works great but is not beautiful to see. I hope you understand that frustration!

Thank you.

Upvotes: 1

Views: 146

Answers (4)

irakli2692
irakli2692

Reputation: 137

you can use Chain Of Responsibility pattern. you will need catching the exception

UnhandledQuestionException

.

public abstract class QuestionHandler {
    protected QuestionHandler successor;

    public void setSuccessor(QuestionHandler successor) {
        this.successor = successor;
    }

    public abstract void handle(String question);
}

and implementors should be so

public class HealthQuestionHandler extends QuestionHandler {

    private bool canHandle(String question) {
        return question.startsWith("How") && question.endsWith("Josh");
    }

    public void handle(String question) {
        if( canHandle(question) ) {
            String healthStatus = "I am fine";

            System.out.println(healthStatus);

        } else {
            super.successor.handle(question);
        }
    }
}

public class MotherQuestionHandler extends QuestionHandler {

    private bool canHandle(String question) {
        return question.startsWith("Who") && question.endsWith("Mother");
    }

    public void handle(String question) {
        if( canHandle(question) ) {
            String mother = "..."; //name

            System.out.println(mother);

        } else {
            super.successor.handle(question);
        }
    }
}

the final handler, when question cannot be handled:

public class UnhandledQuestionHandler extends QuestionHandler {

    public void handle(String question) {
        throw new UnhandledQuestionException("question not recognized");
    }
}

you should create

UnhandledQuestionException

first, that extends Exception class.

you should create QuestionHandlerFactory too.

public class QuestionHandlerFactory {
    public static QuestionHandler create() {
        //if you can have several variants of this handler combinations, this method shouldn't be static

        QuestionHandler healthQuestionHandler = new HealthQuestionHandler();
        QuestionHandler motherQuestionHandler = new MotherQuestionHandler();
        QuestionHandler unhandledQuestionHandler = new UnhandledQuestionHandler()'

        motherQuestionHandler.setSuccessor(unhandledQuestionHandler);
        healthQuestionHandler.setSuccessor(motherQuestionHandler);

        return healthQuestionHandler;
    }
}

and in the user of this class will be:

QuestionHandler handler = QuestionHandlerFactory.create();

try {
    handler.handle(question);
} catch( UnhandledQuestionException ex ) {
    System.out.println(ex.getMessage());
}

Upvotes: 0

Phuong Nguyen
Phuong Nguyen

Reputation: 3080

Not sure why you want to check the question based on the keyword, it has some drawbacks like mentioned by HCBPshenanigans But to change it to be more flexible, I would do something like this:

An interface for all question handlers

public interface IQuestionHandler
{
    bool CanHandle(string question);
    void Handle(string question);
}

Concrete class for each scenario. Each class will tell whether it can handle the question or not, and contain logic to handle the question:

public class HealthQuestionHandler : IQuestionHandler
{
    public bool CanHandle(string question)
    {
        return question.StartsWith("How") && question.EndsWith("Josh?");
    }

    public void Handle(string question)
    {
        //Replace by actual processing
        string healthStatus = "I'm fine";

        Console.WriteLine(healthStatus);
    }
}

public class MotherQuestionHandler : IQuestionHandler
{
    public bool CanHandle(string question)
    {
        return question.StartsWith("Who") && question.EndsWith("mother?");
    }

    public void Handle(string question)
    {
        //Replace by actual processing
        string mother = "...";

        Console.WriteLine(mother);
    }
}

And finally a question handler processor to manage all the handlers. It will register all available handlers in constructor. When called to process, it goes through all of available handlers, ask one by one which one can handle the question

public class QuestionHandlerProcessor
{
    private List<IQuestionHandler> _handlers;

    public QuestionHandlerProcessor()
    {
        //Register available handlers
        _handlers = new List<IQuestionHandler>
        {
            new HealthQuestionHandler(),
            new MotherQuestionHandler()
        };
    }

    public void Process(string question)
    {
        foreach(var handler in _handlers)
        {
            if(handler.CanHandle(question))
            {
                handler.Handle(question);
                return;
            }
        }

        Console.WriteLine("Question not recognized");
    }
}

Usage:

QuestionHandlerProcessor processor = new QuestionHandlerProcessor();
processor.Process("How are you Josh?");
processor.Process("Who is Josh's mother?");

Although my answer is in C#, but should not be difficult to convert to Java.

Upvotes: 1

naveen
naveen

Reputation: 1056

You can use Factory pattern and a strategy pattern. Since Qestion is being asked in a different class (let's call it QueryResolver ) it should look like this :

class QueryProcessor
{
 private IQueryResolver _ resolver;

//We will be injecting our dependencies in the constructor (Dependency Inversion)
public QueryProcessor(IQueryResolver resolver )
{

_resolver = resolver;
}


public string ProcessQuery()
{
_resolver.ResolveQuery();
}

Now your QueryResolver Implements the IQueryResolver interface

public interface IQueryResover
{
string ResolveQuery();
}

And you will have multiple implementation of IQueryResolver each responsible for a particular kind of Query e.g.:

//This particular implementation know how to resolve question including the "Who" key word.
class WhoQueryResolver : IQueryResolver
{
private string _question;
public WhoQueryResolver(string question)
{
 _question = question;
} 

public string ResolveQuery()
{
//do a lot of things here.

     System.out.print(getParents().getMother());

}

Similarly,

class HowQueryResolver : IQueryResolver
{
private string _question;
public HowQueryResolver(string question)
{
 _question = question;
} 

public string ResolveQuery()
{
//do a lot of things here.

     System.out.print(GetActualHealth());

}

than finally a factory which return concrete implementation of IQueryResolver

public class QueryResolverFactory
{
public static IQueryResolver GetQueryResolver()
{
if (question.startsWith("How") && question.endsWith("Josh?"))
{
    return new HowQueryResolver(question);

} 

else if (question.startsWith("Who") && question.endsWith("mother?"))
{
    return new WhoQueryResolver(question);
} 
}
}

Upvotes: 0

Hany Moh.
Hany Moh.

Reputation: 989

create an enum for your Constants such "WHO","HOW", .... and WHERE" then try to use switch after that

you can create enum in the same class

Upvotes: 0

Related Questions