2013-06-27 46 views
0

我有以下接口:如何將接口方法傳遞給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); 
    .... 
} 
在我所有的網絡服務調用(我使用的JAX-RS),我需要調用這些

現在方法來處理我的數據庫,你可以從上面的例子中看到,大部分的東西,比如設置mapper,創建記錄器都是一樣的。唯一不同的是方法調用和返回類型。

@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(); 
} 
+0

看起來像是可以在Java 8中完成的東西。但是,爲什麼不通過一個可以調用這些方法的'Mapper'呢? – arshajii

+0

'methodOne'和'methodTwo'的返回類型不同時有點困難。但是你的'Other.doSomething'方法似乎正在拋棄返回值。 –

+0

這可從Java 8中獲得。現在,您需要傳遞一個'interface'作爲其他參數,並在此接口中定義一個方法來完成您想要的任務。 –

回答

1

因爲功能在爪哇(至少目前還沒有)的對象,你不能做你以簡單的方式想要什麼。

如果您不介意丟棄返回值(例如您正在使用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); 
+0

非常好的例子!謝謝。 – Chan

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

那麼,這是一個能怎麼樣,調用任何一種方法,使用反射給出一個具體的實例:

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

但如果你只是想避免鍋爐板代碼,可以考慮使用類似的指令PA ttern。或者,如果你使用spring,這將是它的AOP的一個很好的用例。

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); 
    } 
} 
相關問題