2017-05-03 54 views
1

我有一個關於如何通過接口實例化時調用對象基礎成員的問題。Java鑄造接口,但使用對象方法

假設我有一個框架下面的接口和具體類我試圖建立:

public interface UsedClass { 
    public boolean getBool(); 
} 

public class User implements UsedClass { 

    private String userName; 
    private String userRole; 
    public User(String userName, String userRole){ 
     this.userName = userName; 
     this.userRole = userRole; 
    } 
    public boolean getBool() { 
     // some code 
    } 
    public int getUserName() { 
     return userName; 
    } 
    public int getUserRole() { 
     return userRole; 
    } 

而實現類:

public class Run implements UsedClass {   
    private String runName; 
    private int runNumber; 
    public Run(String runName, int runNumber){ 
     this.runName = runName; 
     this.runNumber = runNumber; 
    } 
    public boolean getBool() { 
     // some code 
    } 
    public String getRunName() { 
     return runName; 
    } 
    public int getRunNumber() { 
     return runNumber; 
    } 
} 

但我不能把方法getRunName()getUserRole()成界面!

最終目標是創建一個FactoryClass來處理從數據庫GUI傳遞的對象。

我想知道是否有更好的方法,然後使用類的引用可以安全地調用運行的方法或用戶,如:

public class EntityFactory { 
    public static Object getValueAt(int rowIndex, int columnIndex, UsedClass usedClass) { 
     if (usedClass.getClass().getSimpleName().equals("User")) { 

      switch (columnIndex) { 
      case 0: 
       return ((User) usedClass).getUserName(); 
      case 1: 
       return ((User) usedClass).getUserRole(); 
      default: 
       return null; 
      } 
     } else if (usedClass.getClass().getSimpleName().equals("Run")) { 
      switch (columnIndex) { 
      case 0: 
       return ((Run) usedClass).getRunName(); 
      case 1: 
       return ((Run) usedClass).getRunNumber(); 
      default: 
       return null; 
    } 
} 

我已看過一些SO帖子 type casting when objects are of interface references in JavaJava cast interface to class

暗示不建議使用引用轉換,但由於我無法將所有方法都放入界面中,會有什麼建議?

+0

至少使用'usedClass instanceof User'而不是'usedClass.getClass()。getSimpleName()。equals(「User」)''。 – Jesper

+0

也許你可以在接口中添加一些'getValueAt(int columnIndex)'方法並在子類中實現它? – Berger

+0

Jesper:謝謝。 Berger:但是更多的OOP在一個類中擁有這個getValueAt。至少這是我的想法。 – mkunkel

回答

1
static interface ColumnSource<T> { 
    String getColumn(T value, int index); 
} 
static Map<Class, ColumnSource> map = new HashMap(); 
static { 
    map.put(User.class, new UserNameAndRoleSource<User>() { 
     public String getColumn(User user, int index) { 
      switch (index) { 
       case 0: return user.getUserName(); 
       case 1: return user.getUserRole(); 
       default: throw new RuntimeException(); 
      } 
     } 
    }); 
    map.put(Run.class, new ColumnSource<Run>() { 
     public String getColumn(Run run, int index) { 
      switch (index) { 
       case 0: return run.getRunName(); 
       case 1: return run.getRunNumer(); 
       default: throw new RuntimeException(); 
      } 
     } 
    }); 
} 
public static Object getValueAt(int rowIndex, int columnIndex, Object o) { 
    Class type = o.getClass(); 
    ColumnSource source = map.get(type); 
    if (source == null) throw new RuntimeException(type.getName() + " not supported"); 
    return source.getColumn(o, columnIndex); 
} 
+0

這並不能解決問題,因爲接口將實現Run或User不使用的方法。例如,Run沒有方法getUserRole()。 – mkunkel

+0

更新爲'ColumnSource.getColumn(T值,int index)' –

+0

這很好,但也有一個問題,有些方法返回一個字符串和一些int。因此,即使向不同的返回類型的接口添加另一個方法,getValueAt方法也會返回一些異常,因爲User中沒有輸入,但有一些輸入在Run中。 – mkunkel

1

您應該使用instanceof而不是查看該類的simpleName

除此之外,你是正確的。您需要有一個包含常用方法的接口,然後您可以調用它們,或者需要確定該對象是特定類的實例,然後執行強制轉換並進行方法調用。

你可以考慮使用一個Map<Class<? extends UsedClass>, Map<Integer, Function<___>>>處理程序。

那麼你的處理將是

handlers.get(usedClass.getClass()).get(columnIndex).apply(usedClass); 

很明顯,你將需要考慮如何處理意外的類/索引的情況。內部Map<Integer,...可能會是List<...>,具體取決於它如何使用。

+0

我認爲這個地圖是一個好主意,但是我很難概念化這個。一旦我開始瞭解它,我可能會將其標記爲可以接受的答案。 – mkunkel

1

兩件事情:

  • 如果有的話,您使用的instanceof,而不是字符串/類名稱比較
  • 你建立你的接口/類是有益。他們是你正在做的所有事情的基地。如果你從抽象破碎開始,你就會破碎。就那麼簡單。

我的意思是:如果有「共同」行爲;那麼你應該使用通用接口來表達。如果不是的話,你開始在一個已經破碎的基礎上努力;並且您需要在整個地方創建「創意解決方案」以對抗該疾病的症狀。

也許一個小的解決方案可能是至少有多個接口,像

interface UsedClass { ... 

interface SpecialUsedClassA extends UsedClass { ... 

interface SpecialUsedClassB extends UsedClass { ... 

比你至少可以回UsedClass而不是對象。

+0

該項目的常見行爲是在一個界面中。但是,我試圖提取所有實現UsedClass的類的所有getter的非常見行爲,如run.getRunName()和user.getUserRole ...等。如果實施數量很少,則您的解決方法是「富有創造性」和實用的。但是,對於我的項目,我實際上有23個實際上是持久性實體的類。因此,我覺得擁有23個「特殊」界面對於這個領域的新手來說是非常乏味和困惑的。 – mkunkel

+0

我明白了。仍然是一個很好的有趣的問題。無論如何;有什麼我可以做的,使我的答案在你眼中至少值得讚賞嗎? (並且不,我現在沒有一個關於接近23個接口的好主意)。 – GhostCat