Modulation of adding new Strings -> Method calls

815 views Asked by At

If I have a program that does the following:

if(input=='abc'){do x}
if(input=='def'){do y}

In the future, I may want to add another piece of code like so:

if(input=='ghy'){do x}

As you can see, I am adding a new 'if' statement for a different conditional BUT using the SAME function X. The code in future has potential to have lots of different IF statements (or switches) all of which are comparing a string vs a string and then performing a function. Considering the future expansion, I was wondering if there is a possible 'neater', 'modular' way of achieving the same results.

It's a shame I can't combine the String with a Method call in a hashtable (String, method) in Java. That way I could just store any new procedures inside a hashtable and grab the relevant method for that String.

Any ideas?

Thank you

EDIT: Thank you for everyone's solutions. I was surprised by the quantity and quality of replies I received in such a small amount of time.

4

There are 4 answers

4
johusman On

I guess you could always use a Map<String, Runnable> and map to anonymous Runnable implementations:

myMap.put("abc", new Runnable() { public void run() { do x } });

...

myMap.get(input).run();
5
Lachezar Balev On

Maybe you can use enum. Example:

public enum InputType
{

    abc, def
    {
        @Override
        public void x()
        {
            System.out.println("Another method");
        }
    },
    ghy;

    public void x()
    {
        System.out.println("One method");
    }
}

And further:

InputType.valueOf("abc").x();

Cheers!

0
lukastymo On

A lot of ifs always tell us that we could do this better. In your case better option is to use design pattern e.g. Chain of responsibility. You will have good implementation which you can dynamic change and your code will be easier to maintenance than ifs implementation.

Take a look at this adaptation chain of responsibility to your case:

Main:

public static void main(String[] args) {
    ClassA classA = new ClassA(Arrays.asList("abc", "ghi"));
    ClassB classB = new ClassB(Arrays.asList("def"));
    classA.setNextInChain(classB);  // you can always write Builder to do this
    String input = "def";
    classA.execute(input);
}

BaseClass:

public abstract class BaseClass {
    private Collection<String> patterns = Collections.EMPTY_LIST;
    protected BaseClass nextInChain;
    protected abstract void doMethod();  // your doA, doB methods

    public void execute(String input) {
            // this replace many ifs in your previous implementation
        if (patterns.contains(input)) {
            doMethod();
        } else {
            nextInChain.execute(input);
        }       
    }

    public void setPatterns(Collection<String> patterns) {
        this.patterns = patterns;
    }

    public void setNextInChain(BaseClass nextInChain) {
        this.nextInChain = nextInChain;
    }
}

Class in chain:

public class ClassA extends BaseClass {
    ClassA(Collection<String> patterns) {
        setPatterns(patterns);
    }
    @Override
    protected void doMethod() {
        // do A     
    }
}

public class ClassB extends BaseClass {...}
4
svachon On

You should take a look at the command pattern. There are several ways of implementing it, and frameworks such as Spring can help you do with in a clean way.

But in a simple manner here's what you could do:

1-Create a Command interface with a method that your program will have to call to do the task, say doTask()

2-Create classes for command X and Y, implementing the Command interface.

3-Create a Map<String, Command> that will map your commands (X and Y) to logical names

4-Create a configuration file of your choice, say a .properties file that will map your input to your command names: abc=X, def=Y, ghi=X

5-Your program then does lookups on the config file to know which command to run according to the input.