2013-01-24 26 views
7

Tôi rất quen thuộc với các ngôn ngữ chức năng như Scheme và Haskell. Tôi đang cố gắng giải quyết một vấn đề trong Java và gặp khó khăn, có thể bởi vì tôi vẫn đang trong tư duy chức năng.Chức năng đa hình bậc cao của Java

Tôi muốn viết:

public void doQueryAndStoreData(String query, <? extends Collection> storeIn) { 
    /* make a jdbc query, get ResultSet */ 
    ResultSet rset = ...; 
    ProcessResultSet proc = new ProcessResultSet(); 
    proc.process(rset, storeIn); 
    /* clean up */ 
} 

với một giao diện như:

private interface IProcessResultSet<C> { 
    public void process(ResultSet rset, C storeIn); 
} 

và một lớp học thực hiện giao diện như:

private class ProcessResultSet implements IProcessResultSet<? extends Collection> { 
    public void process(ResultSet rset, Map storeIn) { 
     /* do something */ 
    } 

    public void process(ResultSet rset, List storeIn) { 
     /* do something else */ 
    } 
} 

để phương pháp đầu tiên có thể gọi thích hợp process dựa trên loại storeIn được cung cấp.

Trong Haskell tôi có thể viết

class Storeable c a where 
    store :: a -> c a -> c a 

doQueryAndStoreData :: Storeable c a => ResultSet a -> c a -> c a 
doQueryAndStoreData (ResultSet rs) coll = foldr store coll rs 

và cung cấp Storeable trường hợp đối với bất cứ bộ sưu tập kiểu tôi muốn để lưu trữ của tôi ResultSet trong.

Đây có phải là cách tiếp cận đúng trong Java? Bởi vì tôi cảm thấy như tôi đang phần nào chiến đấu với langauge để thực hiện điều này.

+1

Tôi nghĩ rằng những gì bạn cần có thể được giải quyết bằng cách sử dụng mẫu khách truy cập - công văn kép. – Scorpion

+0

Cá nhân, tôi sẽ có nhiều khả năng trả lại nội dung nào đó từ một hàm. Có xu hướng làm cho mã dễ đọc hơn. Không thể nghĩ siêu mẫu gần nhất với Bản đồ và Danh sách, nhưng đó sẽ là giá trị trả lại và sau đó truyền tới Bản đồ/Danh sách trong câu lệnh gán, tức là 'Bản đồ myMap = Bản đồ mới ; myMap = (Bản đồ ) quy trình (rset, myMap); " – anthropomo

Trả lời

2

Không, Java không làm thế.

Bạn sẽ cần phải làm một cái gì đó như:

public <T> void doQueryAndStoreData(
    String query, 
    T storeIn, 
    ResultSetProcessor<T> processor 
) { 

Hoặc nhiều khả năng:

public void doQueryAndStoreData(
    String query, 
    ResultSetHandler handler // may contain processor and storeIn 
) { 

Tôi hy vọng tôi không cần phải đề cập đến lỗ hổng SQL injection là một điều xấu. (Ngoài ra Map không phải là Collection bằng Java (trong C# nhưng C# Collection không phải là rất hữu ích).)

2

Rất tiếc, bạn không thể làm điều đó. Trình biên dịch phải biết tại thời gian biên dịch phương thức nào cuộc gọi này bị ràng buộc. Nếu bạn muốn để quyết định phương pháp để gọi dựa trên loại runtime của đối tượng, bạn phải tự kiểm tra xem nó:

Các nhất mà bạn có thể làm:

private class ProcessResultSet implements IProcessResultSet<? extends Collection> { 

    @Override 
    public void process(ResultSet rset, Collection storeIn) { 
     if (storeIn instanceof Set) { 
      return processSet(rset, (Set) storeIn); 
     } else if (storeIn instanceof List) { 
      return processList(rset, (List) storeIn); 
     } else { 
      throw new IllegalArgumentException("Unimplemented storage type"); 
     } 
    } 


    public void processSet(ResultSet rset, Set storeIn) { 
     /* do something */ 
    } 

    public void processList(ResultSet rset, List storeIn) { 
     /* do something else */ 
    } 
} 
0
private class ProcessResultSet implements IProcessResultSet<? extends Collection> { 

    public void process(ResultSet rset, Object storeIn) 
    { 
     if (storeIn instanceof Map) 
      processMap(rset,(Map) storeIn); 
     else if (storeIn instanceof List) 
      processList(rset,(List) storeIn); 
     else 
      System.out.println("Unsupported input type."); 
    } 

    public void processMap(ResultSet rset, Map storeIn) { 
     /* do something */ 
    } 

    public void processList(ResultSet rset, List storeIn) { 
     /* do something else */ 
    } 
} 
+0

Tôi trễ 1 phút ... –

Các vấn đề liên quan