![](/img/trans.png)
[英]How to pass an implementation of an interface as a variable in a method in Java?
[英]How to pass an interface method to a function in Java?
我有以下界面:
public interface Mapper {
public SomeType methodOne(HashMap<String, Object>);
public OtherType methodTwo(HashMap<String, Object>);
...
}
然后就是它可以调用任何methodOne
或methodTwo
作为另一个类中的参数?
public class Other {
public void doSomething(HashMap<String, Object> params, ????) {
Mapper mapper = new ConcreteMapper();
mapper.methodOne(params);
}
}
我尝试了Java反射,但是在编译时无法获取HashMap<String, Object>
的类型。 我想知道是否有解决此问题的方法?
动力来自我在工作场所遇到的一个实际问题。 例如,每个REST
方法调用唯一不同的是getAddressPhone
和AddressPhoneType
。 诸如打开SQL会话,实例化Mapper
类的嘈杂步骤本质上是相同的。
public Response getAddressPhone(@PathParam("acc_nbr") String accNbr, @HeaderParam("AuthToken") String authToken) {
SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
Logger log = LoggerFactory.getLoggerFactory();
AddressPhoneType addressPhone = null;
try {
MyAccountMapper mapper = session.getMapper(MyAccountMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("acc_nbr", accNbr);
addressPhone = mapper.getAddressPhone(map);
if (addressPhone == null) {
return Response.ok(null).status(Status.NOT_FOUND).build();
}
} catch (Exception e) {
log.debug("getAddressPhone(map):" + e.getMessage());
return Response.ok().status(Status.BAD_REQUEST).build();
} finally {
session.close();
}
return Response.ok(gson.toJson(addressPhone)).header("AuthToken", authToken).status(Status.OK).build();
}
编辑我正在使用MyBatis映射器执行MySql查询,所以我有以下称为MyAccountMapper
接口。 由于这些方法中的每一个都在SQL查询中使用ID进行映射,因此没有针对它们的定义:
public interface MyAccountMapper {
AddressPhoneType getAddressPhone(HashMap<String, Object> map);
AdminUserInfoType getAdminUserInfo(HashMap<String, Object> map);
DueDateInfoType getDueDateInfo(HashMap<String, Object> map);
....
}
现在,在所有Web服务调用中(我使用的是JAX-RS),我都需要调用这些方法来对数据库进行处理,从上例中可以看到,大多数工作如设置映射器,创建记录器是相同的。 唯一的不同是方法调用和返回类型。
@GET
@Path("/admin/user/info/{acc_nbr}")
@Produces("application/json")
public Response getAdminUserInfo(@PathParam("acc_nbr") String accNbr) {
SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
AdminUserInfoType adminUserInfoType = null;
Logger log = LoggerFactory.getLoggerFactory();
try {
MyAccountMapper mapper = session.getMapper(MyAccountMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("acc_nbr", accNbr);
adminUserInfoType = mapper.getAdminUserInfo(map);
if (adminUserInfoType == null) {
return Response.ok(gson.toJson(null)).status(Status.NOT_FOUND).build();
}
} catch (Exception e) {
log.debug("getAdminUserInfo(map):" + e.getMessage());
return Response.ok("getAdminUserInfo(map):"+ MyBatisErrorMessage.SELECT_ERROR).status(Status.BAD_REQUEST).build();
} finally {
session.close();
}
return Response.ok(gson.toJson(adminUserInfoType)).status(Status.OK).build();
}
@GET
@Path(value = "/address/phone/{acc_nbr}")
@Produces(MediaType.APPLICATION_JSON)
public Response getAddressPhone(@PathParam("acc_nbr") String accNbr,
@HeaderParam("AuthToken") String authToken) {
SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
Logger log = LoggerFactory.getLoggerFactory();
AddressPhoneType addressPhone = null;
try {
MyAccountMapper mapper = session.getMapper(MyAccountMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("acc_nbr", accNbr);
addressPhone = mapper.getAddressPhone(map);
if (addressPhone == null) {
return Response.ok(null).status(Status.NOT_FOUND).build();
}
} catch (Exception e) {
log.debug("getAddressPhone(map):" + e.getMessage());
return Response.ok("getAddressPhone(map):"+ MyBatisErrorMessage.SELECT_ERROR).status(Status.BAD_REQUEST).build();
} finally {
session.close();
}
return Response.ok(gson.toJson(addressPhone)).header("AuthToken", authToken).status(Status.OK).build();
}
public interface Method {
public Object invoke(Map<> params);
}
public void invokeTheMethod(Map<> params, Method method) {
// ... do common work here ...
Object result = method.invoke(params);
// ... handle result here ...
}
// run common invoker with Mapper.methodOne
invokeTheMethod(params, new Method() {
public Object invoke(Map<> params) {
return mapper.methodOne(params);
});
由于函数不是Java中的对象(至少现在还不是),因此您无法以简单的方式完成所需的操作。
如果您不介意抛弃返回值(就像您对Other.doSomething
所做的Other.doSomething
),那么接口和几个实现可以完成此工作。 实现可以是单例。
interface MethodCaller {
void callMethod(HashMap<String, Object> args, Mapper mapper);
MethodCaller methodOneCaller = new MethodCaller() {
@Override
public void callMethod(HashMap<String, Object> args, Mapper mapper) {
mapper.methodOne(args);
}
}
MethodCaller methodTwoCaller = new MethodCaller() {
@Override
public void callMethod(HashMap<String, Object> args, Mapper mapper) {
mapper.methodTwo(args);
}
}
}
然后,您可以将呼叫者之一传递给想要使用它们的任何人:
public class Other {
public void doSomething(HashMap<String, Object> params, MethodCaller caller) {
Mapper mapper = new ConcreteMapper();
caller.callMethod(params, mapper);
}
}
Other other = . . .;
HashMap<String, Object> stuff = . . .;
other.doSomething(stuff, MethodCaller.methodOneCaller);
other.doSomething(stuff, MethodCaller.methodTwoCaller);
嗯,给定一个具体实例,这就是使用反射调用任何一种方法的方式:
Mapper concreteMapper = new ConcreteMapper();
Method method1 = concreteMapper.getClass().getMethod("methodOne", HashMap.class);
Method method2 = concreteMapper.getClass().getMethod("methodTwo", HashMap.class);
method1.invoke(concreteMapper, new HashMap<String, Object>());
method2.invoke(concreteMapper, new HashMap<String, Object>());
但是,如果您只是想避免样板代码,请考虑使用类似命令模式的内容。 或者,如果您使用spring,这将是其AOP的一个好用例。
我认为需要一个映射器工厂,并且还需要修改映射器接口。
public interface Mapper {
public SomeType method(HashMap<String, Object> map);
}
public class MapperFactory {
public static Mapper createMapper(some parameters here) {
// create a mapper according to the parameters.
}
}
// usage within another class
public class Other {
public void doSomething(HashMap<String, Object> params, ????) {
Mapper mapper = new MapperFactory.createMapper(......);
mapper.method(params);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.