如何将接口方法传递给Java中的函数?

时间:2013-06-27 02:21:34

标签: 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();
}

4 个答案:

答案 0 :(得分:2)

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);
  });

答案 1 :(得分:1)

因为函数不是Java中的对象(至少现在还没有),所以你不能以一种简单的方式做你想做的事。

如果您不介意丢弃返回值(就像您使用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);

答案 2 :(得分:1)

嗯,这就是在给定具体实例的情况下,可以使用反射来调用任一方法:

    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来说是一个很好的用例。

答案 3 :(得分:1)

我认为需要一个mapper工厂,并且还需要修改mapper接口。

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);
    }
}