web-dev-qa-db-ja.com

貧血ドメインモデルがC#/ OOPでは悪いと考えられているが、F#/ FPでは非常に重要なのはなぜですか?

楽しさと利益のためにF#の ブログ投稿 で、それは言う:

機能設計では、動作をデータから分離することが非常に重要です。データ型は単純で「ダム」です。そして、個別に、これらのデータ型に作用する多数の関数があります。

これは、動作とデータを組み合わせることが意図されているオブジェクト指向設計の正反対です。結局のところ、それがまさにクラスです。実際、真にオブジェクト指向の設計では、振る舞いしかありません。データはプライベートであり、メソッドを介してのみアクセスできます。

実際、OODでは、データ型の周囲に十分な動作がないことは悪いことと見なされ、「 貧血ドメインモデル 」という名前さえ付いています。

C#では、F#から借用し続け、より機能的なスタイルのコードを記述しようとしているようです。データ/動作を分離するという考えを借りずに、悪いと考えているのはなぜですか?それは単に、定義がOOPに含まれていないということですか、それともC#で悪いという具体的な理由があり、何らかの理由でF#には当てはまらない(実際には逆になっている)のでしょうか。

(注:私は特に、ブログの投稿でどちらの意見にも反対する可能性のある個人ではなく、善悪の意見を変える可能性があるC#/ F#の違いに興味があります)。

49
Danny Tuppeny

主な理由FPがこれを目指しており、C#OOPがそうではないのは、FPが参照の透明性に焦点を当てているためです。つまり、データは関数に入り、データは出てきますが、元のデータは変更されません。

C#OOPには、オブジェクトの管理をオブジェクトに委任する責任の委任という概念があるため、オブジェクトの内部を変更する必要があります。

FPでは、オブジェクトの値を変更したくないので、オブジェクトに関数を埋め込んでも意味がありません。

さらにFPでは、より高い種類の多態性があり、C#OOPが許可するよりもはるかに一般化することができます。この方法で、任意のaであるため、データのブロックに埋め込むことは意味がありません。これは、メソッドを密結合して、特定のkindof a。そのような動作はすべてC#ではよくあり、一般的ですOOPとにかく関数を抽象化する機能がないため、 FPでは、トレードオフです。

C#の貧血ドメインモデルで見た最大の問題OOPは、DTO xがあるためにコードが重複してしまうことと、4のためにアクティビティfをDTO xにコミットする4つの異なる関数があることです。 DTO xにメソッドを直接配置すると、4人全員がfの実装を見て再利用します。

C#の貧血データモデルOOPはコードの再利用を妨げますが、FPの場合はそうではありません。単一の関数が非常に多くの異なる型にわたって一般化されているためです。その関数は、C#で単一のDTOに対して作成する関数よりもはるかに多くのシナリオで使用できるため、コードの再利用性が高まります。


コメントで指摘 のように、型推論は利点の1つですFPは、このような重要な多態性を許可することに依存しており、具体的には Hindley Milner アルゴリズムWの型推論を伴う型システム; C#でのそのような型推論OOP=型システムは、制約ベースの推論が追加されるときのコンパイル時間が非常に長くなるため、回避されました必要な徹底的な検索、詳細はこちら: https://stackoverflow.com/questions/3968834/generics-why-cant-the-compiler-infer-the-type-arguments-in-this-case

39
Jimmy Hoffa

貧血ドメインモデルがC#/ OOPでは悪いと考えられているが、F#/ FPでは非常に重要なのはなぜですか?

あなたの質問には、あなたが得る答えの有用性を制限する大きな問題があります:あなたはF#とFPが類似していることを示唆/仮定しています。 FPは、シンボリックな用語の書き換え、動的および静的を含む言語の巨大なファミリです。静的に型付けされたFP言語の間でも、OCamlやSMLの高次モジュール(F#には存在しない)などのドメインモデルを表現するためのさまざまなテクノロジーがあります。 F#はこれらの関数型言語の1つですが、無駄のないことは特に注目に値し、特に、高次のモジュールまたはより種類の高い型を提供していません。

実際、ドメインモデルがFPでどのように表現されているかを説明することはできませんでした。ここでのもう1つの回答は、Haskellでそれがどのように行われるかについて非常に具体的に述べており、LISP(すべてのFP言語の母)、言語のMLファミリ、またはその他の関数型言語にはまったく当てはまりません。

データ/動作を分離するという考えを借りずに、悪いと考えているのはなぜですか?

ジェネリックスは、データと動作を分離する方法と考えられるかもしれません。ジェネリックは関数型プログラミング言語のMLファミリーに由来し、OOPの一部ではありません。もちろん、C#にはジェネリックがあります。したがって、C#はデータと動作を分離するという考えをゆっくりと取り入れていると主張することができます。

単に定義がOOPに適合しないということですか、

OOPは根本的に異なる前提に基づいているため、データと動作を分離するために必要なツールを提供していないと思います。すべての実用的な目的のために、積と合計のデータ型が必要であり、それらをディスパッチします。 MLでは、これはユニオンとレコードタイプ、およびパターンマッチングを意味します。

チェックアウト ここで示した例

または、何らかの理由でF#には当てはまらない(そして実際には逆になっている)C#で悪いという具体的な理由はありますか?

OOPからC#へのジャンプには注意してください。 C#は、他の言語ほど純粋なOOPに近いものではありません。 .NET Frameworkには、ジェネリック、静的メソッド、さらにはラムダが満載です。

(注:私は特に、ブログの投稿でどちらの意見にも反対する可能性のある個人ではなく、善悪の意見を変える可能性があるC#/ F#の違いに興味があります)。

C#にはユニオンタイプとパターンマッチングがないため、ほとんど不可能です。あなたが持っているのはハンマーだけだと、すべてが釘のように見えます...

6
Jon Harrop