2009-08-07 14 views
9

私はクラスで内部的に使用する比較的複雑なジェネリックタイプ(たとえばMap<Long,Map<Integer,String>>)を持っています。 (外部の可視性はなく、実装の詳細です)。これをtypedefで非表示にしたいのですが、Javaにはそのような機能はありません。"疑似typedef反パターン"の正当な理由はありますか?

昨日私は次のイディオムを再発見し、それが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時に再帰的に入れ子になった6つのジェネリック薬を扱うことになった。 –

+1

靴なし...上り坂...雪の中。 – skaffman

+2

@Marcus Downing :そして、再帰の終わりにレストランで朝食を食べるのは第七レベルです。 ;-) – Mnementh

答えて

5

本当の問題は、このイディオムはのtypedefあなた擬似とクライアントコード間の高い結合を作成することです。しかしFooBarMapを個人的に使用しているので、実際の接続の問題はありません(実装の詳細です)。

NB

現代のJava IDEが決定的に複雑なジェネリック型を扱うのに役立ちます必要があります。

+0

このイディオムを使用しない場合は、複雑で長いタイプの記述( 'HashMap >')とクライアントコードの間に高い結合を作成しています。反パターンの結合がそれより悪い理由を説明できますか? – bacar

+1

@bacar問題は、誰かが 'HashMap >'または 'FooMap'を使用できるかどうかです。 'FooMap'をとるAPIを使用するには、HashMapを渡すことはできません。つまり、インタフェースメソッドで宣言されている場合、それらは一方向のみの多型です。 – Bringer128

2

パブリックインターフェイスでは、意味がないのでジェネリックタイプは見たくありません。 HashMapの引数を持つメソッドを見るには< Long、Map < Integer、String >>はfoo(int、int、int、void *、int)のようなCのメソッドによく似ています。実際の型を持つと、コードを読みやすくなります。パブリックインターフェイスの場合は、HashMap < Long、Map < Integer、String >>を 'typedef'ではなくむしろラップするFooBarMapを作成する方が良いでしょうが、クラス内部使用の場合は、この疑似typedefをなし

+0

このアプローチの問題は、クライアントコードがMapデータ構造の有用性を失うことです。 – skaffman

+2

いいえ、それはそこに残っています... – marijne

0

私はむしろ

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

を書き、私がいつか決めた場合TreeMapのかJava7GreatEnhancedWonderfulMap何も壊れないでしょう:-)するためのHashMapから実装クラスを変更するだろう。しかしこれで、あなたはHashMapに悩まされています。

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

を、それはますます面倒になっ:まあ、あなたが作ることができます。

+2

例の型はプライベートなので、実際には 'typedef'ルートはコードの1か所でMap - > HashMapを置き換えるだけで済むので、型を保存します。 – marijne

+0

Map型のフィールドを宣言すると、コンパイラはインターフェイスで宣言されていないメソッドを呼び出せません。そして、実装クラスをMapを実装する他のクラスに置き換えれば、すべてのコードが機能し続けるでしょう。私がHashMapとして宣言すれば、私はHashMapメソッドを呼び出すことができます。また、 "typedef"に型を代入するとコードが壊れてしまいます。ある日、Hibernateを使用してDBからマップをロードしたい場合、私はそれを行うことができます。私がHashMapを持っていれば、Hibernateによって与えられたMapの内容を新しいものにコピーしてコピーする必要があります。可能な限り一般にインターフェイスを使用することが強く推奨されています。このイディオムはそれを失望させます。 –

0

パブリックインターフェイスに配置することについては、彼はこれについて良い点があります。このイディオムは構文的な砂糖のいくつかの形をエミュレートしているので、クライアントに表示する内容に影響を与えるべきではありません。

しかし、ローカルで使用しないといけない理由はありません。それは、人生が楽になり、コードを読みやすくすることができます。ブライアンはどんな状況でも一般化して強くアドバイスするかもしれませんが、それは彼のGoetzの感情です:p

0

小さなローカライズされたコード単位でしか使用しない場合、問題は小さいです。

あなたのプログラムは、擬似typedefを5回以上参照するまで、テキストのサイズが小さくなることはないでしょう。これは、表示される領域が些細なものでなければならないことを意味します。

おそらく、これを行ったコードを書き直すことはできませんでしたが、悪い習慣に思えます。

9

IMO、Javaアンチパターンの問題は、彼らが白黒の思考を奨励することです。

実際には、ほとんどのアンチパターンはニュアンスがあります。たとえば、リンクされた記事では、擬似typedefがタイプシグニチャが制限的すぎるAPIにつながり、特定の実装の決定、ウイルスなどに結びついていることが説明されています。しかし、これはすべてパブリックAPIのコンテキストにあります。擬似typedefを公開APIから守ると(つまり、クラスやモジュールに制限するなど)、実際には害はなく、コードを読みやすくします。

私のポイントは、あなたがアンチパターンを理解し、どこでそれを回避する程度推論判断を作るに必要があるということです。単に「私はになりません。は反パターンなのでXを行う」ということは、時には許容可能な、あるいは良い解決策を除外することを意味することを意味します。

関連する問題