繁体   English   中英

如何在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>);

    ...
}

然后就是它可以调用任何methodOnemethodTwo作为另一个类中的参数?

public class Other {
    public void doSomething(HashMap<String, Object> params, ????) {
        Mapper mapper = new ConcreteMapper();
        mapper.methodOne(params);
    }
}

我尝试了Java反射,但是在编译时无法获取HashMap<String, Object>的类型。 我想知道是否有解决此问题的方法?
动力来自我在工作场所遇到的一个实际问题。 例如,每个REST方法调用唯一不同的是getAddressPhoneAddressPhoneType 诸如打开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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM