web-dev-qa-db-ja.com

オブジェクト指向プロジェクトをどのように設計しますか?

私は多くのクラスを持ち、拡張可能である必要がある大規模なプロジェクトに取り組んでいますが、プログラムを計画する方法とクラスが相互作用する方法がわかりません。

私は数学期前にOODコースを受講し、そこから多くのことを学びました。 UMLの作成、要件ドキュメントのオブジェクトやクラスへの翻訳など。私たちもシーケンス図を学びましたが、どういうわけか講義や何かを見逃しましたが、それらは本当に私に固執しませんでした。

以前のプロジェクトでは、コースから学んだ方法を使用してみましたが、通常「最終的には自分が考えていたもののように見える」と言うことができるコードになります。新機能。

Steve McConnellのCode Completeのコピーを手に入れました。設計に関する章を読んだのですが、探している情報が出てこなかったようです。彼は、これはカットアンドドライプロセスではなく、ほとんどがヒューリスティックに基づいていると言っていることを知っていますが、彼の情報をすべて取り入れて自分のプロジェクトに適用することはできないようです。

プログラミングを始める前の高レベルの設計段階で行うことは何ですか?必要なクラス(特に「実世界のオブジェクト」に基づいていないクラス)を決定し、それぞれがどのように対話するかその他

具体的には、あなたが使用する方法は何ですか?通常、最終製品を厳密に表す優れたクリーンなデザインを実現するプロセスは何ですか?

225
Victor

最初の設計(クラス図の取得)に使用する手順は次のとおりです。

  1. 要件の収集。クライアントと話し合い、ユースケースを考慮して、ソフトウェアに必要な機能を定義します。

  2. 個々のユースケースの物語を作成します。

  3. 物語に目を通し、候補クラスおよび動詞(アクション)として、名詞(人、場所、物)をメソッド/行動として強調表示します。

  4. 重複する名詞を破棄し、共通の機能を除外します。

  5. クラス図を作成します。あなたがJava開発者であれば、SunのNetBeans 6.7には、図式化とラウンドトリップエンジニアリングを可能にするUMLモジュールがあり、無料です。 Eclipse(オープンソースJava IDE)にもモデリングフレームワークがありますが、私は経験がありません。また、オープンソースのツールであるArgoUMLを試してみることもできます。

  6. OODの原則を適用して、クラスを整理します(一般的な機能の抽出、階層の構築など)。

190
Scott Davies

私はまだコメントするほどの評判がありません(今日参加しました)か、スコット・デイヴィスの答えにコメントするだけです。彼が言わなければならなかったことに加えて:

  1. 開始する前に、プログラムの内容を完全に把握してください。あなたのプログラムは何ですか? notは何をしますか?解決しようとしている問題は何ですか?

  2. ユースケースの最初のセットは、プログラムが最終的に実行するすべてのリストではありません。プログラムの目的の本質を捉えた、考えられる最小のユースケースセットから始めます。たとえば、このWebサイトのコアユースケースは、loginask aquest質問に答える、および質問と回答を見る。評判、投票、コミュニティwikiについては何もありません。あなたが狙っているのは生の本質です。

  3. 潜在的なクラスを思い付くとき、それらが表す名詞の観点だけでなく、それらの責任について考えてはいけません。これは、プログラムの実行中にクラスが互いにどのように関連するかを理解する上で最大の助けになることがわかりました。 「犬は動物である」や「子犬には母親が1人いる」などの関係を簡単に思い付きます。通常、オブジェクト間の実行時の相互作用を記述する関係を理解するのは困難です。プログラムのアルゴリズムは少なくともオブジェクトと同じくらい重要であり、各クラスの仕事を詳しく説明しておけば、設計がはるかに簡単になります。

  4. ユースケースとオブジェクトの最小限のセットを取得したら、コーディングを開始します。あまり役に立たず、おそらくがらくたのように見えても、できるだけ早く実際に実行されるものを入手してください。それは出発点であり、紙の上であなたが見直すかもしれない質問に答えることを強制します。

  5. 戻って、さらに多くのユースケースを選択し、それらがどのように機能するかを書き、クラスモデルを修正し、さらにコードを書きます。最初のカットと同じように、意味のあるものを追加しながら、できる限り少しずつ実行します。すすぎ、繰り返します。

ちょうど私の2セント。うまくいけば便利です。

65
Darryl

機会があったとき、私は通常「3反復ルール」と呼ぶものを使用します。

最初の反復(または起動)で、モデルオブジェクト、アルゴリズム、および予想(実際予想ではなく、多分予想に従ってアプリケーションの一般的なレイアウトを考案します) 今後の方向性。私は設計文書を書きませんが、複数の人を調整する必要がある場合、依存関係の分析と必要な時間の推測とともに、手順の大まかなスケッチがもちろん必要です。私のように、より機敏な方法を好む場合は、このフェーズを最小限に抑えるようにしてください。特に、プログラムのロジックについてすべてが既知であり、真実である場合、およびコード内の機能間で多くの対話を行う予定がある場合は、強力な設計フェーズが必要な場合があります。この場合、特にGUIアプリの場合、ユースケースまたはユーザーストーリーが提供する優れた高レベルのアイデアです。コマンドラインアプリ、および特定のライブラリの場合、開発する必要のあるライブラリに対してコードを記述する「プログラムストーリー」を作成し、その外観を確認してください。これらのプログラムは、完了するとライブラリの機能テストになります。

この最初のイテレーションの後、物事がどのように相互作用するかについてよりよく理解し、詳細と大まかなスポットを明らかにし、スラップダクトテープパッチの問題を解決します。このエクスペリエンスを活用して、大きすぎたものを改善、クリーン化、洗練、分割し、断片化しすぎたものを合体させ、設計パターンを定義して使用し、パフォーマンスのボトルネックと重大なセキュリティ問題を分析する準備ができています。一般に、これらの変更はすべて、作成した単体テストに大きな影響を与えますが、機能テストには大きな影響を与えません。

この2回目の反復を完了すると、小さな宝石、十分にテストされ、十分に文書化され、適切に設計されます。これで、3回目の反復、拡張を行うための経験とコードの両方が得られました。新しい機能とユースケースを追加して、アプリケーションを改善します。大まかなスポットが見つかり、最終的に2番目の反復に類似した4番目の反復に入ります。すすぎ、繰り返します。

これがソフトウェア設計に対する私の一般的なアプローチです。これはスパイラルデザインに似ており、短い3か月の反復とアジャイル開発の要素があり、問題を学習し、ソフトウェアとそのアプリケーションの分野を知ることができます。もちろん、スケーラビリティの問題なので、アプリケーションが非常に大きく、数百人の開発者が関与する場合は、これよりも少し複雑になりますが、最終的には考え方は常に同じだと思いますdivideetimpera

要約すると:

  1. 反復1では、それを味わって、学習します
  2. 反復2では、製品をクリーンアップし、将来に備えます。
  3. イテレーション3では、新しい機能を追加して詳細を学習します
  4. 後藤2
19
Stefano Borini

これに関して私が知っている最も興味深い情報源は、Bertrand Meyerによるオブジェクト指向ソフトウェア構築、第2版のパートDです。

パートD:オブジェクト指向の方法論:メソッドをうまく適用する

19:方法論、20:デザインパターン:マルチパネルインタラクティブシステム、21:継承のケーススタディ:インタラクティブシステムでの「取り消し」、22:クラスを見つける方法、23:クラス設計の原則、24:継承をうまく使う、25:役に立つテクニック、26:スタイル感覚、27 :オブジェクト指向分析、28:ソフトウェア構築プロセス、29:メソッドの指導

興味深いことに、章22。クラスの見つけ方はオンラインで利用できます。

16
Daniel Daranas

それはしばしば繰り返されますが、完全に真実です-データを理解してください。

OOPの場合、クラスは重要な情報とそれらの相互作用を記述する必要があります。

データの動作と有効期間を詳しく説明するメンタルモデルがある場合は、クラスを簡単にレイアウトできます。

これは単に次の拡張機能です。何をしようとしているかを正確に把握します。

12
Dave Gamble

行動駆動開発を使用してみてください。古い習慣を破ることは難しいでしょうが、現実世界での開発に関しては、BDDが本当に最善の策であることがわかりました。

http://behaviour-driven.org/

10
Eric the Red

大規模プロジェクトの問題は、コンポーネント間のすべての相互作用を監視できないことです。したがって、プロジェクトの複雑さを軽減することが重要です。クラス図とシーケンス図は、この設計段階では詳細すぎます。

最初に、より高い抽象化レベルから考えてみてください。主要なコンポーネントとその責任(他のコンポーネントへのインターフェイス)を考え、インスピレーションを得るためのアーキテクチャパターンを見てください(デザインパターンではなく、低レベルです!MVCとマルチティアはアーキテクチャパターンの例です)。かなり大きなプロジェクトの場合、このようなビューには約3〜5個のコンポーネントが必要です。

その後、特定のコンポーネントにズームインして、それを設計しようとします。これで、設計パターンとクラス図のレベルになりました。プロジェクトのこの部分に集中してみてください。他のコンポーネントの1つに責任を追加する必要がある場合は、ドキュメント/タスクリストに追加してください。この時点で影響があまりにも急速に変化することを考えて時間を無駄にしないでください。設計がより強固になったら確認してください。

この時点で各コンポーネントを完全に設計する必要はありませんが、実装されていないコンポーネントのインターフェイスを実装し、シンプルだが有用な応答を生成するコードを用意するのがおそらく賢明です。これにより、一度に1つのコンポーネントの開発(および設計)を開始し、妥当な程度までテストできます。

もちろん、新しいコンポーネントが完成したら、先に進む前に、それらがどのように(そしてどのように)統合するかをテストする必要があります。

簡単に言うと、OOと情報隠蔽の原則を採用し、それを別のレベルに引き上げます!


PS:設計中に多くのスケッチをします、それは本物の建築のようです!

PPS:さまざまな角度から問題にアプローチし、ボックスの外側を考えてみてください(ボックスが進むべき道かもしれませんが)、ピアと議論することはこれに非常に役立ちます...そして、昼食について話すことがあります。

8
NomeN

合理的な成功を収めた実際のプロジェクトで使用した手法は、Wirfs-Brockの本に触発された責任駆動型設計です。

トップレベルのユーザーストーリーから始め、同僚とともに、ホワイトボードで、彼らが示唆する高レベルの相互作用をスケッチします。これにより、大きなモジュールが何であるかを最初に知ることができます。そして、プレイのような高レベルのCRCカードを1〜2回反復することで、主要なコンポーネントのリスト、それらが何をするのか、どのように相互作用するのかを安定させる必要があります。

次に、責任のいずれかが大規模または複雑である場合、より高いレベルの相互作用によって識別された主要な操作ごとにモジュール内の相互作用を実行することにより、オブジェクトになるのに十分小さくて単純なものになるまで、それらのモジュールを絞り込みます。

いつ停止するかを判断することは、判断の問題です(これは経験によってのみ発生します)。

7
Steve Gilham

デザインパターン

創造的なデザインパターン

シングルトン-クラスのインスタンスが1つだけ作成されるようにし、オブジェクトへのグローバルアクセスポイントを提供します。

Factory(Factory Methodの簡易バージョン)-インスタンス化ロジックをクライアントに公開せずにオブジェクトを作成し、共通インターフェースを介して新しく作成されたオブジェクトを参照します。

ファクトリメソッド-オブジェクトを作成するためのインターフェイスを定義しますが、サブクラスにインスタンス化するクラスを決定させ、共通インターフェイスを介して新しく作成されたオブジェクトを参照させます。

Abstract Factory-クラスを明示的に指定せずに、関連するオブジェクトのファミリーを作成するためのインターフェースを提供します。

Builder-オブジェクトを作成するためのインスタンスを定義しますが、インスタンス化するクラスをサブクラスに決定させ、構築プロセスをより細かく制御できます。

プロトタイプ-プロトタイプインスタンスを使用して作成するオブジェクトの種類を指定し、このプロトタイプをコピーして新しいオブジェクトを作成します。

行動デザインパターン

Chain of Responsibiliy-リクエストの送信者をその受信者に接続することを回避し、この方法で他のオブジェクトにリクエストを処理する可能性を与えます。 -オブジェクトはチェーンの一部になり、オブジェクトの1つがそれを処理するまで、要求がチェーン間で1つのオブジェクトから別のオブジェクトに送信されます。

コマンド-要求をオブジェクトにカプセル化し、異なる要求を持つクライアントのパラメーター化を許可し、要求をキューに保存できます。

通訳者-言語が与えられたら、その表現を使用して言語の文を解釈するインタープリターとともに、文法の表現を定義します。

イテレータ-基礎となる表現を公開せずに、集合オブジェクトの要素に順番にアクセスする方法を提供します。

メディエーター-オブジェクトのセットが相互作用する方法をカプセル化するオブジェクトを定義します。メディエータは、オブジェクトが相互に明示的に参照しないようにすることで疎結合を促進し、相互作用を個別に変えることができます。

オブザーバー-オブジェクト間の1対多の依存関係を定義して、1つのオブジェクトの状態が変化したときに、そのすべての依存関係が自動的に通知および更新されるようにします。

戦略-アルゴリズムのファミリーを定義し、各アルゴリズムをカプセル化し、それらを交換可能にします。戦略により、アルゴリズムはそれを使用するクライアントとは独立して変化します。

テンプレートメソッド-操作でアルゴリズムのスケルトンを定義し、いくつかのステップをサブクラスに委ねます/テンプレートメソッドにより、サブクラスはアルゴリズムの構造を変更させずにアルゴリズムの特定のステップを再定義できます。

訪問者-オブジェクト構造の要素に対して実行される操作を表します。訪問者は、操作対象の要素のクラスを変更せずに新しい操作を定義できます。

Nullオブジェクト-指定されたタイプのオブジェクトがないことの代理としてオブジェクトを提供します。/Null Object Patternは、インテリジェントな「何もしない」動作を提供し、協力者から詳細を隠します。

構造設計パターン

アダプタ-クラスのインターフェイスを、クライアントが期待する別のインターフェイスに変換します。 /アダプタは、クラスが連携して動作するようにします。これは、互換性のないインターフェイスのためにそうでなければできませんでした。

ブリッジ-オブジェクトをツリー構造に構成して、部分全体の階層を表します。/Compositeを使用すると、クライアントは個々のオブジェクトとオブジェクトの構成を均一に処理できます。

複合-オブジェクトをツリー構造に構成して、部分全体の階層を表します。/Compositeを使用すると、クライアントは個々のオブジェクトとオブジェクトの構成を均一に処理できます。

デコレータ-オブジェクトに責任を動的に追加します。

フライウェイト-共有を使用して、状態の他の部分が変化する可能性がある内部状態の一部を共有する多数のオブジェクトをサポートします。

Memento-カプセル化に違反せずにオブジェクトの内部状態をキャプチャし、必要に応じてオブジェクトを初期状態に復元する手段を提供します。

プロキシ-オブジェクトへの参照を制御するオブジェクトの「プレースホルダー」を提供します。

7
Sauron

BlueJ とActiveWriterを使用して、オブジェクトについて学習し、理解を深めることをお勧めします。推奨される本は、素敵なリソースでもあります。

から ウィキペディア

alt text

BlueJはJavaプログラミング言語の統合開発環境であり、主に教育目的で開発されていますが、小規模なソフトウェア開発にも適しています。

さらに、UMLを使用しており、私にとっては、オブジェクトのモデリングに関するいくつかのことを理解するのに良いリソースでした。

代替テキストhttp://www.ryanknu.com/ryan/bluej.png

ActiveWriter は、エンティティと関係をモデル化するツールです。また、コードを生成し、簡単に変更できます。時間を節約でき、アジャイル開発には非常に適しています。

alt text
(ソース: altinoren.com

4
Nelson Miranda

引用するだけ http://www.fysh.org/~katie/computing/methodologies.txt

また、RUPの中核となるのは、OOデザインの才能を使用する必要がある小さな領域です。..持っていない場合は、100mを実行する方法論があるようなものです。

「ステップ1:非常に速く走ることについて書いてください。ステップ2:競馬場の計画を立ててください。ステップ3:とてもタイトなライクラショーツを買ってください。ステップ4:本当に、本当に、本当に速く走ってください。 」

難しいのはそのステップ4です。しかし、1、2、3、5に重点を置いた場合、誰も気付かない可能性があります。そして、100mの「秘密」があると思うアスリートになるように方法論を売って多分お金を稼ぐことができます。ランナーオーバー

4
martin

まず第一に-デザインはあなたの魂から来るべきです。あなたはすべての繊維でそれを感じなければなりません。私は通常、何かを始める前に2〜3か月間歩いています。通りを歩いているだけです(本当に)。そして考えます。ウォーキングは良い瞑想ですだから、あなたはよく集中することができます。

第二に-OOPとクラスを使用するのは、自然なオブジェクト階層が存在する場合のみです。人為的に「ねじ込み」しないでください。厳密な階層が存在しない場合(ほとんどのビジネスアプリケーションのように)-手続き型/機能を使用するか、少なくともオブジェクトを分離アクセサーを持つデータコンテナーとしてのみ使用します。

そして最後-これを読んでみてください: The Creative Algorithm of Creative Thinking

4
Thevs

多くの著者が本を書くために使用する質問をしました。方法論は多数ありますが、「最も美しい」方法を選択する必要があります。
Eric Evansの本 "Domain Driven Design" をお勧めします。また、サイト dddcommunity.org を確認してください。

4
zendar

ここでの答えは、尋ねる人の現実世界の経験に応じて、非常に異なるであるべきだと思います。

1年または2年の実務経験がある場合は、次のポイントに移動する必要があります:howあなたは本当にあなたのデータを知っており、あなたが何を正確に理解しているのかやり直しますか?

ええ、実世界で5年以上働いている場合は、多くのソフトウェア開発プロセスモデルまたは手法のいずれかを選択します。

しかし、本を読むだけでは経験が得られません。優れたリーダーシップの下で、優れたグループで働くことで学ぶべきです。

それが不可能な場合は、自分で行う必要があります。おそらく非常に厄介なコードをコーディングし、エラーを学習し、すべてをダンプし、より良いコードをコーディングするなどして、反復を開始します。

コードベースについて多くを学びます。ツールはツールであり、何も教えません。

3
IlDan

プロジェクトに関する専門知識をお持ちの場合は、銀行などの仕事をする予定です。オブジェクトを簡単に構成でき、それらの機能強化が1日おきにどのように行われるかを知っています。

その専門知識がない場合は、その専門知識を持っている人と協力して、それらのアイデアを技術的な詳細に変換します。

プロジェクト設計の構成方法について混乱している場合。 「実用的なプログラマー」の本に盲目的に従ってください。私は以前同じ状況にありました、その本から章を読んでみてください。違いがわかります。ソフトウェア開発者としての考え方が変わります。

3
Broken Link

テスト駆動設計(TDD)を使用しています。最初にテストを書くことは、実際にクリーンで正しい設計に導くのに役立ちます。 http://en.wikipedia.org/wiki/Test-driven_development を参照してください。

2
David Allen
  1. 研究とマスターデザインパターン。
  2. 次に、ドメイン駆動設計について学びます
  3. その後、要件収集を学習します

私は数学期前にOODコースを受講し、そこから多くのことを学びました。 UMLの作成、要件ドキュメントのオブジェクトやクラスへの翻訳など。私たちもシーケンス図を学びましたが、どういうわけか講義や何かを見逃しましたが、それらは本当に私に固執しませんでした。

  1. ステップ3については知っています。マスターする必要があります。つまり、多くの練習を経て、それがあなたの第二の自然になるようにしています。それは、あなたが学ぶ方法が、私たちがかつて持っていた方法に単純に反しているからです。だから、あなたは本当にそれをマスターする必要があります。そうしないと、元のやり方に戻ってしまいます。これは、テスト駆動プロセスのようなもので、多くのJava開発者が数回の試行後にそれをあきらめます。彼らが完全にマスターしない限り

  2. 特に代替コースのユースケースを作成します。代替コースは、開発時間の50%以上を占めています。通常、あなたのPMがタスクを割り当てたとき、たとえばログインシステムを作成したとき、彼はそれが簡単だと思うでしょう。しかし、彼はあなたが考慮しなければならないことを決して考慮に入れません。1。ユーザーキーが間違ったパスワードの場合、2。ユーザーキーが間違ったパスワードの場合、3回、3。あなたはそれらをリストし、あなたのPMにそれを見せ、期限を再スケジュールするよう彼に頼む必要があります。

2
janetsmith

これは答えではないのではないかと思います聞きたい人。とにかく、私の意見を述べさせてください。

OOPは、優れたパラダイムではなく、パラダイムの1つと見なされるべきです。 OOPは、GUIライブラリの開発など、特定の種類の問題を解決するのに適しています。また、通常は大規模なソフトウェア会社が従うソフトウェア開発のスタイルにも適合します。designersまたはarchitectsのエリートチームは、UML図または他の同様の媒体でソフトウェア設計を定めます。 developersのあまり知識のないチームが、その設計をソースコードに変換します。 OOPは、単独で、または非常に才能のあるプログラマーの小さなチームと一緒に作業している場合、ほとんど利点がありません。次に、複数のパラダイムをサポートし、プロトタイプを迅速に作成するのに役立つ言語を使用することをお勧めします。 Python、Ruby、LISP/Schemeなどが適切な選択です。プロトタイプがあなたのデザインです。次に、それを改善します。手元の問題を解決するのに最適なパラダイムを使用してください。必要に応じて、Cまたはその他のシステム言語で記述された拡張機能でホットスポットを最適化します。これらの言語のいずれかを使用すると、プログラマレベルだけでなくユーザーレベルでもextensibilityが無料で得られます。 LISPのような言語は、コードを動的に生成および実行できます。つまり、ユーザーは、ソフトウェア自体がコーディングされている言語で小さなコードスニペットを記述することにより、アプリケーションを拡張できます。または、プログラムをCまたはC++で作成することを選択した場合は、Luaのような小さな言語用のインタープリターを埋め込むことを検討してください。その言語で記述されたpluginsとして機能を公開します。

ほとんどの場合、OOPとOODは、過剰設計の犠牲となるソフトウェアを作成すると思います。

要約すると、ソフトウェアを書くための私の好ましい方法は次のとおりです。

  1. 動的言語を使用します。
  2. その言語自体でデザイン(プロトタイプ)を記述します。
  3. 必要に応じて、C/C++を使用して特定の領域を最適化します。
  4. 実装言語自体のインタープリターによって拡張性を提供します。

最後の機能により、ソフトウェアは特定のユーザー(自分を含む)の要件に簡単に適応できます。

2
Vijay Mathew

設計パターンを学ぶ。 OOPに関する過去2年間の個人的な革命でした。本を入手してください。これをお勧めします:

Head First Design Patterns

Javaにありますが、どの言語にも拡張可能です。

2
David Espart

正直なところ、良いステップは戻って、フローチャートとシーケンス図を見ることです。その方法を示す優れたサイトがたくさんあります。プログラムが入力、計算、および出力する必要があるものを正確に知っており、各ステップをプログラムの一部に分解できるので、プログラムをクラスに分解する方法を見ると非常に貴重です。

1
user133018
1
ChrisW

クラス構造を設計するという冒険の中で、疑似コードを書くことから始めるのが非常に役立つことに気付きました。つまり、アプリケーションのコードの一般的な断片を最高レベルで「記述」し、それで遊んで、表示されている要素、実際にはプログラマーとして使用したい要素を見つけます。モジュールの一般的な構造とそれらの相互作用を設計するための非常に良い出発点です。数回の反復の後、構造全体がクラスの完全なシステムのように見え始めます。コードの一部を設計するための非常に柔軟な方法です。それをプログラマー指向の設計と呼ぶことができます。

1
Darius

便利なテクニックの1つは、固有の問題の説明を実際の世界で見つけることができるものに関連付けることです。たとえば、世界を席巻する複雑な医療システムをモデリングしています。これをモデル化するためにすぐに呼び出すことができる例はありますか?

確かに。副薬局がどのように動作するか、または医師の部屋を観察します。

ドメインの問題を理解しやすいものに絞り込みます。あなたが関係できる何か。

次に、ドメイン内の「プレーヤー」が明白になり始め、コードのモデリングを開始したら、「プロバイダー-コンシューマー」モデリングアプローチを選択します。つまり、コードはモデルの「プロバイダー」であり、は「消費者」です。

ドメインに関連し、それを高レベルで理解することは、設計の重要な部分です。

1
Mike J