1

(私は比較的経験の浅いプログラマであることを心に留めておいてください。OOP には継承に関する非常に多くの哲学があるため、この質問はあまりにもオープンエンドと見なされる可能性があることを認識しています。この質問は、私の思考プロセスに向けられています。つまり、経験豊富なプログラマーにとって正しいと思われるような方法でこのシナリオに取り組んでいますか? 私の考えが明らかに正確または不正確であることは何ですか?)

私は、コンピューター、プリンター、スイッチ、ルーター、携帯電話、ハード ドライブ、およびその他のデバイスを含む IT ハードウェアに関する情報を追跡するインベントリ システムを設計しています。私はデータベースを設計しており、現在フロントエンド アプリケーションを計画中です。アプリケーションでデータ アクセス レイヤー、ビジネス ロジック レイヤー、およびビジネス エンティティを使用する予定です。私はまだ概念的な計画段階にあり、この時点で実装の詳細を検討するべきではないことを認識していますが、私の心は前に進む傾向があります。検索機能が動作するはずの方法は、ユーザーが検索条件を入力して検索を実行することです。一致するデバイス (または一致する唯一のデバイス) のリストが返されます。デバイスのリストはある種のリスト ビューで表示され、デバイスを選択すると詳細ビューが表示されます。

最終的なビジネス エンティティで継承を使用するとアプリケーションにメリットがあるのか​​、不要な複雑さを追加するのか、それとも単純に間違っているのか疑問に思っていました。私の最初の考えは、図のようなセットアップです。

(これは実際の設計ではなく、この投稿の単純化された概念にすぎません) タイプ固有の属性を持つ各デバイスに加えて、任意の時点でデバイスはアクティブまたはアーカイブの 2 つの状態のいずれかになります。これをモデル化する方法がまったくわかりません。

概念クラス図

このセットアップを使用すると、クエリがどのように機能するかを考え始めました。次のように、データアクセス層からデバイスの特定のサブクラスを照会するのは簡単に思えます。

擬似コード:

Computer comp = getComputerBySerialNumber(sn);
List<Router> routers = getRouters();

// I can then write code to display a list of basic device information and
// additionally display all details of a computer or router when requested.
// Obviously display would be handled in a different layer.

この質問を書くに至った問題は、「特定の場所からすべてのデバイスを取得する」などのクエリを処理する方法です。

// Returns a list of devices regardless of device type
// as long as they have the same location
List<Device> devsFromLocation = getDevicesByLocation(loc);

// List contains computers, routers, printers, etc.

基本クラスのオブジェクト参照がある場合、基本的なデバイスの詳細を表示してから、特定のデバイスの詳細を表示するにはどうすればよいですか? (クレイジーなキャストやリフレクションの使用を避けようとしています)。その場所の各デバイスには、サブタイプの特定の属性がありません。特定のデバイスに関するすべてのデータを表示したい場合は、残りのフィールドを取得するためにデータベースを再度クエリする必要があります。別のクエリを実行する必要があるのは、設計が不十分な兆候ですか? さらに、正しいタイプのデバイスをどのように判断すればよいでしょうか? おそらく、それぞれをテストする大きな switch/case ステートメントDevice.Type属性、正しいクエリを実行し、完全なサブタイプを返し、詳細をユーザーに表示しますか? または...完全なサブタイプのオブジェクトを含む個別のリストを返し、すべてのリストを繰り返し処理してリスト ビューに共通の属性を表示し、詳細ビューにサブタイプの詳細を簡単に表示する方がよいでしょうか?

これは継承の有用なケースですか、それとも誤用ですか? 私は現在、情報過多の問題に苦しんでいます。私は OOD について可能な限りすべてを読みましたが、頭の中に非常に多くのルールとガイドラインがあり、自分が正しいことをしているかどうかわかりません。脳が吸収した情報を適用しようとしているような気がするので、間違った実装を想像しています。コードの柔軟性を維持するための抽象化へのプログラミングに関するこのすべてのビジネスについて考え続けていますが、ある時点で具体的なクラスを処理する必要がありますよね? 私の見解では、継承は属性ではなく動作に関するものです。私は実際に行動をモデル化しているわけではなく (または、私と私はそれを見ることができないのでしょうか?)、デバイスに関するデータを収集しているだけなので、それらの関係を解釈するのが難しくなっています。これらのクラスは本質的に属性の愚かなコレクションであるため、それらはすべて別のクラスであるべきだと思います。繰り返しになりますが、すべてのクラスでフィールドが重複していますが、この場合は本当に問題になるのでしょうか?

OOD、継承、構成などに関する本がたくさんあることは知っています。私はそれらの本のいくつかを読みました。私は現在、さらにいくつかを読んでおり、オンラインで調査するのに何日も費やしました。誰もが分かりやすい継承の例を便利に使用しています。果物、動物、形の例について悪夢を見ています。

私の質問を読んでくれてありがとう、そしてあなたが提供できる情報や洞察に感謝します。その他のヒント、洞察、企業秘密、埋もれた宝物への地図、耐航性のあるボートと六分儀、または役立つと思われるその他の情報をお気軽に提供してください。

4

1 に答える 1

1

最も簡単な方法は、情報を返す基本クラスに情報メソッドを追加し、各派生型でそのメソッドを正しい情報でオーバーライドすることです。

これにより、次のことが可能になります。

foreach (Base b in list)
  Write(b.Information());

出力をより動的にする必要がある場合は、デバイス情報オブジェクトを検討してください。

あなたの投稿だけをざっと読んだだけなので (そのため、これを悪い考えにする詳細を見逃している可能性があります) 、 「has-a(n)」であるため、基本クラスActive Stateのメンバーを作成することもお勧めします(同じ場合は真実)。DeviceDeviceActive StateArchive State

それ以外は、あなたのデザインは素晴らしくシンプルで理にかなっています。

編集:

したがってReport、情報を書き込みたいオブジェクトがある場合は、次のようになります。

class Device{
  write_information_to_report(Report report);
}

これは、派生した特定の情報を追加する派生クラスによってオーバーライドできます。

あなたが本当にしたいのであれば、Reportアウトを抽象化して次のようにすることもできます。InformationOutputter

図形を描画するこの種の良い例:

class Graphics{
  line(int, int, int, int) = 0;
  curve(float, float, float, float) = 0;

class OpenGLDrawer : Graphics {
  line(int, int, int, int) { // Use open gl to draw a line };
  curve(int, int, int, int) { // Use open gl to draw a line };
}

class DirextXDrawer : Graphics {
  line(int, int, int, int) { // Use directX to draw a line };
  curve(int, int, int, int) { // Use directX to draw a line };
}

class Shape{
  draw(Graphics g) = 0;
}

class Triangle : Shape{
  draw(Graphics g) { g.line(... /* draw a triangle using line */ };
}

class Circle : Shape{
  draw(Graphics g) { g.arc(... /* draw a circle using arc */};
}

ここでは、各オブジェクトに独自の機能を持たせることができ、共通の機能を基本クラス レベルで共有でき、任意のグラフィックス オブジェクトが任意の形状を描画できることがわかります。

于 2012-07-04T10:02:40.977 に答える