本の中でUML 2とArlowとNeustadtの統一プロセスは言われています:分析クラスは3から5の責任を持つべきです
しかし、あなたが知っているように、私たちは私たちに何か他のものを伝えるSRPを持っています!!
なぜそうなったのですか?よくわかりません
次の控除のうち、正しいものはどれですか。
ケース1-著者が責任の異なる定義を採用している
ケース2-採用された定義は同じで、実際にはそれらの目的は次のとおりです。分析クラスでは複数の責任を持つことができますが、SRPに関する設計段階では、分析クラスを1つの責任を持つ設計クラスに分割します。
私を助けてください
これらは少し異なる方法でこれらの用語を使用していますが、同様の基本的なアイデアを伝えようとしています。
あなたが参照した本からの引用は次のとおりです( emphasis mine):
ShoppingBasketの例に戻ると、このクラスには次のような責任があることが期待されます。
- バスケットにアイテムを追加します。
- バスケットからアイテムを取り出します。
- バスケット内のアイテムを表示します。
これは cohesive 一連の責任[...]です。すべての責任が同じ目標 [...]に向かって取り組んでいるため、まとまりがあります。実際、これらの3つの責任を「[バスケットの維持]」と呼ばれる非常に高レベルの責任として要約できます。
ここで、ShoppingBasketに[...その他の...]責任を追加することもできます[...]。しかし、これらの責任は、買い物かごの意図または直感的なセマンティクスには適合しないようです。 [...]各クラス内の結束を最大化するために、分析クラスに責任を適切に分散させることが重要です。
最後に、優れたクラスには、他のクラスへの最小量のカップリングがあります。
彼らは本質的に高い凝集性と低い結合を達成することについて話している-目標は、典型的な変更をローカライズし、影響を少なくすることです(たとえば、単一のクラスで、コードベース全体に広げるのではなく、無関係に見えるコードに変更をカスケードすることなく)。
したがって、彼らは、各クラスが1つの「高レベルの責任」を持つべきだと言っています。
SRPは 非常に類似した一連のアイデア をキャプチャします:
SRPは当初、ソフトウェアモジュールには1つの責任があるべきだと述べていました。ボブマーティンは後に、「責任」を「変更する理由」として明確にすることを決定しました。
すべての原則と同様に、それらの単一文のステートメントは、それらを覚えてそれらについて話すための本当にきちんとした方法です。しかし、それらを理解するには、それを超えて、基礎となるアイデアをもう少し掘り下げる必要があります。
ソフトウェア設計とその原則の主要なポイントは、変更により時間の経過とともに生じる複雑さをある程度制御できるようにすることです。コードが変更されなければ、デザインはそれほど重要ではありません。
どのドメインでも、変化を引き起こすものがあります。例えば。ソフトウェアが作成されているビジネスには、特定の機能が必要になる場合があります。しかし、企業には独自の方法があり、ソフトウェアがそれをサポートすることを望んでいます。 1人のユーザーセットに1つの機能セットが必要で、別のユーザーセット(別の部門のユーザーなど)に別の機能セットが必要な場合があります。彼らはすでに特定のビジネスプロセスを持っているかもしれず、ソフトウェアがその一部を自動化することを望んでいるかもしれません-そして、開発者チームがそれらのプロセス(彼らが物事を行う方法)と彼らのビジネス(なぜ彼らが物事を行う、彼らがどのように概念を考えるか)ソフトウェアは、必要な種類の変更を困難にするような方法で概念化および構造化/開発されます -コードは間違った抽象化のセットに基づいており(これらは変更するのが難しい)、したがって、間違った種類の方法で結合されます。考えられるすべての種類の変更をサポートするコードはありません。特定の種類の変更をサポートするようにして、他の種類の変更を固定します。デザインはトレードオフについてです。トリックは、これについて意識的/意図的であることです。
変化の方向を推進するこれらの要因は、「変化の力」または「変化の軸」と考えることができます。これらは、多くの場合、人々、組織、それらのポリシーや政治などによって推進されます。それが、人間がどこに、どのように登場するかです。マーティンの記事を引用するには:「whoプログラムの設計は応答する必要がありますか?」
アイデアは、最初に、これらの変化の軸のいくつかを認識するのに十分な領域を理解し、それを中心に設計することです。これは、一部はドメイン分析に基づいており、一部は経験に基づいています。ただし、この時点では過剰設計しないことが重要です。まだ十分に理解していないドメインの側面について、意識的に想定しないでください。
しかし、それだけではありません。アジャイル開発は反復的プロセスであるため、ドメインとシステムについて学習します。考慮しなかった変化の軸があることや、実際に変化を引き起こすことはほとんどないため、予想したものの一部はそれほど重要ではないことがわかります。または、いくつかの間違った仮定をしたこと、そして今それらはあなたに問題を与えること。この新しい知識に基づいて、コードをいつ、どこで、どのように再構成するかを、「最後の責任ある瞬間を待つ」方法で(結合と複雑さが制御不能になる前に)決定する必要があります。これが、YAGNIのようなヒューリスティックであり、「抽象化する前に何かの3つの例を待つか、DRY it up)」です。これを行うことは、コードベースのこれらの部分でより重要です時間の経過とともに最も変化しますが、他の部分ではそれほど変化しません。
ボブ・マーティンをもう一度引用するには( emphasis mine):
ソフトウェアモジュールを作成するとき、変更がリクエストされたときに、それらの変更が1人から、または 1つの狭く定義されたビジネスを表す1人の密結合グループからのみ発生できることを確認する必要があります。関数。組織全体の複雑さからモジュールを分離し、各モジュールがその1つのビジネス機能のみのニーズに対応(対応)するようにシステムを設計したいとします。
これが、SRPの「責任」をやや抽象的な方法で定義する必要がある理由です-あなたは、コードをクラス(または他の種類のコンポーネント)に分割して、開発中の特定のアプリケーション。
注意深く読んで分析すると、よくある誤解を見つけるのに役立ちます。おめでとう!
正しいケースは、1:作者は同じWordを非常に異なる定義で使用します:
私の見解では、ボブおじさんは 懸念の分離 がその目的であるため、彼の原則を曖昧さなく「単一懸念原則」と名付けたかもしれません。ボブおじさんが自分の記事で提案した別の表現は、責任をまったく言及することなくこれを明確にします:"同じ理由で変化するものを集めます。異なる理由で変化するものを分けてください]。
白熱した議論(客観的で文書化された回答に対するすでに2票)と他のいくつかの回答の推測を考慮して、いくつかの定義に戻りたいと思います。それが問題なのです。 =
質問はUMLから始まります。 UMLの創始者であり発明者であるGrady Booch、Ivar Jacobson、James Rumbaughは、統合ソフトウェア開発プロセスで1999を公開しています。
ページ48:クラスの責任は、すべてのユースケースの実現においてクラスが果たすすべての役割をまとめたものにすぎません。まとめると、役割間の重複を取り除いて、クラスのすべての責任と属性の仕様を取得します。
ページ182:分析クラス(...)の振る舞いは、より高い、より正式でないレベルでの責任によって定義されます。責任は、クラスによって定義された動作のまとまりのあるサブセットのテキストによる説明です。
別の非常に一般的に使用されている責任の定義は、アジャイル運動の2人の父親であるケントベックとワードカニンガムによって発明されたCRCカードと、1989年9月に発行された 公開9月 :
責任は、解決すべき問題を特定します。ソリューションは多くのバージョンと改良で存在します。責任は潜在的な解決策を議論するためのハンドルとして機能します。オブジェクトの責任は、それぞれがアクティブな動詞を含む少数の短い動詞句によって表されます。
ご覧のように、専門家の見解では、オブジェクトにそのような責任がいくつかある場合があります。この記事は、 September 1989 にも掲載されているWirfs-Brockの記事を明示的に参照していることに注意してください。
レベッカは契約との類比によって責任を定義しました:
それは尋ねることによって契約に焦点を合わせます:
- このオブジェクトはどのようなアクションを担当しますか?
- このオブジェクトはどのような情報を共有しますか?
繰り返しになりますが、オブジェクトには当然いくつかの責任があります。彼女はさらに、これらの責任の一部が他のオブジェクトに委任される可能性があることを説明しました。
Wirfs-Brockの責任の概念を使用している他の著者の中には、たとえば、優れたソフトウェア設計のリファレンスである GoF があります。本のすべてのパターンについて、リストまたは参加者とその責任、およびこれらの参加者間のコラボレーションについて説明します。具体的なデコレータの説明を例にとります(私は複数を強調表示しました):
- responsibilitiesをコンポーネントに追加します
さて、もう一方の側には、それぞれのオブジェクトが単一の責任を持つべきだと主張する1人の著者がいます。これは、他のすべての著者の仮定と矛盾しています。私が回答の冒頭で引用したボブおじさんの記事を見ると、彼自身が責任を定義するときに「変更する理由」は他のすべての著者とはまったく異なる定義であることは明らかです。
コメントの中で、ボブおじさんが実際に何を意味していたかについての私の解釈に同意しない人もいます。私はこれを受け入れます:私はR.Cにいません。マーティンの頭と私の解釈は推測です。他の解釈も。しかし、客観的には、ボブおじさんの定義が他のすべてのものと(非常に)異なっていることを否定することはできません。したがって、ケース1です。他の解釈はすべて純粋な推測です。
クラスの責任について複数の定義がありますか?
要するに、はい。これはほとんどの単語に当てはまり、論理科学はその命名法についてはるかに厳密になる傾向がありますが、あいまいなネーミングもあります。あなたはそれらの1つにつまずきました。
責任はさまざまな粒度で定義できます。ウェイターとクックは2つの別々の責任であると言えます。または、ハンバーガークックからオムレツクックをさらに細分化し、それらを個別の責任と見なすこともできます。十分な大きさのキッチンの場合は、卵を割ってオムレツを調理することを別の責任として検討することもできます。
ここで重要なのは、責任と見なされるものの境界(粒度)です。異なるシナリオ(たとえば、家族経営のレストランと工業用キッチン)では、異なるアプローチが好まれます。
分析クラスには3〜5の責任が必要です
私はあなたが持っている本にアクセスできませんが、これは CRCモデリングアプローチ に基づいているようです。ここでは、「責任」がクラスの存在理由の説明に使用されているのではなく、特定のクラスの特定の動作が使用されていることがわかります。
クラスは類似したオブジェクトのコレクションを表し、責任はクラスが知っているまたは行うものであり、コラボレーターはクラスが対話する別のクラスですその責任を果たします。
含まれている画像を見てください。 CRCモデルによると、顧客には5つの責任があり、注文には6つの責任があります。
しかし、あなたが知っているように、私たちは私たちに何か他のものを告げる基本的なSRPを持っています!!
ここでボブおじさんの「責任」の定義が分かれる。ボブおじさんの責任の定義は、クラスの特定の動作にラベルを付けるのではなく、クラス自体にラベルを付けます。ボブおじさんによると、顧客には1つの責任(発注者を特定する)と1つの責任(注文情報を含む)としての注文があります。
同じことですが、説明が異なります。
あなたにとって重要なことを考えてください。あなたのアプリケーションは、すべての料理人がすべての料理を作ることができると考えていますか?あなたのアプリケーションは、各料理人が特定の専門知識を持つことができると期待していますか?これらの種類の考慮事項により、適切なレベルで責任を定義することができます。つまり、シナリオに意味があるほど細かく、それ以上ではありません。
私はその本を読みませんでしたが、「UML」「分析クラス」を聞いたとき、ビジネスアナリストが要件モデリングに使用しているクラスを思い浮かべます。完全に間違っています。コメントを残してください。答えを削除します)。
私は自由を取り、クリストファーによってすでに言及された そのブログ記事 から例を引用します:
要件分析中、UMLダイアグラムでこのようなクラスを使用しても問題ありません。したがって、これは有効な「分析クラス」です。
すでにこのレベルの抽象化でSRPを適用すると、多くの場合、1つのメソッドだけで多くのクラスが作成され、クラス名とメソッド名に違いがないため、見かけ上の値がありません。
しかし、Robert MartinがSRPについて語るとき、これらの要件が実装されるときにコードで実際に発生するクラスの種類をIMHOに持っています。上記の「分析クラス」は、ボブマリンがSRPを適用した後のコードにはおそらくないものです。
代わりに、私は彼のコードでクラスを見つけることを期待します
paymentCalculatorクラス
時間をERPシステムに報告するための複数のクラスのセット全体
従業員データをデータベースに保存するためのクラスEmployeeRepository
、インターフェースIEmployeeRepository
、およびおそらくテスト用のモック実装
データを保持するための唯一のEmployeeクラス(およびそのクラスのデータメンバー以外は何も必要としない再利用可能なメンバー関数)。
マーティンの記事は、システムのmaintenanceとevolvementを許可するために、これらの異なる責任をクラスに分けることが良いアイデアである理由をよく説明しています。変更を後で実装する必要がある場合に、物事を壊すリスクが低くなります。これが、SRPが最も理にかなった場所です。
要するに、
要件分析中にUMLを使用する場合、SRP(Bob Martinの意味で)はそれほど重要ではなく、逆効果になることもあります。
設計フェーズで責任を分離することは理にかなっている
しかし、最も理にかなっているのは、既存のクラスにコードを追加し、いくつかの責任を追加した後、コードをリファクタリングしてクラスを分離し、保守しやすい状態にすることです。
これがあなたの質問のコメントで私が意味したことであり、「ケース2」が正しい答えだと思うのはなぜですか。しかし、私はあなたの本を持っていないので、著者が別のことを意味し、ケース1も当てはまる可能性は十分にありますが、それは必要な説明ではありません。