1

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
    
    }
}
2
  • One possible approach would be the strategy pattern. To implement this, we could - create an appropriate interface whit - for example - a play(...) method - extract the handler-methods in separate handler-classes, implementing the interface - select the appropiate hander class, based on the customFunction. Notice that the interface would have some boolean handles(String customFunction)-method to select the appropiate concrete implementation to select. Commented Aug 21, 2021 at 10:47
  • "I would like to dynamically call the proper method, removing the switch..case". How else you want to decide which method to call? There must be some kind of if-else or switch-case if you don't want to use reflection. Or you create a Map<String, BiFunction> where you insert key = "CustomPlayFunction1" (string), value = customPlayFunction1 (method). Which is essentially just another form of switch-case. But I doubt that this will make your code easier / smaller / faster. Commented Aug 21, 2021 at 10:48

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.