私は、自身の状態を変更する方法を知っているPlayerオブジェクトのような例を扱ってきました。
別の例は、アルゴリズムを使用して請求額を計算する方法を知っているInvoiceオブジェクトです。
これは単一責任の原則に違反していますか?
はいの場合、InvoiceCalculatorを作成することは、アルゴリズムを収容するための適切なアプローチですか?
そして、PlayerStateChangerは有効なものです。
「単一の責任の原則」は、その名前が混乱しているため、善よりも害を及ぼしているという結論に達しました。
原則はnotは、クラスが特定のことを1つだけ行うことを許可されるべきであると言います。それが事実なら、それは本当に愚かな原則でしょう!
その状態を変更する方法を知っているオブジェクトは完全に問題ありません-実際、多くの人はonlyオブジェクト自体がその状態を変更できるはずであると主張します。請求書料金を計算できる請求書オブジェクトもまったく問題なく聞こえます。
SRPは、独立して変化する可能性のある懸念を分離することに関するものです。自身をPDFandとしてレンダリングするためのロジックを含む請求書オブジェクトは、料金を計算するための原則を破るでしょう。請求書の外観とレイアウトは、料金計算のアルゴリズムとは関係なく変更される場合があります。
(ここでの「変更」とは、別の問題であるランタイム状態の変更ではなく、開発者にコードの変更を強制する要件の変更を指すことに注意してください。)
SRPは、分離を確実にするために、多数の小さなクラスを定義する道を進んでいく可能性があります。しかし、原則は対応するものとバランスを取る必要があります。つまり、doが一斉に変化するものが必要なものコードで結合されている。これは「低結合であるが凝集度が高い」と呼ばれます。
自分自身を変更できるデータオブジェクト(ドメインオブジェクト)を設計しないことをお勧めします。
私は次の区別をすることを好みます:
Player
、Invoice
。できれば不変ですが、アプリに依存します(たとえば、ゲームの場合、効率を上げるために可変オブジェクトが必要になる場合があります)InvoiceCalculator
またはBank
sに預金するAccount
オブジェクト利点:
上記で説明したのは、Martin Fowlerによって 貧血ドメインモデル として特徴付けられています。私はそれを懸念の分離と呼びます。
プログラミングはドグマではないので、「本当のOOPではない」と言われる可能性があることに落胆しないでください。 OOPは1つのパラダイムにすぎません-手続き型および機能型のものもあります。
2003年に記事が書かれたとき、マルチコアプログラムは今日ほど一般的ではありませんでした。現在はそうなっているので、データオブジェクトをシンプルで不変に保ち、他の場所でロジックを処理したいと思っています。
ソフトウェアには多くの利害関係者がいて、それらの利害関係者のそれぞれがソフトウェアの変更を要求する場合があります。
たとえば、請求アプリケーションには複数の利害関係者がいます。
単一責任原則の目的は、利害関係者Aから要求された変更を行うときに、利害関係者Bの何かにブレーキをかけるのを助けることです。単一責任は、各クラスが会社の1人(またはそれ以上)の役割のみに責任を負う必要があることを意味します。
あなたがやりたい最後のことは、別のdbスキーマに移行している間、または会計士があなたに求めたレポートのレイアウトを変更している間に、税の計算方法を壊すためにCOOを怒鳴らせることです。
ここで、特にこの例の請求書ケースの場合、BCEモデルでは、アプリケーションに依存しないロジックとアプリケーション固有のロジックを区別することをお勧めします。請求書は、ビジネス(別名ドメイン)オブジェクトです。このオブジェクトは、請求書を処理する必要がある社内の他のアプリケーションでも使用できます。 addItem()、removeItem()などのメソッドは、ユースケースにとらわれないため、ビジネスオブジェクトである請求書クラスに属します。現在、特定のユースケースに関するコードは、コントローラー(またはインタラクター)と呼ばれる別のクラスに属しています。料金の計算は、請求のユースケースの一部であり、おそらく別々に置くと思います。これらのルールはその1つのアプリケーションまたはユースケースに固有のものではないと主張することもできるため、これは主観的です。