【问题标题】:Android - Dynamic method call (java)Android - 动态方法调用 (java)
【发布时间】:2021-10-22 14:31:27
【问题描述】:

我有这个类,它包含四个私有方法,每个都有相同的两个参数,以及一个在它们之间进行选择的公共方法。 可能的方法存储在 Map 中,并且可以添加更多方法。 我想动态调用正确的方法,删除 switch..case。 有没有礼貌的方法,即没有 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
    
    }
}

【问题讨论】:

  • 一种可能的方法是strategy pattern。为了实现这一点,我们可以 - 创建一个适当的接口 - 例如 - play(...) 方法 - 在单独的处理程序类中提取处理程序方法,实现接口 - 基于 customFunction 选择适当的处理程序类。请注意,该接口将有一些boolean handles(String customFunction)-方法来选择要选择的适当具体实现。
  • “我想动态调用正确的方法,去掉 switch..case”。您还想如何决定调用哪个方法?如果您不想使用反射,则必须有某种 if-else 或 switch-case。或者您创建一个Map<String, BiFunction>,在其中插入key = "CustomPlayFunction1" (string), value = customPlayFunction1 (method)。这本质上只是另一种形式的开关盒。但我怀疑这会让你的代码更容易/更小/更快。

标签: java android methods


【解决方案1】:

你可以使用Enums,如果它们是有限的并且可以使用(取决于上下文,但目前你还没有提供任何信息):

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

否则你必须将责任分离给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

Channel 中,您可以存储一个PlayStrategy 对象,该对象将传递给PlayerClass,它会执行以下操作:

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

最后但最不建议的方法是使用Map<String, BiFunction<Channel, Other, MediaSource>>,如下所示:

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

【讨论】:

    【解决方案2】:

    您可以将Map 与来自java.util.functionBiFunction&lt;Channel, OtherParam, MediaSource&gt; 组合起来。您需要做的就是根据字符串键填充您的地图:

    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 将使用适当的参数调用接收到的函数。

    getOrDefault 将捕获在您的地图中找不到键的任何情况,并自动调用defaultPlayFunction

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-16
      • 2013-05-14
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 2016-01-20
      相关资源
      最近更新 更多