[〜#〜] edit [〜#〜]2017/02/13- repo を確認する。最初の例は、[〜#〜] srp [〜#〜]を考慮して解決していますが、後で[〜#〜 ] solid [〜#〜]..私はそれをもっとよく説明すべきだった。
私は違反とSR原則の解決方法の良い例を見つけようとしています。しかし、それが良いことであり、意味のないことを書き留めていないことを確認したいので、どんな入力も歓迎します。私はこれを自分自身に教え、SOLID=より良いの "S"を理論と例によって理解します。
次に例を示します。 https://github.com/learnasyougo/S.O.L.I.D#single-responsibility-principle -以下を参照として使用します。
クラスの変更理由は1つだけです。
クラスPerson
は、人物に関連するデータを保持する責任があります。また、この人物データを指定された形式に出力する関数Format
も保持します。現在、このメソッドは、関数が使用するアルゴリズムを決定するパラメーターを受け入れ、必要な形式でデータを返します。
以下の例violates単一責任の原則クラスPerson
は現在、人物のデータを保持する責任があるためandフォーマットそのデータ。
class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
public DateTime DateOfBirth { get; set; }
public string Format(string formatType) {
switch(formatType) {
case "JSON":
// implement JSON formatting here
return jsonFormattedString;
break;
case "FirstAndLastName":
// implementation of first & lastname formatting here
return firstAndLastNameString;
break;
default:
// implementation of default formatting
return defaultFormattedString;
}
}
}
これを解決するには、クラスPerson
がデータの保持のみを担当し、データのフォーマットは担当しないようにします。したがって、メソッドFormat
を抽出し、本のフォーマットを担当する別のクラスを紹介します。
class PersonFormatter {
public string Format(Person person, string formatType) {
switch(formatType) {
case "JSON":
// implement JSON formatting here
return jsonFormattedString;
break;
case "FirstAndLastName":
// implementation of first & lastname formatting here
return firstAndLastNameString;
break;
default:
// implementation of default formatting
return defaultFormattedString;
}
}
}
class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
public DateTime DateOfBirth { get; set; }
}
この例は[〜#〜] solid [〜#〜]に対してviolationsを保持していると主張できますが、それは事実です。 format
メソッド自体は、どのようにフォーマットされているかについての詳細を実装しなければならないため、依然として責任が多すぎます。後で、他の1つ以上の原則を使用してこれを解決します。つまり、依存関係の逆転原則とインターフェイスセグメンテーション原則です。しかし、少なくとも今では、SRPが述べるように、Personクラス自体に影響を与えることなく、Personのフォーマットの実装を変更できます。
まず、文字列引数を使用して必要な形式のタイプを決定しないでください。残りの形式が悪くなり、コンパイラーがキャッチできないエラーが発生しやすくなります。
次に、データを保持するオブジェクトがそれ自体をフォーマットできることに問題はありません。コードの残りの部分では、オブジェクトがどのメンバーに属しているかを心配する必要がないのが理想的です。ミドルネームを追加したからといって、100か所を変更する必要はありません。
第三に、これは単一の責任が関係する場所であり、個人のインスタンスはjson自体の方法を知らないはずです。それはそれ自体が情報(名、姓など)で呼び出すことができる何かを知っているだけで、すべてをjsonに変換します。フィールド名と値のコレクションを作成し、それをjson作成者に渡す必要がある場合があります。
ブラケットやデリミタなどを追加するjson自体に必要なときに、どのクラスでも使用できる一般的なクラスを作成します。
また、一般的なフォーマットメソッド内にすべてのロジックを含めるのではなく、それをタイプごとにメソッドに分割し、一般的なフォーマットメソッドからそれらを呼び出す必要があります。
私は「うーん」と思う前に「人」という言葉までしか読みませんでした。広範なエンティティクラスは、重要なシステムでは、最終的にSRPに違反します。
多くの教科書には、エンティティをモデル化しようとするクラスの例が示されています。IMOの場合、実際には狭い範囲の動作をモデル化する必要があります。たとえばPOCOを例に取ると、「人」を表すように定義されている可能性がありますが、実際には、彼らにとって意味のある非常に限られた範囲の動作があります。彼らは人ができるすべてを行うことができるように定義されていません。
それは極端な例ですが、原則は依然として適切です。クラスは、それらが何であるかによって広くはないものによって狭く定義されるべきです。つまり、SRPの良い面にとどまる方法です。
クラスPersonは、その人のデータを保持し、そのデータをフォーマットする責任があります。
OOPの特徴は、データを動作と結び付けることです。クラスへのアクセサをデータに保持することのみを目的とする場合、あなたが持っているものは 貧血ドメインモデル です。 。貧血クラスはオブジェクトではなくデータ構造であるため、実際にOOPをデータと行動から分離するときは書いていません。優れたオブジェクトはデータを隠し、動作のみを公開します。
データ構造と手続き型コードがOOPを備えた実際のオブジェクトよりも全体的に優れたソリューションになる場合がある理由はたくさんありますが、貧弱なオブジェクトは基本的にOOPと矛盾します。
SRPに関しては、PersonFormatterはまだ多くを行います。 PersonFormatterはJSON、プレーン名などのフォーマットを行います。私が提案するのは、複数の実装を持つIPersonFormatterインターフェイスを定義することです。
interface IPersonFormatter {
public string Format(Person person);
}
class JSONPersonFormatter : IPersonFormatter {
...
}
class TemplateStringPersonFormatter : IPersonFormatter {
public TemplateStringPersonFormatter(String fmtString) {
...
}
...
}
国際化の注意:多くの人はテンプレートに合わない名前を持っています。