kekk0
kekk0

Reputation: 57

Android - Dynamic method call (java)

I have this class that contains four private methods, with same two arguments each, and a public method which chooses between them. The possible methods are stored in a Map and more may be added. I would like to dynamically call the proper method, removing the switch..case. Is there a polite way to do it, i.e. without getMethod/invoke?

public class PlayerClass {

    private MediaSource customPlayFunction1(Channel chn, OtherParam other) {
        
    }
    
    private MediaSource customPlayFunction2(Channel chn, OtherParam other) {
        
    }
    
    private MediaSource customPlayFunction3(Channel chn, OtherParam other) {
        
    }
    
    private MediaSource defauPlayFunction(Channel chn, OtherParam other) {
        
    }
    
    
    public void playChannel(Activity activity, Channel chn) {

        //do something 

        switch (chn.customFunction) {
            case ("CustomPlayFunction1"): {
                videoSource = customPlayFunction1(chn,other);
                break;
            }
            case ("CustomPlayFunction2"): {
                videoSource = customPlayFunction2(chn,other);
                break;
            }
            case ("CustomPlayFunction3"): {
                videoSource = customPlayFunction3(chn,other);
                break;
            }
            default: {
                videoSource = defaultPlayFunction(chn,other);
                break;
            }
        }
        //do something else
    
    }
}

Upvotes: 1

Views: 455

Answers (2)

Alberto
Alberto

Reputation: 12899

Well you can use Enums if those are finite and makes sense to be used (depends on the context, but for the moment you have not provided any informations):

public enum Channel{
  CUSTOM_1 {
    @Override
    public abstract MediaSource perform(Other other){
      // customPlayFunction1
    }
  }, 
  CUSTOM_2{
    @Override
    public abstract MediaSource perform(Other other){
      // customPlayFunction2
    }
  }, 
  CUSTOM_3{
    @Override
    public abstract MediaSource perform(Other other){
      // customPlayFunction3
    }
  }, 
  DEFAULT{
    @Override
    public abstract MediaSource perform(Other other){
      // defaultPlayFunction
    }
  };
  public abstract MediaSource perform(Other other);
}

Otherwise you have to separate the responsibility to a Strategy:

public interface PlayStrategy{
  public MediaSource perform(Channel chn, Other other);
}
public class Custom1Strategy implements PlayStrategy{
  public MediaSource perform(Channel chn, Other other){
     // customPlayFunction1
  }
}
// same fore 2, 3  and default

and inside Channel you can store a PlayStrategy object that will be passed to the PlayerClass that will do something like:

chn.getPlay().perform(chn, other);

The last but least suggested way, is using a Map<String, BiFunction<Channel, Other, MediaSource>> like this:

public class PlayerClass {
    private BiFunction<Channel, Other, MediaSource>> map = new HashMap<>();
    public PlayerClass(){
        map.put("CustomPlayFunction1", this::customPlayFunction1)
        map.put("CustomPlayFunction2", this::customPlayFunction2)
        map.put("CustomPlayFunction3", this::customPlayFunction3)
    }
    private MediaSource customPlayFunction1(Channel chn, OtherParam other) {}
    private MediaSource customPlayFunction2(Channel chn, OtherParam other) {}
    private MediaSource customPlayFunction3(Channel chn, OtherParam other) {}
    private MediaSource defauPlayFunction(Channel chn, OtherParam other) {}
    public void playChannel(Activity activity, Channel chn) {
        map.getOrDefault(chn.customFunction, this::defauPlayFunction).apply(chn, other);
    }
}

Upvotes: 1

QBrute
QBrute

Reputation: 4536

You could combine a Map with a BiFunction<Channel, OtherParam, MediaSource> from java.util.function. All you need to do is fill your map depending on string key:

private Map<String, BiFunction<Channel, OtherParam, MediaSource>> myMap;

public void setup() {
    myMap = new HashMap<>();
    myMap.put("CustomPlayFunction1", this::customPlayFunction1);
    myMap.put("CustomPlayFunction2", this::customPlayFunction2);
    myMap.put("CustomPlayFunction3", this::customPlayFunction3);
}

public void playChannel(Activity activity, Channel chn) {
    videoSource = myMap.getOrDefault(chn.customFunction, this::defaultPlayFunction).apply(chn, other);
}

apply will call the received function with the appropriate parameters.

The getOrDefault will catch any cases, where a key is not found in your map and automatically calls the defaultPlayFunction.

Upvotes: 1

Related Questions