marclee44 / me

1 stars 0 forks source link

替代switch/case之Android篇 #14

Open marclee44 opened 3 years ago

marclee44 commented 3 years ago

替代switch/case之C#篇说完了,来看Android。 switch/case的方式实在和C#很像,不说了,就说替代方式。

字典+代理(泛型接口)

Android没有像C#这样的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文件。。。) 于是,我掉坑里了!

缝缝补补完

        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的运行时类型,这条路似乎被堵死了……

soapgu commented 3 years ago
public interface IAction<T> {
    void invoke(T o);
}

IAction可以直接改androidx.core.util.Consumer,更通用少一个自定义类

第二个例子可以用匿名类