2009-08-07 67 views
9

我有一個比較複雜的泛型(比如Map<Long,Map<Integer,String>>),我在課堂上使用它。 (沒有外部可見性;它只是一個實現細節。)我想將它隱藏在typedef中,但Java沒有這樣的設施。是否有過「pseudo-typedef antipattern」的理由?

昨天我重新發現了下面的習語,很失望地得知它是considered an anti-pattern


class MyClass 
{ 
    /* "Pseudo typedef" */ 
    private static class FooBarMap extends HashMap<Long,Map<Integer,String>> { }; 

    FooBarMap[] maps; 

    public FooBarMap getMapForType(int type) 
    { 
    // Actual code might be more complicated than this 
    return maps[type]; 
    } 

    public String getDescription(int type, long fooId, int barId) 
    { 
    FooBarMap map = getMapForType(type); 
    return map.get(fooId).get(barId); 
    } 

    /* rest of code */ 

} 

可我會有這方面的任何理由,當種類是隱藏的,沒有形成一個庫API的一部分(這在我的閱讀是戈茨的使用它主要反對)?

+6

你稱這種泛型類型複雜?哈!當我是一個小夥子時,我們不得不在早上3點起牀,處理六級遞歸嵌套仿製藥... – 2009-08-07 08:40:39

+1

Aye ...沒有鞋子...上山...在雪地裏.. – skaffman 2009-08-07 08:49:04

+2

@Marcus Downing :在遞歸結束時,你在餐廳吃早餐的第七層。 ;-) – Mnementh 2009-08-07 10:36:41

回答

5

真正的問題是,這個成語創建您的僞typedef的和您的客戶端代碼之間的高耦合。但由於您私下使用FooBarMap,所以不存在耦合(它們是實現細節)的實際問題。

NB

現代的Java IDE應明確有助於應對複雜的泛型類型。

+0

如果你不使用這個習慣用法,那麼你將在長而複雜的類型描述('HashMap >')和客戶端代碼之間建立一個高度耦合。你能解釋爲什麼反模式的耦合比​​這更糟嗎? – bacar 2012-11-20 18:15:16

+1

@bacar問題是某人是否可以使用'HashMap >或你的'FooMap'。要使用一個採用'FooMap'的API,你不能傳遞一個HashMap。也就是說,如果在接口方法上聲明,它們只在一個方向上是多態的。 – Bringer128 2012-11-21 01:48:34

2

對於公共接口,我不喜歡看泛型類型,因爲它們沒有意義。對於我看到一個參數爲HashMap < Long的方法,Map < Integer,String >>與Foo(int,int,int,void *,int)等C方法非常相似。擁有真正的類型只是讓代碼更容易閱讀。對於公共接口,最好創建包裝HashMap的FooBarMap < Long,Map < Integer,String >>而不是'typedef',但對於類內部使用,我根本沒有看到任何下面的東西。

+0

該方法的問題是客戶端代碼失去了Map數據結構的有用性。 – skaffman 2009-08-07 08:50:49

+2

不是,它仍然在那裏...... – marijne 2009-08-07 11:26:54

0

沒有這個僞typedef的,我寧願寫

private Map<Long,Map<Integer,String>>[] maps; 

,如果有一天我決定做改變從HashMap中的實現類的映像樹或Java7GreatEnhancedWonderfulMap :-)什麼都不會破裂。但是有了這個,你就會陷入HashMap。那麼,你可以做:

interface FooBarMap extends Map<Long,Map<Integer,String>> { }; 
class FooBarHashMap extends HashMap<Long,Map<Integer,String>> implements FooBarMap{ }; 

但它變得越來越麻煩。

+2

不是真的,因爲示例中的類型是私有的,事實上,'typedef'路由可以節省一些輸入,因爲您只需在代碼中的一個位置替換Map - > HashMap。 – marijne 2009-08-07 08:15:21

+0

如果我聲明一個類型爲Map的字段,編譯器不會讓我調用未在接口中聲明的方法。如果我用實現Map的其他類替換實現類,則所有代碼都將繼續工作。如果我將它聲明爲HashMap,我可以調用HashMap方法。而在「typedef」中替換type會破壞代碼。如果我有一天想用Hibernate從數據庫加載我的Map,我可以做到。如果我有HashMap,我必須創建新的並複製Hibernate給出的Map的內容。通常在可能的地方使用接口是非常值得鼓勵的。這個成語不鼓勵它。 – 2009-08-07 08:24:32

0

當談到把它放入公共界面時,他有一個很好的觀點。這個習語模擬某種形式的語法糖,它不應該影響你向客戶展示的東西。

但我認爲沒有理由不在本地使用它,只要它讓你的生活更輕鬆,代碼更具可讀性 - 並且你知道你在做什麼。布賴恩可能會在任何情況下強烈反對,但這是他的戈茨感覺:p

0

如果您只在小的本地化代碼單元中使用它,問題很小,真實。

事情是,收益也是:你的程序可能甚至不會在文本上變得更小,直到你引用pseudo-typedef 5+次,這意味着它可見的區域必須是非平凡的。

我可能不會重寫這樣做的代碼,但它似乎是一個壞習慣。

9

IMO,Java反模式的問題是他們鼓勵黑白思維。

實際上,大多數反模式都是微妙的。例如,鏈接的文章解釋了僞類型定義如何導致類型簽名過於嚴格的API,與特定的實現決策,病毒等等緊密相關。但這都是在公共API的背景下。如果您將僞類型定義保存在公共API之外(即將它們限制爲某個類或某個模塊),那麼它們可能不會造成實際的損害,並且它們可能會使您的代碼更具可讀性。

我的意思是,你需要了解反模式,並就何時何地,以避免他們理性的判斷。只要採取「我會從不做X因爲它是一種反模式」的立場,這意味着有時你會排除可接受的甚至是好的解決方案。

相關問題