2013-06-21 63 views
2

我已經我有四種類型的數據對象的情況下:實例化特定亞型

class DataTypeAlpha extends DataType 
class DataTypeBeta extends DataType 
class DataTypeGamma extends DataType 
class DataTypeDelta extends DataType 

和來自GUI框架四種不同的樹節點的類型,每一個特定的數據類型包裹:

class AlphaTreeNode extends MyAppTreeNode 
... 

現在我經常有模式,我有一個DataType的實例,需要一個MyAppTreeNode的新實例。我看到兩個解決方案。解決方法一:

class DataType { 
    // Instantiates and returns the appropriate MyAppTreeNode for this DataType 
    abstract MyAppTreeNode createTreeNode(); 
} 

解決方法二:

class MyAppTreeNode { 
    static MyAppTreeNode createTreeNodeForDataType(DataType dataType) { 
    if(dataType instanceOf DataTypeAlpha) return new AlphaTreeNode((DataTypeAlpha)dataType) 
    else if (dataType instanceOf DataTypeBety) return new BetaTreeNode((DataTypeBeta)dataType) 
    else if ... 
    else if ... 
    else throw new IllegalArgumentException(); 
    } 
} 

解決一個使用多態性,是更短和更 「優雅」。但我更喜歡DataType類沒有關於我使用的GUI框架的知識。也許我甚至可以使用兩種不同的GUI框架?

您是否看到第三種解決方案?我爲這個問題添加了Guice標籤。也許在Guice或其他依賴注入庫中有一些功能可以在這裏幫助?

翻翻類似的問題:

  • 當然,我會用這個工廠模式,但在工廠裏面我還是留下的問題。
+0

如何使用泛型和類似的溶劑像通用道? http://insidecoding.com/2011/09/07/the-generic-dao-pattern-in-java-with-spring-3-and-jpa-2-0/ –

回答

1

你可能會使用訪問者啓發式的方法。像往常一樣,所有的DataType對象都有一個accept方法,但與普通的訪問者模式不同,它不會遍歷子元素,它會返回一個值。爲了避免太多的混淆,讓我們將呼叫對象傳遞給accept,代替operator而不是visitor。訣竅是使acceptoperators返回一個泛型類型。

因此,代碼會是這樣的數據模型

public abstract class DataType { 
    public abstract <T> T accept(Operator<T> op); 
} 

public interface Operator<T> { 
    T operateAlpha(DataTypeAlpha data); 
    T operateBeta(DataTypeBeta data); 
    ... 
} 

public class DataTypeAlpha extends DataType { 
    public <T> T accept(Operator<T> op) { 
    return op.operateAlpha(this); 
    } 
} 
.... 

,並在GUI中,你將有

public class TreeNodeFactory implements Operator<MyAppTreeNode> { 
    public MyAppTreeNode operateAlpha(DataTypeAlpha data) { 
     return new AlphaTreeNode(data); 
    } 
    ... 
} 

public class MyAppTreeNode { 
    static TreeNodeFactory factory = ...; 
    static MyAppTreeNode createTreeNodeForDataType(DataType dataType) { 
    return dataType.accept(factory); 
    }  
} 
+0

我喜歡這個。它優雅,類型安全,簡短,我可以用它來處理DataType的幾件事情。我仍然對替代解決方案感到好奇。 –

+0

謝謝。一旦你的好奇心得到滿足,記得接受你最喜歡的;) – Tobber

0

所以短期,簡單的答案是,一個構造函數只能返回它自己的類型。沒有子類型,沒有其他類,沒有重用實例,沒有null - 只是該類型的新實例。所以你正在尋找一個解決方案,在這裏構造函數的範圍之外運行。最簡單也是最常用的解決方法是編寫一個靜態工廠方法(通常名爲newInstancegetInstance),該方法返回封閉類的任何新的或現有的實例,並且可以毫無問題地返回子類或子類或null

您的解決方案1和2的觀點是有效的。避免讓數據類型知道UI是很好的,在你的情況下(只有四種類型),我可能會選擇你的解決方案2.如果你的操作在這些類型中會有所不同 - 這是在圖形用戶界面中將相似類型混合到一個樹中的相當常見的需求 - 比特努斯的解決方案可能是值得的。 (如果你只需要做一次這樣的事情,那麼需要處理很多代碼。)

如果你有點期待你的類型,數量增長,但你的操作永遠長不大,一個替代方案是提取多態創建到一個單獨的工廠,這可能是這樣的:

class MyAppTreeNode { 
    interface Factory { 
    MyAppTreeNode create(DataType type); 
    } 
} 

class AlphaTreeNode extends MyAppTreeNode { 
    static class Factory implements MyAppTreeNode.Factory { 
    @Override public AlphaTreeNode create(DataType type) { 
     // Remember, in an override your return types can be more-specific 
     // but your parameter types can only be less-specific 
     return new AlphaTreeNode((DataTypeAlpha) type); 
    } 
    } 
} 

然後你就可以只是做一個地圖(雖然考慮番石榴的更好的語義ImmutableMap):

private static Map<Class<?>, MyAppTreeNode.Factory> factoryMap = new HashMap<>(); 
static { 
    factoryMap.put(DataTypeAlpha.class, new AlphaTreeNode.Factory()); 
    // ... 
} 

public static createTreeNode(DataType type) { 
    return factoryMap.get(type.getClass()).create(type); 
} 

更多的麻煩比它的價值?可能在大多數情況下。但請記住,Guice可能也是最好的。 Guice有能力爲你自動生成工廠實現,但你仍然需要以某種方式將DataType映射到MyAppTreeNode.Factory,並且它必須存在於一個Map,一個條件或雙重間接中,訪客模式。

希望這有助於,如果只是爲了認可你已經有的答案!