调用类方法时,如何优雅选择多实例中的对应实例?
如何优雅实现基于参数选择实例调用方法的管理器?
问题背景
假设有一个ClassA类,包含MethodA(int a)、MethodB(int b)等多个方法。我们拥有多个ClassA实例,需要编写一个管理器,根据参数或上下文决定调用哪个实例的对应方法。
现有方案分析
方案一:包装所有方法
class ClassA { public void MethodA(int a) { // 业务代码 } public void MethodB(int a) { // 业务代码 } } class Manager { ClassA evenClassA = new ClassA(); ClassA oddClassA = new ClassA(); public void MethodA(int a) { Choose(a).MethodA(a); } public void MethodB(int a) { Choose(a).MethodB(a); } private ClassA Choose(int a) { return a % 2 == 0 ? evenClassA : oddClassA; } } // 调用处 Manager manager = new Manager(); manager.MethodA(2); manager.MethodB(1);
问题:存在冗余代码,必须在Manager中实现ClassA的所有方法。后续ClassA新增方法时,必须同步修改Manager,维护成本高。
方案二:直接暴露实例选择方法
class Manager { ClassA evenClassA = new ClassA(); ClassA oddClassA = new ClassA(); public ClassA Choose(int a) { // 原代码为private,外部无法调用,此处修正为public return a % 2 == 0 ? evenClassA : oddClassA; } } // 调用处 Manager manager = new Manager(); manager.Choose(2).MethodA(2); manager.Choose(1).MethodB(1);
问题:存在误用风险,Choose方法的参数必须和目标方法的参数一致,一旦写错(比如manager.Choose(1).MethodA(2)),就会导致逻辑错误,且编译器无法提前发现。
优化方案
方案三:基于接口的动态代理(Java)
通过给ClassA定义接口,结合动态代理自动转发方法调用,避免手动包装所有方法:
- 定义
ClassA的接口:
interface IClassA { void MethodA(int a); void MethodB(int a); } class ClassA implements IClassA { @Override public void MethodA(int a) { // 业务代码 } @Override public void MethodB(int a) { // 业务代码 } }
- 实现动态代理的
Manager:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; class Manager implements InvocationHandler { private final ClassA evenClassA = new ClassA(); private final ClassA oddClassA = new ClassA(); public IClassA getProxy() { return (IClassA) Proxy.newProxyInstance( IClassA.class.getClassLoader(), new Class<?>[]{IClassA.class}, this ); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 从方法参数中获取选择实例的依据(此处取第一个int参数) int param = (int) args[0]; ClassA target = param % 2 == 0 ? evenClassA : oddClassA; // 调用目标实例的对应方法 return method.invoke(target, args); } } // 调用处 Manager manager = new Manager(); IClassA proxy = manager.getProxy(); proxy.MethodA(2); // 自动调用evenClassA的MethodA proxy.MethodB(1); // 自动调用oddClassA的MethodB
优势:
- 无需手动包装
ClassA的所有方法,后续IClassA新增方法时,Manager无需修改,自动支持转发。 - 调用方式和直接使用
ClassA一致,避免了方案二的参数误用问题。 - 选择实例的逻辑集中在
invoke方法中,便于统一维护。
方案四:函数式委托(通用思路)
如果不想依赖反射,可以用函数式接口封装方法调用,分离实例选择和方法执行逻辑:
class Manager { private final ClassA evenClassA = new ClassA(); private final ClassA oddClassA = new ClassA(); private ClassA choose(int param) { return param % 2 == 0 ? evenClassA : oddClassA; } // 通用执行方法,接收方法引用和参数 public void execute(int param, java.util.function.Consumer<ClassA> action) { action.accept(choose(param)); } } // 调用处 Manager manager = new Manager(); manager.execute(2, instance -> instance.MethodA(2)); manager.execute(1, instance -> instance.MethodB(1));
优势:
- 无需重复包装方法,新增
ClassA方法时,直接通过Lambda表达式调用即可。 - 选择实例的逻辑由
Manager控制,调用方只需关注执行的方法,降低误用概率。 - 实现简单,无需依赖反射。
内容的提问来源于stack exchange,提问作者Mehran Akhavan
相关产品推荐
相关产品推荐

