流暢なインターフェイスはデメテルの法則に違反しますか?
-
09-06-2019 - |
質問
の ウィキペディアの記事 について デメテルの法則 言います:
この法則を簡単に言うと、「ドットは 1 つだけ使用する」というものです。
しかし、 簡単な例 の 流暢なインターフェース 次のようになります:
static void Main(string[] args)
{
new ZRLabs.Yael.Pipeline("cat.jpg")
.Rotate(90)
.Watermark("Monkey")
.RoundCorners(100, Color.Bisque)
.Save("test.png");
}
それで、これは一緒ですか?
解決
そうですね、法律の定義を短くすると、短くなりすぎます。本当の「法則」(実際には、優れた API 設計に関するアドバイス)は基本的に次のように述べています。自分で作成したオブジェクト、または引数として渡されたオブジェクトのみにアクセスしてください。他のオブジェクトを通じて間接的にオブジェクトにアクセスしないでください。流暢なインターフェイスのメソッドはオブジェクト自体を返すことが多いため、そのオブジェクトを再度使用しても法律に違反しません。他のメソッドはオブジェクトを作成するため、違反はありません。
また、「法則」は「古典的な」API に対するベスト プラクティスのアドバイスにすぎないことにも注意してください。Fluent インターフェイスは API 設計に対するまったく異なるアプローチであり、デメテルの法則では評価できません。
他のヒント
必ずしも。「ドットは 1 つだけ使用する」というのは、デメテルの法則の不正確な要約です。
デメテルの法則は、各ドットが異なるオブジェクトの結果を表す場合、複数のドットの使用を妨げます。例:
- 最初のドットは ObjectA から呼び出されるメソッドで、ObjectB 型のオブジェクトを返します。
- 次のドットは、ObjectB でのみ使用可能なメソッドで、ObjectC 型のオブジェクトを返します。
- 次のドットは ObjectC でのみ使用できるプロパティです
- 無限に
ただし、少なくとも私の意見では、各ドットの戻りオブジェクトが元の呼び出し元と同じ型である場合は、デメテルの法則に違反していません。
var List<SomeObj> list = new List<SomeObj>();
//initialize data here
return list.FindAll( i => i == someValue ).Sort( i1, i2 => i2 > i1).ToArray();
上記の例では、FindAll() と Sort() の両方が元のリストと同じタイプのオブジェクトを返します。デメテルの法則は違反されていません。リストは直接の友人とのみ会話しました。
そうは言っても すべてではない 流暢なインターフェイスは、呼び出し元と同じ型を返す限り、デメテルの法則に違反します。
はい、ただし、状況にある程度の現実主義を適用する必要があります。私は常にデメテルの法則をルールではなくガイドラインとして捉えています。
確かに、次のことは避けたほうがよいでしょう。
CurrentCustomer.Orders[0].Manufacturer.Address.Email(text);
おそらく次のように置き換えます。
CurrentCustomer.Orders[0].EmailManufacturer(text);
一般にドメイン全体をオブジェクト グラフとして表す ORM を使用する人が増えるにつれ、特定のオブジェクトに対して許容可能な「スコープ」を定義することが考えられるかもしれません。おそらく、デメテルの法則を利用して、グラフ全体を到達可能としてマップすべきではないことを示唆する必要があります。
デメテルの法則の精神は、オブジェクト参照またはクラスが与えられた場合、複数のサブプロパティまたはメソッドから離れたクラスのプロパティへのアクセスは避けるべきであるということです。アクセスすると 2 つのクラスが緊密に結合され、意図しない可能性があり、問題が発生する可能性があります。保守性の問題。
滑らかなインターフェイスは、法律の例外として許容されます。 意味 すべてのプロパティとメソッドは、一緒に構成されて機能的な文を形成するミニ言語の用語であるため、少なくともある程度緊密に結合されている必要があります。
1)全く違反していない。
コードは次と同等です
var a = new ZRLabs.Yael.Pipeline("cat.jpg");
a = a.Rotate(90);
a = a.Watermark("Monkey");
a = a.RoundCorners(100, Color.Bisque);
a = a.Save("test.png");
2) 古き良きフィル・ハークの言葉: デメテルの法則は点を数える練習ではありません
あなたの例では問題ありません。結局のところ、回転したり透かしを入れたりしているのです...いつも同じイメージ。その間、あなたは常に Pipeline オブジェクトと通信していると思います。そのため、コードが Pipeline のクラスにのみ依存している限り、LoD には違反していません。