0

我有以下界面:

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

HashMap<String, Object>我尝试了 java 反射,但在编译时无法获得类型。我想知道有没有办法解决这个问题?
动力来自我在工作场所遇到的一个实际问题。例如,每个REST方法调用的唯一不同之处是getAddressPhoneand 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();
}
4

4 回答 4

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);
  });
于 2013-06-27T02:34:11.263 回答
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);
于 2013-06-27T02:34:09.703 回答
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 的一个很好的用例。

于 2013-06-27T02:34:24.870 回答
1

我认为需要一个映射器工厂,映射器接口也需要修改。

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);
    }
}
于 2013-06-27T02:36:46.793 回答