2009-07-01 18 views
5

でコレクションクラスをカプセル化するには、私は次のタイプのデータがあるとします。継承およびJava

class Customer { 
    String id; // unique 
    OtherCustData someOtherData; 
} 

class Service { 
    String url; // unique 
    OtherServiceData someOtherData; 
} 

class LastConnection { 
    Date date; 
    OtherConnData someOtherData; // like request or response 
} 

今私は、顧客のそれぞれが、各サービスに接続したときに覚えておく必要があります。
私は構造になるだろう:

Map<Customer, Map<Service, LastConnection>> lastConnections; 

をあるいは、IDSで検索できるようにしていないすべての均等を記述する必要が()とhashCode():

Map<String, Map<String, LastConnection>> lastConnections; 

今、私はアクセスすることができました

LastConnection connection = lastConnections.get(custId).get(srvUrl); 

すべてこれは私がLastConnections、Sのマップのマップを期待する方法の数十にパラメータとして渡す必要があり、特にこと、醜いと思われることでLastConnectionデータO私はそのようなことになり、私自身のクラスの作成を考えています:

class CustomerConnections { 
    Map<String, LastConnection> customerConnections; 
    LastConnection get(String srvUrl) { 
     return customerConnections.get(srvUrl); 
    } 
    ... // all other needed operations; 
} 

class AllConnections { 
    Map<String, CustomerConnections> allConnections; 
    public LastConnection get(String custId, String srvUrl) { 
     return get(custId).get(srvUrl); 
    } 
    public CustomerConnection get(String custId) { 
     return allConnections.get(custId); 
    } 
    ... // all other needed operations; 
} 

問題があることである:

class CustomerConnections extends HashMap<String, LastConnection> { 
} 

class AllConnections extends HashMap<String, CustomerConnections> { 
    public LastConnection get(String custId, String srvUrl) { 
     return get(custId).get(srvUrl); 
    } 
} 

[OK]を、私はその継承が3v1lで、それでは、構図を試してみましょうすでに学びました私は、SOLIDの原則とすべてのベストプラクティスを尊重した最善のアプローチが何であるかはわかりません。既存のコレクションを拡張する以外は何もしないクラスを作成することは、必要以上にエンティティを増やすように思えますが、コードをより明確にします(特に、月ごとにAllConnectionsのマップなどの次のレベルがある場合)。どんな方向?あなたはMap<K,V>を実装するクラスを作成し、内部の容器マップに委任することができ

答えて

5

をデリゲートの短い何もしないメソッドの多くを実装するためにあなたを必要とする欠点を持っています既存の コレクションを拡張することは、私はカプセル化するために、拡張変わってしまう必要

超え エンティティを掛けるように思えます。この情報がどのように格納されているかの詳細は隠しています。クラスのクライアントは、顧客の接続履歴をどのように提供しているかを知る必要はありません。私はこれが良いアイデアだと思うので、基本的なモデルを変更することができますAPIのクライアントは、コードを変更することなく。

が、これは素晴らしいですし、これを行うための十分な理由である

私のコードがより明確になるだろう。 YourClass.getCustomerConnection(cId)は、yourCollection.get(id).get(id).getConnection()よりはるかに明確です。あなたがその人であっても、このコードを使用する人々の人生をより簡単にする必要があります。

(次のレベルがある場合は特に - AllConnectionsの地図などは、月によってなど)

良い、あなたは前もって計画し、コードの拡張性を作っています。どちらが良いOOの練習です。私の意見では、自分で達成した拍手は私がやることです。

シンプル Map<String, LastConnection>でキーとして custId+"#"+srvurl使用しないのはなぜ
-1

class CustomerConnections implements Map<String,LastConnection> { 
    private Map<String, LastConnection> customerConnections; 

    @Override 
    public LastConnection get(Object srvUrl) { 
     return customerConnections.get(srvUrl); 
    } 
    // all other needed operations; 
} 

このアプローチの良いところは、あなたが良く、標準を持っているMapの周りに渡すことができるということですライブラリクラスを拡張することは避けられますが、これはしばしば嫌にされます。

EDIT:以下指摘したように、これが以外何も しないクラスを作成する基になるコレクションに

+2

無益な「その他すべての必要な操作」コメントは、定型的な代表団の計量値を隠しています。 –

+0

@マイケル・フェア・ポイント – butterchicken

+1

これは一度だけ行う必要があります。 DelegatingMap は、マップを実装しており、すべてのそのような拡張の基本クラスとして使用できます。 – paulcm

0

? 「クリーン」OOソリューション -

または2つのIDが含まれており、hashCode()equals()を実装キーとしてTupleまたはペアクラスを使用します。

+0

custId + "#" + srvUrlをキーとして使用すると、すべての顧客の接続をすばやく取得することはできません。とにかくTupleライブラリのアイデアをありがとう、私はそれを調べます。 – Jakub

+0

元の問題の一部ではありませんでした。その場合はおそらくマップマップが最適です。 –

1

私は、この情報を格納するための専用のオブジェクトを作成します。あなたが作成しているのは、単純なコレクションではなくのマネージャオブジェクトです。

私はあなたがこの情報を保存する方法のセマンティクスは将来変更される可能性があるので、それは、地図または他のよく知られたコレクションクラスから派生しないでしょう。

代わり

(あなたがインターフェイスとあなたのコードの残りの部分に影響を与えずに、後で変更するには自由にしていること)は、顧客との接続を結びつけるクラスを実装し、そのクラス内の適切なコレクションクラスを使用します

あなたの顧客/接続マネージャクラスは単なるコンテナ以上のものです。メタデータを格納することができます(この関係が確立された時期など)。必要な場合は、顧客情報がある接続に関する検索を実行できます。それは、基になるコレクションクラスがそれらを処理する方法ではなく、必要な方法を重複して扱うことができます。デバッグ/ロギング/パフォーマンス監視で簡単にスロットを入れて、何が起こっているのかを簡単に理解できます。

0

は、なぜあなたはそれらのオブジェクトの外側のオブジェクト間の関係を維持しています。あなたは、この情報を使用する方法にList<Customer>を渡す

public class Customer 
{ 
    public List<LastConnection> getConnectionHistory() 
    { 
    ... 
    } 

    public List<LastConnection> getConnectionHistory(Service service) 
    { 
    ... 
    } 

    public List<LastConnection> getConnectionHistory(Date since) 
    { 
    ... 
    } 
} 

public class LastConnection 
{ 
    public Date getConnectionTime() 
    { 
    ... 
    } 

    public Service getService() 
    { 
    ... 
    } 
} 

は、私は次のようなものをお勧めしたいです。

+0

しかし、私のCustomerクラスはLastConnectionクラスについて知る必要があります。私は、さまざまなパッケージの間に数トンのサイクルで終わるかもしれません。 Farewell、reusability ...私のコードにCore、LastConnections、AddressBook、TransactionHistoryという4つのパッケージがあるとします(例のみ)。私がmypackage.core.CustomerにLastConnections、AddressBook、およびTransactionHistoryについて知ってもらえれば、それは混乱を招くでしょう。私は、LastConnectionが顧客について知っており、AddressBookが顧客について知っていることを、他の方法よりも好むことを好みます。このようにして次の機能を実装しても、既存のコードは変更されません。 – Jakub

+0

パッケージで私はあなたが瓶を意味すると仮定していますか?この場合、これらの関係を使用するアプリケーションでは、ドメインクラスを(前述のように)定義します。ドメインクラスは、パッケージ化されたクラスを特殊化またはカプセル化することができます。私の傾向は、アプリケーションに関連しないパッケージ化されたクラスの属性/機能を隠すことができるためです。私は通常、 '値オブジェクト'が関わっているときにこれを使用しましたが、アプリケーションは '値オブジェクト'が公開するセッターを表示してはいけません。別の利点は、パッケージ化されたクラスが変更された場合、アプリケーションが分離されることです。 –

1

は、私はあなたにもコレクションが使用されようとしている方法を検討すべきだと思うし、データを取得する方法:

  • 彼らは、単純な結果は、その後、(例えば)ページに表示されるように設定している場合標準的なコレクションを使用することは妥当と思われます。そして、それらを操作するために多くの標準ライブラリを使用することができます。一方
  • 、彼らは変更可能であり、任意の変更は(、その後、データベースに変更を書き込むことができるなど)が好ましいかもしれないその後、独自のクラス内でそれらをカプセル化する、(例えば)永続化する必要がある場合。

どのようにあなたのデータを取得し、持続しますか?データベースに格納されている場合は、データ構造を自分で管理する必要はなく、顧客やサービス、月ごとにLastConnectionsを選択するためにSQLを使用することができます(単なるリストや接続マップや接続数を返します)。あるいは、各リクエストに対してクエリを実行したくない場合もありますので、データ構造全体をメモリに保存する必要があります。

カプセル化は、特にLaw of Demeterを遵守するのに役立ちます。特に、コレクションで実行する操作の一部をAllConnectionsクラスにプッシュすることができます(実際にはDAOです)。 )。これは単体テストに役立ちます。

また、HashMapを拡張するのは、些細なヘルパーメソッドだけを追加したいと考えているため、ここでは邪魔になるのはなぜですか? AllConnectionsのコードでは、AllConnectionsは常にHashMapと同じように動作します。これは多態的に代入可能です。もちろん、HashMap(TreeMapなどではなく)を使用することに潜在的に自分自身をロックしていますが、Mapと同じパブリックメソッドがあるため、おそらく問題ありません。しかし、実際にこれを行うかどうかは、コレクションをどのように使用するかによって異なります。常にが悪い(実装されているのは通常です)

class AllConnections extends HashMap<String, CustomerConnections> { 
    public LastConnection get(String custId, String srvUrl) { 
     return get(custId).get(srvUrl); 
    } 
} 
関連する問題