データクラスがコード臭と見なされるのはなぜですか?


18

この記事では、データクラスは「コード臭」であると主張しています。理由:

新しく作成されたクラスに含まれるパブリックフィールドが少数(そしておそらく少数のゲッター/セッターさえ)である場合、これは通常のことです。しかし、オブジェクトの真の力は、データに動作タイプまたは操作を含めることができることです。

オブジェクトにデータのみが含まれているのはなぜ間違っているのですか?クラスの中心的な責任がデータを表すことである場合、データを操作するメソッドを追加して単一責任原則を破らないでしょうか?


1
これは、言語機能に強く依存します。たとえば、Pythonでは、PythonでJavaを作成するために邪魔にならない限り、「フィールド」とそのアクセッサに違いはありません。
jscs 16

1
私は、それ自体コードのにおいはありませんが、ほとんどのクラスは、そのようにしているならば、私たちは「貧血ドメイン」について話しているアンチパターン、一部のデータのみのクラスを持つと思いますen.wikipedia.org/wiki/Anemic_domain_model
Tulainsコルドバ

1
この質問がどのように重複しているのかわかりません。他の質問は、オブジェクト指向でのデータクラスの使用に関するものですが、これはデータクラスの欠点-完全に異なる主題に関するものです。
ミロスMrdovic

リッチドメインモデルの劣等性を仮定し、実証済みの事実のように提示する、ここで上位に選ばれた回答よりもはるかに差別化されているstackoverflowでこの回答を読むことができます。stackoverflow.com/questions/23314330/...
McLovin

回答:


30

純粋なデータオブジェクトを持つことには、まったく問題はありません。作品の作者は率直に言って、彼が何について話しているのか分からない。

このような考え方は、「真のオブジェクト指向」がプログラミングの最良の方法であり、「真のオブジェクト指向」はすべてデータと機能が混在する「リッチデータモデル」に関する古い失敗したアイデアに由来します。

現実は、特にマルチスレッドソリューションのこの世界では、実際には逆のことが当てはまることを示しています。不変のデータオブジェクトと組み合わせた純粋な関数は、明らかにコード化するためのより良い方法です。


1
純粋なデータオブジェクトは、関係のモデリング、検証、アクセス/変更の制御に非常に貴重なものになる可能性があることを追加したかっただけです。
エイドリアン

2
不変のデータオブジェクトのインスタンスのみを引数として取る純粋な関数が、データオブジェクトのメソッドとして実装されていると便利です。
RemcoGerlich 16

7
関数がそのデータ型の引数を取る場合、データに既に結合されています。
RemcoGerlich

4
これが間違っているか、せいぜい意見の問題であるため、ダウン投票。オブジェクト指向言語では、通常、オブジェクトにデータ(まだ不変な可能性があります!)とそれに作用するメソッドの両方を含めるのが理にかなっています。他の言語のパラダイムでは、純粋な関数と個別のデータが優れていますが、OOを実行している場合は、OOを完全に実行してください。
Marnen Laibow-Koser

3
現実には多くのことが示されています。独断的な「すべてが他の人が失敗した」という意見に対しては-1。また、著者は、純粋なデータオブジェクトが「間違っている」と言っているのではなく、「コードのにおい」であり、疑問に値するだけだと言っています。私は私の国に与えるために1つの下票を持っていることをただ後悔しています。:-)
user949300

7

純粋なデータオブジェクトを持つことには、まったく問題はありません。著者は、私が知っているソフトウェア開発者と共有していない意見を持っています。

特にデータベースマッピングでは、一般に、データベースに格納されたフィールドとゲッターとセッターのみを含むエンティティクラスがあります。ウィキペディアHibernate(フレームワーク)

多くのツール/フレームワークで使用されるJava Beanの穴のアイデアは、フィールドと関連するゲッターとセッターのみを含むBeanと呼ばれるデータクラスに基づいています。Wikipdia JavaBeans

ファジット:
誰かが何かが「悪い」または「コードのにおい」であると主張する場合、あなたは常に与えられた理由を探すべきです。理由が納得できない場合は、他の誰かにもっと良い理由や別の意見を求めてください。(このフォーラムでやったように)


著者は、純粋なデータオブジェクトが「間違っている」とは言いません。彼らは、純粋なデータオブジェクトは「コードの匂い」であると言います。つまり、それらを使用することについてもう一度考えるべきだということです。
user949300

1
@ user949300、あなたは混乱しているようです。作者がそれらをコードの匂いと呼ぶ場合、彼はそれらに何か問題があるかもしれないことを示します。最近では非常に良い習慣として広く認識されているため、明らかにコードの匂いではありません。したがって、MrSmith42は正しいです:彼らには全く何も悪いことはありません。
デビッドアルノ

4

マーティン・ファウラーによる正当な理由:

「Tell-Don't-Ask」は、オブジェクト指向とは、データを操作する機能とデータを結び付けることであることを人々が思い出すのに役立つ原則です。代わりに、オブジェクトに何をすべきかを伝える必要があります。これにより、データに合わせて動作をオブジェクトに移動することが推奨されます。

https://martinfowler.com/bliki/TellDontAsk.html


1
ここでの問題は、Fowlerが、関数をより広いスコープの要求からオブジェクトスコープの要求に変更することにより、人工的に "tell do n't ask"を制限することです。彼らはまだ尋ねています。実際には、引数リストを介してこれらの関数に真に伝えることで、「聞かないで」をさらに一歩進めることができます。そのため、データオブジェクトと、個別に(データに関して)関数が「tell do n't ask」の真の実装であることに到達します。そのため、データクラスはコードの匂いであるという主張の良い議論ではなく、実際には逆のことがさらに証明されています。
デビッドアルノ

2
@DavidArnoカプセル化と非表示を忘れています。オブジェクトにメンバーメソッドを実行するように指示すると、メンバーメソッドはオブジェクトのブラックボックスに入り、答えを得るために必要なことをすべて実行します。外部からオブジェクトを要求する場合、プライベート状態にアクセスできないため、オブジェクトが賢明な状態よりも多くの状態を公開するか、アスカーが必要以上にフープをジャンプする必要があります。オブジェクト指向環境でオブジェクトを「尋ねる」理由がわかりません。(もちろん、他のプログラミングパラダイムでは異なるアプローチが必要になる場合があります。)
Marnen Laibow-Koser

2
@DavidArnoもちろん、静的メソッドにパラメーターとして渡すことができますbaz、それを行うには、最初にオブジェクトを要求する必要があります。おそらくメソッドがプライマリであるプログラミングパラダイム(関数型プログラミングなど)ではこれは理にかなっていますが、オブジェクト指向環境ではオブジェクトはプライマリであり、それに作用するデータと関数の両方を含む必要があるため、絶対に意味がありません。オブジェクトからメソッドを削除するとカプセル化が増加するという主張も、私が知る限りではまったく逆ですbaz。これは、オブジェクトの外側に現れていることを意味しているためです。
Marnen Laibow-Koser

1
@ MarnenLaibow-Koser、私は「OOをしている」と主張していません。私はコードを書き、そのために優れたテクニックを使用しています。それらの技術が機能的パラダイムから来たのか、オブジェクト指向パラダイムから来たのか、それとも誰が​​パラダイムを与えたのかは、私には興味がありません。パラダイムを選択し、可能な限り完全にそれに従うことは、純粋な教義です。悪いです。馬鹿馬鹿しい。それはあなたを窒息させ、劣ったコードをもたらします。しないでください。
デビッドアルノ

1
@DavidArnoそれどころか、パラダイム(オブジェクト指向だけでなく、適切なパラダイム)に完全にコミットすると、強力で高レベルの抽象化と論理的に一貫した保守可能なコードが得られます。私はこれを独断的だと言っているのではなく、むしろ実用的だと言っています。私は、あなたが使用しているシステムの論理的な一貫性に著者が実際にコミットしなかった、あなたのような態度で作成されたと思われるコードをあまりにも多く見て、維持しました。理解するのも、維持するのも、修正するのも難しいです。完璧なパラダイムはありませんが、一般に混合物(慎重に検討しない限り)は理解しにくいです。
Marnen Laibow-Koser

2

理解する必要があるのは、2種類のオブジェクトがあるということです。

  • 動作するオブジェクト。これらは、ほとんど/すべてのデータメンバーへのパブリックアクセスを許可しないでください。これらに対して定義されているアクセサメソッドはごくわずかです。

    例はコンパイルされた正規表現です:オブジェクトは特定の動作を提供するために作成されます(特定の正規表現と文字列を一致させ、(部分的な)一致を報告します)が、コンパイルされた正規表現がどのように動作するはユーザーのビジネス。

    私が書くほとんどのクラスはこのカテゴリに属します。

  • 実際には単なるデータであるオブジェクト。これらは、すべてのメンバーをパブリックに宣言するだけです(または、アクセサーの完全なセットを提供します)。

    例はクラスPoint2Dです。このクラスのメンバーに確保する必要のある不変条件はまったくありません。また、ユーザーはとを介してデータにアクセスできる必要がmyPoint.xありmyPoint.yます。

    個人的に、私はそのようなクラスをあまり使用しませんが、どこかにそのようなクラスを使用しない、私が書いたコードの大きな部分はないと思います。

オブジェクト指向に習熟することには、この区別が存在することを理解し、クラスの機能をこれら2つのカテゴリのいずれかに分類することを学ぶことが含まれます。


C ++でコーディングする場合class、オブジェクトの最初のカテゴリとstruct2番目のカテゴリに使用することで、この区別を明確にすることができます。もちろん、この2つは同等classですが、デフォルトではすべてのメンバーがプライベートであり、デフォルトではstructすべてのメンバーがパブリックであると宣言されます。まさにあなたが伝えたい情報の種類です。


1
downvoteの説明はクールです...
cmaster-モニカを

答えてくれてありがとう。人々が理由なく投票するとき、私はそれを嫌います。回答に問題がある場合は、その理由を説明してください
Sipo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.