5

次のタイプのデータがあるとします。

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;

または、id で検索できるようにするには、equal() と hashCode() をすべて記述する必要はありません。

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

これで LastConnection データにアクセスできるようになりました

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

特に、LastConnections のマップのマップを期待する数十のメソッドにパラメーターとして渡す必要があるため、次のような独自のクラスを作成することを考えています。

class CustomerConnections extends HashMap<String, LastConnection> {
}

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

継承が 3v1l であることはすでにわかったので、構成を試してみましょう。

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;
}

問題は、SOLID の原則とすべてのベスト プラクティスを尊重する最善のアプローチが何であるかがわからないことです。既存のコレクションを拡張する以外に何もしないクラスを作成することは、必要以上にエンティティを増やすように見えますが、私のコードをより明確にします (特に次のレベルがある場合 - 月ごとの AllConnections のマップなど)。道順は?

4

6 に答える 6

5

既存のコレクションを拡張する以外に何もしないクラスを作成することは、エンティティを必要以上に増やしているように見えます

カプセル化するために拡張を変更します。この情報の保存方法の詳細を隠しています。クラスのクライアントは、顧客接続履歴をどのように提供しているかを知る必要はありません。API のクライアントにコードを変更させることなく、基になるモデルを変更できるため、これは良い考えだと思います。

しかし、私のコードをより明確にするでしょう

これは素晴らしいことであり、これを行う正当な理由です。YourClass.getCustomerConnection(cId) は、yourCollection.get(id).get(id).getConnection() よりもはるかに明確です。たとえあなたがその人であっても、このコードを使用している人々の生活を楽にする必要があります。

(特に次のレベルがある場合 - 月ごとの AllConnections のマップなど)

よし、あなたは前もって計画を立て、コードを拡張可能にしています。これは良いオブジェクト指向の練習です。私の意見では、あなたが自分で到達した結論は私がすることです.

于 2009-07-01T10:45:53.310 に答える
1

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

この情報の保存方法のセマンティクスは将来変更される可能性があるため、Mapやその他のよく知られたコレクションクラスから派生させることはしません。

代わりに、顧客とその接続を結び付けるクラスを実装し、そのクラス内で適切なコレクションクラスを使用します(インターフェイスや残りのコードに影響を与えることなく、後で自由に変更できます)。

顧客/接続マネージャークラスは単なるコンテナーではありません。メタデータを保存できます(たとえば、この関係が確立されたのはいつですか)。顧客情報を指定して接続を検索できます(必要な場合)。基盤となるコレクションクラスが重複を処理する方法などではなく、必要な方法で重複を処理できます。デバッグ/ログ記録/パフォーマンス監視を簡単にスロットに入れて、何が起こっているのかを簡単に理解できます。

于 2009-07-01T10:48:08.937 に答える
1

コレクションの使用方法とデータの取得方法についても検討する必要があると思います。

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

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

ただし、カプセル化は一般的には良いことです。特に、デメテルの法則を順守するのに役立つためです。コレクションに対して実行する操作の一部を AllConnections クラス (実質的には DAO) に戻すことができるかもしれません。これは多くの場合、単体テストに役立ちます。

また、単純なヘルパー メソッドを追加したいだけなのに、HashMap の拡張がここで悪と見なされるのはなぜですか? AllConnections のコードでは、AllConnections は常に HashMap と同じように動作します。つまり、多態的に置換可能です。もちろん、(TreeMap などではなく) HashMap を使用することに固執する可能性がありますが、Map と同じパブリック メソッドがあるため、おそらく問題にはなりません。ただし、実際にこれを行うかどうかは、コレクションをどのように使用するかによって異なります-実装の継承を常に悪いものとして自動的に割り引く必要はないと思います(通常はそうです!)

class AllConnections extends HashMap<String, CustomerConnections> {
    public LastConnection get(String custId, String srvUrl) {
        return get(custId).get(srvUrl);
    }
}
于 2009-07-01T18:44:49.470 に答える
0

なぜそれらのオブジェクトの外側のオブジェクト間の関係を維持しているのですか。

私は次のようなものを提案します:

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()
  {
    ...
  }
}

List<Customer>次に、この情報を使用するメソッドに渡します。

于 2009-07-01T10:48:29.187 に答える
0

custId+"#"+srvurlシンプルな鍵として使ってみませんMap<String, LastConnection>か?

または、2 つの ID を含むタプルまたはペア クラスをキーとして使用し、「最もクリーンな」OO ソリューションを実装hashCode()します。equals()

于 2009-07-01T10:46:34.197 に答える