Select method based on field in class

空扰寡人 提交于 2019-12-13 14:05:03

问题


So I have a class that contains a String-field:

public class A {
    private String type = ...
    public String getType(){
        return this.type;
    }
    public void setType(String type){
        this.type = type;
    }
}

I also have a list of all possible types, there are twelve and possibly more in the future.

Now I want to write a method that gets an object of class A and calls a specific method depending on which "type" is in the class. Is there a smarter solution than writing 12 (or more) if-statements?
Normally I would use the Visitor-pattern but I don't want to create twelve new classes.

edit:
I ended up creating a

Map<String,Function<A,String>> map = new HashMap<String,Function<A,String>>

and then call

A a;
...
map.get(a.getType).apply(a);

回答1:


Instead of storing type as a "free-form" text value, you should be using an enum, since you have a well-defined list of values.

You can even have the different enums implement the same method differently, by using an abstract method. This will allow you to totally eliminate the error-prone switch statements.

Below is an example showing both instance values and abstract methods. The pattern shown will keep the implementation out of the enum, while having the compiler catch all uses when a new enum is added.

public enum Type {
    INTEGER("Integer") {
        @Override
        public void apply(Action action, A a) {
            action.applyInteger(a);
        }
    },
    STRING ("Text") {
        @Override
        public void apply(Action action, A a) {
            action.applyString(a);
        }
    };

    private String displayName;

    private Type(String displayName) {
        this.displayName = displayName;
    }

    public String getDisplayName() {
        return this.displayName;
    }

    public abstract void apply(Action action, A a);

}

public interface Action {

    public void applyInteger(A a);
    public void applyString(A a);

}

public class A {
    private Type type;
    public Type getType(){
        return this.type;
    }
    public void setType(Type type){
        this.type = type;
    }
    public void apply(Action action) {
        this.type.apply(action, this);
    }
}

When you add a new type to the TYPE enum, you also add a new method to the Action interface, which will force you to implement that method in all implementations of the interface. With switch statements, you'd get no such safety.




回答2:


If you are using JDK 7 or greater go for a switch which accepts String as a parameter and write cases for each.

  switch (type) {
         case "SomeX":
             yourInstance.invokeMethod();
             break;
         case "SomeY":
         ...



回答3:


I guess the other answers are correct but, by reading the question I think the more direct answer will be using introspection and convention:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
    public static class A {
        private String type;
        public String getType(){
            return this.type;
        }
        public void setType(String type){
            this.type = type;
        }
    }

    public static class Actions {

        public void runForType1(A a) {
            System.out.println("It's type 1");
        }

        public void runForType2(A a) {
            System.out.println("It's type 2");
        }

        public void runForType3(A a) {
            System.out.println("It's type 3");
        }
    }

    public static class Runner {
        Actions actions;
        public Runner(Actions a) {
            this.actions = a;
        }

        public void run(A a) {
            try {
                Method m = actions.getClass().getMethod("runFor" + a.getType(), A.class);
                m.invoke(actions, a);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Runner r = new Runner(new Actions());

        A type1 = new A();
        type1.setType("Type1");
        A type2 = new A();
        type2.setType("Type2");
        A type3 = new A();
        type3.setType("Type3");

        r.run(type1);
        r.run(type2);
        r.run(type3);
    }
}

expected output for the example will be:

It's type 1
It's type 2
It's type 3

If convention is not possible you can always create a HashMap with a type to method name mapping.



来源:https://stackoverflow.com/questions/32158288/select-method-based-on-field-in-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!