0

3 つの可能な設計があり、どれが優れているか、どの場合に優れているかを判断しようとしています。すべての設計の一般的な考え方は、データを格納するデータ オブジェクトと、データを分析するアナライザー オブジェクトがあるということです。

これらのデザインから選択する必要がありますが、デザイン 2 が一番気に入っています。しかし、私が一緒に働いている開発者は、私が最悪だと思うデザイン 3 を推し進めています。どのデザインにも欠けている長所や短所はありますか? 説明が必要な場合はお知らせください。

デザイン1

デザイン1

設計 1 では、DataAnalyzer には、構築中に提供される Data オブジェクトがあります。クライアントが呼び出すときdataAnalyzer.analyze()、データが分析されます。この設計では、各オブジェクトの責任は明確です。Data オブジェクトは単にデータを保持し、DataAnalyzer オブジェクトはデータを分析します。格納されたデータを変更すると Data クラスのみが変更され、分析メソッドの種類を追加すると DataAnalyzer クラスのみが変更されます。この設計の問題点の 1 つは、DataAnalyzer オブジェクトは構築中に渡された Data オブジェクトにしか使用できないため、データ オブジェクトが多数ある場合は、多数の DataAnalyzer を作成する必要があることです。もう 1 つの欠点 (設計 3 から明らかになります) は、クライアントが 1 つではなく 2 つのクラスについて知る必要があることです。Data に関連するクラスが他にもある場合、クライアントはこれらすべてのクラスを処理する必要があります。

デザイン 2

デザイン 2

設計 2 は設計 1 と非常に似ていますが、DataAnalyzer が (異なるデータ オブジェクトに対して) 再利用可能になったことを除きます。クライアントは、設計 3 のように 1 つではなく、2 つのクラスで作業する必要があります。責任は依然として非常に明確であり、保守は簡単です。

デザイン3

デザイン3

設計 3 では、クライアントは 1 つのオブジェクトで作業できます。クライアントはdata.analyze()、DataAnalyzer について何も知らなくても、何も言うことができません。これが単一責任規則に違反しているかどうかはわかりません。Data オブジェクトには分析を可能にするインターフェースがありますが、責任は実際には DataAnalyzer に委譲されています。もう 1 つの問題は、データを分析する必要があるかどうかに関係なく、作成されたすべてのデータ オブジェクトに対して DataAnalyzer が作成されることです。さらに機能が追加されれば、多くのことが変わるでしょう。DataPrinter クラスが作成された場合 (これは、データにデータ自体を印刷させるよりも優れていると仮定しましょう)、クライアントは dataPrinter オブジェクトの作成と の呼び出しについて心配する必要はなく、dataPrinter.printData()単に呼び出すことができます。data.print(). ただし、このクラスを追加することで、Data のインターフェイスを変更する必要がありました。DataXX クラスのいずれかにメソッドを追加すると、メソッドが Data クラスに追加されます。

4

4 に答える 4

2

設計 1は、分析に長い時間または多くのリソースが必要な場合に役立ちます。また、ある種のキャッシュを使用して、同じデータの順次分析をより高速に (またはより少ないリソースで) 実行できます。
- 分析中のデータのインスタンスごとに中間結果を保存するか、最終結果をキャッシュする必要がある場合は、これを使用します。

設計 2は、さまざまなデータに対して何度も呼び出すことができ、それを実行するためにリソースを必要としない、またはリソースのプールから要求ごとに異なるリソースを取得できる、静的でスレッド セーフなアナライザーが必要な場合に役立ちます。

さまざまなデータ型 (同じ基底クラスまたはインターフェイスを持つ) がある場合、ビジター パターン、依存性注入、リフレクション、またはコマンド パターンを使用して、メイン クラスから正しい具体的なデータ アナライザー クラスに到達し、単一の責任に違反しないようにすることができます。原理。

設計 3は悪い考えです。なぜなら、それはデータ型とそれに対して行われた処理を結合していることを意味するからです - 処理を追加または変更するたびに、この設計を使用することに決めた場合、決定を呪うことになります :-)

C# 3.0+ などの一部の言語では、設計 3 の構文を使用して設計 2 の操作を機能させるシュガー構文があります。

于 2012-06-26T16:13:06.380 に答える
1

素早い回答

オブジェクト指向の観点から考えると、「データ」はオブジェクトであり、「分析」は操作以上のものであるため、デザイン 3の方が優れていると考えるのは簡単です。

しかし、実際には、@Danny Varodが言うように、データの「悪い結合」です。

実際には、アナライザーはほとんど変更されず、データは大幅に変更されます。オブジェクト指向の観点からすると、アナライザーはデータを変更するため、設計 1がより適しているように見えます。

コメント

余暇には、コンパイラとパーサー、およびそれらが分析するプログラミング言語を使用しています。そして、そのシナリオはあなたの質問に似ています。パーサーは「データ アナライザー」のように見え、解析されるソース コードは「データ」のように見えます。

関係の例:

................................
....+----------------------+....
....|      CPPParser       |....
....+----------------------+....
....| [+] CPPStream Source |....
....+----------+-----------+....
...............|................
...............|................
...............v................
....+----------+-----------+....
....|     <<abstract>>     |....
....|       CPPStream      |....
....+----------------------+....
................................

しかし、私の「データ プロバイダー」 (この場合はストリーム) は、FileStream や StringStream などの派生クラスに置き換えることができるためです。

継承図の例:

............................................................
....+----------------------+................................
....|      CPPStream       |................................
....+----------------------+................................
....| [+] CPPStream Source |................................
....+----------+-----------+................................
...............^............................................
...............|............................................
...............|............................................
...............+---------------------------+................
...............|...........................|................
...............|...........................|................
...............|...........................|................
....+----------+-----------+....+----------+-------------+....
....|     <<concrete>>     |....|      <<concrete>>      |....
....|    CPPFileStream     |....|     CPPFileStream      |....
....+----------------------+....+------------------------+....
....| [+] String Filename  |....| [+] String StringValue |....
....+----------------------+....+------------------------+....
............................................................

あなたのシナリオでは、クラスで表されるデータを子孫クラスに置き換えることはできますか?

その場合は、デザイン 1の方が適しているようです。

乾杯。

于 2012-06-26T20:56:27.637 に答える
0

あなたの懸念を見ると、analyze は静的メソッドのようです。したがって、データを入力として受け入れる静的メソッドとして分析するユーティリティクラスを使用できます。dataPrinting は、この同じユーティリティ クラスの別の静的メソッドにすることができます。データを分析する方法 (アルゴリズム) が複数ある場合、この設計は失敗します。これが必要な場合は、戦略パターンが役立ちます。

于 2012-06-26T18:40:18.180 に答える
0

設計 3 は、データ アナライザーが常にそこにある必要があるため、あまり理想的ではありません。そのクラスを DO にアタッチする必要がない場合がたくさんあると確信しています。また、単一責任の原則に違反していることにも同意します。

設計 2 では、異なるデータ オブジェクト タイプに対して同じではない内部メカニズム/メソッドがある場合、いくつかの問題が発生する可能性があります。毎回再初期化する必要があります。これも単一責任の原則に違反していると思います。Data Analyzer は、1 つのタイプのデータ オブジェクトのみを考慮する必要があります。新しいデータ オブジェクトが入るたびに、内部の仕組みをリセットしてやり直す必要はありません。

デザイン 1 は 3 つの中で私のお気に入りですが、私の理想的なデザインではありません。理想的には、Data Object を Analyzer ファクトリに渡します。ファクトリはその特定のデータ オブジェクトのアナライザーを吐き出し、アナライザーはその作業を行うことができます。これはおそらく最も保守性の高いソリューションです。

于 2012-06-26T15:55:19.967 に答える