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


46

ブログの記事楽しさと利益のためにF#上、それは言います:

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

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

実際、OODでは、データ型の周囲に十分な動作がないことは悪いことと見なされ、「貧血領域モデル」という名前さえあります

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

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


1
こんにちはダン!あなたの忠誠心はインスピレーションに満ちています。.NET(およびhaskell)プラットフォームに加えて、scalaをご覧になることをお勧めします。Debashishゴーシュは、あなたが行くの機能のツールを使用してドメインモデリングに関するブログのカップルは、それはここでは、あまりにもあなたのためにうまくいけば、私のための洞察に満ちた書いた:debasishg.blogspot.com/2012/01/...
AndreasScheinert

2
今日、同僚から興味深いブログ投稿が送られました: blog.inf.ed.ac.uk/sapm/2014/02/04/… 貧血ドメインモデルはまったく悪いという考えに挑戦し始めているようです。それは良いことだと思います!
ダニータッペニー14

1
参照するブログ投稿は、「通常、データをカプセル化せずに公開しても問題ありません。データは不変であるため、不正な動作によって「破損」することはありません」という誤った考えに基づいています。不変の型であっても、保存する必要のある不変式があり、データを非表示にして作成方法を制御する必要があります。たとえば、不変の赤黒ツリーの実装を公開することはできません。これは、誰かが赤いノードのみで構成されるツリーを作成できるためです。
ドーバル

4
@Dovalは、誰かがディスクをいっぱいにする可能性があるため、ファイルシステムライターを公開できないと言っているようなものです。赤ノードのみのツリーを作成した人は、クローン元の赤黒ツリーや、その整形式インスタンスを使用しているシステム全体のコードにまったくダメージを与えません。ガベージの新しいインスタンスを積極的に作成するコードや危険なことを行うコードを記述する場合、不変性はあなたを救うことはできませんが、他の人をあなたから救うでしょう。実装を非表示にしても、ゼロで除算されるナンセンスなコードを書くことはできません。
ジミー・ホッファ

2
@JimmyHoffa同意しますが、それは私が批判したこととは何の関係もありません。著者は、データは不変であるため、通常はデータを公開しても問題ないと主張し、不変性は実装の詳細を隠す必要性を魔法のように削除しないと言っています。
ドーバル

回答:


37

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

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

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

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

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

C#OOPの貧血データモデルはコードの再利用を妨げますが、FPの場合はそうではありません。1つの関数が非常に多くの異なるタイプにわたって一般化され、その関数は、 C#で1つのDTOを記述します。


以下のようなコメントで指摘し、型推論は、FPは、このような重要な多型を許可するに依存している利点の一つであり、具体的に、あなたはこのバックトレースすることができますヒンドリーミルナーのアルゴリズムW型推論と型システムを、C#OOP型システムでのこのような型推論は、徹底的な検索が必要なために制約ベースの推論が追加されるとコンパイル時間が非常に長くなるため、回避されました。詳細はこちら:https : //stackoverflow.com/questions/3968834/generics-why -この場合コンパイラの推論型引数をカント


F#のどの機能が、この種の再利用可能なコードの記述を容易にしますか?C#でコードを再利用できないのはなぜですか?(インターフェイスを必要とせずに、メソッドに特定のプロパティを持つ引数をとらせる能力を見たと思います。これは重要なものでしょうか?)
ダニータッペニー

7
@DannyTuppeny正直なところ、F#は比較のための貧弱な例であり、C#を少しドレスアップしただけです。C#のような可変命令型言語であり、C#にはないが多くはないFP機能がいくつかあります。haskellを見て、FPが本当に際立っている場所を確認し、型クラスと一般的なADTによりこのようなことがはるかに可能になります
ジミーホッファ

@MattFenwick明示的にC#を参照しているのは、それがポスターが求めていたものだからです。ここでの回答全体でOOPを参照する場合、C#OOPを意味します。明確にするために編集します。
ジミー・ホッファ

2
このタイプの再利用を可能にする関数型言語の共通機能は、動的型付けまたは推測型付けです。言語自体は明確に定義されたデータ型を使用する場合がありますが、それらに対して実行される操作(他の関数または算術演算)が有効である限り、一般的な関数はデータが何であるかを気にしません。これはオブジェクト指向のパラダイムでも利用可能です(たとえば、Goは、オブジェクトがDuckであると明示的に宣言されていなくてもFly、Swim、Quackできるため、オブジェクトをDuckにできる暗黙のインターフェイス実装を持っています)ほぼ関数型プログラミングの必要条件です。
キース

4
@KeithS Haskellの値ベースのオーバーロードによって、パターンマッチングを意味すると思います。異なるパターンを持つ同じ名前の複数のトップレベル関数を持つHas​​kellの機能は、すぐに1つのトップレベル関数+パターンマッチに脱糖します。
-jozefg

6

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では、これはユニオンとレコードタイプ、およびパターンマッチングを意味します。

私がここで与えた例をチェックしください。

または、C#で悪いのに、何らかの理由でF#に適用されない(実際には逆になる)という具体的な理由はありますか?

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

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

C#にはユニオン型とパターンマッチングがないため、ほとんど実行できません。あなたが持っているのはハンマーだけである場合、すべてが釘のように見えます...


2
...あなたが持っているのがハンマーだけである場合、OOPの人々はハンマーファクトリーを作成します; P +1は、C#に欠けているものの核心を実際に突き止めて、データと動作を互いに完全に抽象化できるようにします:ユニオンタイプとパターンマッチング。
ジミーホファ

-4

ビジネスアプリケーションでは、不変の値のパターンマッチングは、すべての可能なケースを確実にカバーするために優れているため、データを非表示にしたくないことが多いと思います。ただし、複雑なアルゴリズムまたはデータ構造を実装する場合は、実装の詳細を非表示にして、ADT(代数データ型)をADT(抽象データ型)に変換することをお勧めします。


4
これがオブジェクト指向プログラミングと関数型プログラミングにどのように適用されるかについてもう少し説明していただけますか?
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.