遅い答えですが、私は抵抗することはできません。
XのほとんどのクラスはYに適していますか、それともアンチパターンですか?
ほとんどの場合、ほとんどのルールは、何も考えずに適用されると、恐ろしく間違ったものになります(これを含む)。
意図的ではなく、必死になって起こった、すぐに正しくて汚い、手続き型のコードの混乱のなかでのオブジェクトの誕生についてお話ししましょう。
私のインターンと私はペアのプログラミングで、ウェブページをこするための使い捨てコードをすばやく作成しています。このコードが長く存続することを期待する理由は絶対にないので、機能するものを打ち出しています。ページ全体を文字列として取得し、必要なものをあなたが想像できる最も驚くほど壊れやすい方法で切り抜きます。判断しないでください。できます。
これを行っている間に、チョッピングを行うための静的メソッドをいくつか作成しました。私のインターンは、あなたに非常によく似たDTOクラスを作成しましたCatData
。
私が最初にDTOを見たとき、それは私を悩ませました。何年にもわたってJavaが私の脳に与えたダメージは、私が公共の場で反動する原因となりました。しかし、私たちはC#で作業していました。C#では、データを不変にしたり、後でカプセル化したりする権利を維持するために、時期尚早のゲッターやセッターは必要ありません。インターフェイスを変更せずに、いつでも追加できます。たぶん、ブレークポイントを設定できるようにするためです。クライアントにそれについて何も言わずに。いや、C#。Boo Java。
それで私は舌を抱えました。静的メソッドを使用して、使用する前にこれを初期化するのを見ました。私たちはそれらの約14を持っていました。醜いですが、気にする理由がありませんでした。
それから私たちは他の場所でそれを必要としました。コードをコピーして貼り付けたいと思っていました。14行の初期化が行われています。辛くなり始めていました。彼はためらってアイデアを求めました。
しぶしぶ「私は物を考えますか?」と尋ねました。
彼はDTOを振り返り、混乱して顔を台無しにしました。「オブジェクトです」。
「私は実際のオブジェクトを意味します」
「え?」
「何かお見せしましょう。役立つかどうかはあなたが決めます」
私は新しい名前を選び、すぐに次のようなものを作成しました。
public class Cat{
CatData(string catPage) {
this.catPage = catPage
}
private readonly string catPage;
public string name() { return chop("name prefix", "name suffix"); }
public string weight() { return chop("weight prefix", "weight suffix"); }
public string image() { return chop("image prefix", "image suffix"); }
private string chop(string prefix, string suffix) {
int start = catPage.indexOf(prefix) + prefix.Length;
int end = catPage.indexOf(suffix);
int length = end - start;
return catPage.Substring(start, length);
}
}
これは、静的メソッドがまだ実行していないことは何もしませんでした。しかし今、私は14の静的メソッドをクラスに吸い込んで、それらが作業しているデータと一緒にいる可能性があります。
私のインターンにそれを使わせることを強制しなかった 私はそれを提供し、静的メソッドを使い続けるかどうかを彼に決定させました。私は彼がおそらく彼がすでに働いていたものに固執すると思って家に帰りました。翌日、彼はそれをたくさんの場所で使用していたことがわかりました。それはまだ醜くて手続き的な残りのコードを整理しましたが、この少しの複雑さはオブジェクトの後ろに私たちから隠されました。もう少し良かったです。
これにアクセスするたびに、かなりの作業が行われていることを確認してください。DTOは高速でキャッシュされた値です。私はそれを心配しましたが、使用しているコードに一切手を触れることなく、必要に応じてキャッシュを追加できることに気付きました。気になるまで気にしません。
常にDTOよりもOOオブジェクトに固執する必要があると言っていますか?いいえ。メソッドの移動を妨げる境界を越える必要がある場合、DTOは優れています。DTOは自分の立場にあります。
しかし、OOオブジェクトもそうです。両方のツールの使用方法を学びます。それぞれの費用を学びましょう。問題、状況、およびインターンが決定することを学ぶ。ドグマはここではあなたの友達ではありません。
私の回答はすでに途方もなく長いので、コードのレビューでいくつかの誤解を誤解させます。
たとえば、クラスには通常、クラスのメンバーとメソッドがあります。例:
public class Cat{
private String name;
private int weight;
private Image image;
public void printInfo(){
System.out.println("Name:"+this.name+",weight:"+this.weight);
}
public void draw(){
//some draw code which uses this.image
}
}
あなたのコンストラクタはどこですか?これは、それが有用であるかどうかを知るのに十分ではありません。
しかし、単一責任の原則とオープンクローズの原則について読んだ後、クラスをDTOと静的メソッドのみのヘルパークラスに分離することを好みます。例:
public class CatData{
public String name;
public int weight;
public Image image;
}
public class CatMethods{
public static void printInfo(Cat cat){
System.out.println("Name:"+cat.name+",weight:"+cat.weight);
}
public static void draw(Cat cat){
//some draw code which uses cat.image
}
}
CatDataの責任はデータのみを保持することであり、メソッド(CatMethodsについても)を気にしないため、これは単一責任の原則に適していると思います。
単一責任原則の名の下に、多くの愚かなことができます。Cat StringsとCat Intは分離する必要があると主張できます。その描画メソッドと画像はすべて独自のクラスを持つ必要があります。実行中のプログラムは単一の責任であるため、クラスは1つだけにしてください。:P
私にとって、単一責任の原則に従う最善の方法は、ボックスに複雑さを入れて非表示にすることができる優れた抽象化を見つけることです。もしあなたがそれに良い名前を付けることができれば、人々が彼らの内部を見たときに彼らが見つけたものに驚かされないように、あなたはそれをかなりよくフォローしました。それがより多くの決定を命令するとそれが問題を求めていることを期待します。正直なところ、両方のコードリストがそうしているので、SRPがここで重要である理由はわかりません。
また、新しいメソッドを追加するときにCatDataクラスを変更する必要がないため、オープンクローズの原則にも適合します。
うーん、ダメ。オープンクローズの原則は、新しいメソッドを追加することではありません。古いメソッドの実装を変更でき、何も編集する必要がないということです。古い方法ではなく、あなたを使用するものはありません。代わりに、別の場所に新しいコードを記述します。ある種のポリモーフィズムがそれをうまく行います。ここには表示されません。
私の質問は、それは良いパターンですか、それともアンチパターンですか?
さて地獄どうやって私は知っておくべきですか?見てください、どちらの方法でもそれを行うことには利点とコストがあります。コードをデータから分離すると、もう一方を再コンパイルすることなく変更できます。多分それはあなたにとって非常に重要です。多分それはあなたのコードを無意味に複雑にするだけです。
それが気分が良くなれば、マーティンファウラーがパラメータオブジェクトと呼ぶものからそれほど遠くないでしょう。オブジェクトにプリミティブだけを取り込む必要はありません。
私にしてほしいのは、どちらのコーディングスタイルでも、分離する方法とそうでない方法を理解することです。信じられないかもしれませんが、スタイルを選択する必要はありません。あなたはただあなたの選択で生きなければなりません。