Open marclee44 opened 3 years ago
替代switch/case之C#篇说完了,来看Android。 switch/case的方式实在和C#很像,不说了,就说替代方式。
switch/case
字典+代理(泛型接口)
Android没有像C#这样的Action/Delegate类,但代理模式还是类似的,只不过要自己定义一个泛型接口:
Action/Delegate
public interface IAction<T> { void invoke(T o); }
而调用实现方式就很像C#了:
... protected void onCreate(Bundle savedInstanceState) { ... Map<String, IAction<Employee>> actionMap = new HashMap<String, IAction<Employee>>() {{ put("A", e -> LevelUp(e)); put("B", e -> Raise(e)); put("C", e -> NothingHappened(e)); put("D", e -> PayCut(e)); put("E", e -> Fired(e)); }}; List<Employee> employees = GetEmployees(); employees.forEach(employee -> { String evaluation = employee.getEvaluation(); if (actionMap.containsKey(evaluation)) { Objects.requireNonNull(actionMap.get(evaluation)).invoke(employee); } }); } private void LevelUp(Employee employee) { Log.i(TAG, String.format("%s level up", employee.getName())); } private void Raise(Employee employee) { Log.i(TAG, String.format("%s got a raise", employee.getName())); } private void NothingHappened(Employee employee) { Log.i(TAG, String.format("%s nothing happened", employee.getName())); } private void PayCut(Employee employee) { Log.i(TAG, String.format("%s got a pay cut", employee.getName())); } private void Fired(Employee employee) { Log.i(TAG, String.format("%s is fired", employee.getName())); }
可以看到,除了语法不同,其他还真差不多。
继承接口/基类+反射
这里看上去也就只是反射的调用方式不同罢了
public interface IPay { void DoAction(Employee employee); }
protected void onCreate(Bundle savedInstanceState) { ... List<Employee> employees = GetEmployees(); employees.forEach(employee -> { try { String classname = String.format("%s.%s", this.getClass().getName(), employee.getEvaluation()); //完整类名 Class<?> objClass = Class.forName(classname); Object obj = objClass.newInstance(); //获得实例 Method getAction = objClass.getMethod("DoAction", Employee.class); //获得公有方法 getAction.setAccessible(true); //调用方法前,设置访问标志 getAction.invoke(obj, employee); //调用方法 } catch (Exception e) { e.printStackTrace(); } }); } class A implements IPay { public void DoAction(Employee employee) { Log.i(TAG, String.format("%s level up", employee.getName())); } } class B implements IPay { public void DoAction(Employee employee) { Log.i(TAG, String.format("%s got a raise", employee.getName())); } } class C implements IPay { public void DoAction(Employee employee) { Log.i(TAG, String.format("%s nothing happened", employee.getName())); } } class D implements IPay { public void DoAction(Employee employee) { Log.i(TAG, String.format("%s got a pay cut", employee.getName())); } } class E implements IPay { public void DoAction(Employee employee) { Log.i(TAG, String.format("%s is fired", employee.getName())); } }
Demo嘛,为了图方便,我将所有IPay的派生类都作为内部类写在了MainActivity内(就为了少创建几个java文件。。。) 于是,我掉坑里了!
IPay
Class.forName()
ClassNotFound
objClass.newInstance();
java.lang.InstantiationException: java.lang.Class<....MainActivity$A> has no zero argument constructor
缝缝补补完
employees.forEach(employee -> { try { String classname = String.format("%s$%s", this.getClass().getName(), employee.getEvaluation()); //完整类名 Class<?> objClass = Class.forName(classname); Object obj = objClass.getDeclaredConstructors()[0].newInstance(this); //获得构造函数后,传入当前类实例获得实例 Method getAction = objClass.getMethod("DoAction", Employee.class); //获得公有方法 getAction.setAccessible(true); //调用方法前,设置访问标志 getAction.invoke(obj, employee); //调用方法 } catch (Exception e) { e.printStackTrace(); } });
终于还是完成了
继承接口/基类+重载方法
很抱歉,由于没在Android找到类似C#dynamic的运行时类型,这条路似乎被堵死了……
dynamic
IAction可以直接改androidx.core.util.Consumer,更通用少一个自定义类
第二个例子可以用匿名类
替代switch/case之C#篇说完了,来看Android。
switch/case
的方式实在和C#很像,不说了,就说替代方式。Android没有像C#这样的
Action/Delegate
类,但代理模式还是类似的,只不过要自己定义一个泛型接口:而调用实现方式就很像C#了:
可以看到,除了语法不同,其他还真差不多。
这里看上去也就只是反射的调用方式不同罢了
Demo嘛,为了图方便,我将所有
IPay
的派生类都作为内部类写在了MainActivity内(就为了少创建几个java文件。。。) 于是,我掉坑里了!Class.forName()
报ClassNotFound
??? 包名.类名.内部类名,没错啊? 自己找了个内部类,输出他的ClassName…… 好吧,C#写多了,想当然了。 内部类的命名规则是 包名.类名$内部类名objClass.newInstance();
报java.lang.InstantiationException: java.lang.Class<....MainActivity$A> has no zero argument constructor
??? 没写构造函数,不就是默认有0参的构造函数么? 我加上还不行么? 还给这个异常? 再去一查。。。又是内部类的锅! 内部类的反射创建实例的方式,先要去获取其构造函数,再将当前类的实例作为参数传给newInstance()才行缝缝补补完
终于还是完成了
很抱歉,由于没在Android找到类似C#
dynamic
的运行时类型,这条路似乎被堵死了……