24

私は主に Java に興味がありますが、それは一般的な質問だと思います。最近、私はShrinkWrap多くのメソッドチェーンを使用する Arquillian フレームワーク ( ) を使用しています。メソッド連鎖の他の例は、 、 のメソッドStringBuilderですStringBuffer。このアプローチを使用することには明らかな利点があります。冗長性の削減はその 1 つです。

今私が疑問に思っていたのは、void戻りパラメーターを持つすべてのメソッドがチェーン可能として実装されていないのはなぜですか? 連鎖には、明らかで客観的な欠点がいくつかあるはずです。すべてのメソッドがチェーン可能である場合でも、使用しないことを選択できるからです。

Java の既存のコードを変更することを求めているわけではありません。これにより、どこかで何かが壊れる可能性がありますが、なぜそれが使用されなかったのかについても説明してください。私は、将来のフレームワーク (Java で書かれた) 設計の観点からより多くを求めています。


私は同様の質問を見つけましたが、元の質問者は実際になぜそれが良い習慣と見なされるのか疑問に思っています:メソッドチェーン - なぜそれが良い習慣なのか、そうでないのか?


利用可能ないくつかの回答がありますが、連鎖のすべての利点と欠点は何か、およびすべての void メソッドを連鎖可能にすることが有用であると見なされるかどうかはまだわかりません。

4

9 に答える 9

26

欠点

  • 主に署名を混乱させます。何かが新しいインスタンスを返した場合、それがミューテーターメソッドでもあるとは思いません。たとえば、ベクトルにスケール メソッドがあり、リターンがある場合は、入力によってスケーリングされた新しいベクトルを返すと推測します。そうでない場合は、内部的にスケーリングすると予想します。
  • さらに、クラスが拡張されている場合はもちろん、連鎖の途中でオブジェクトがスーパータイプにキャストされる場合に問題が発生します。これは、連鎖メソッドが親クラスで宣言されているが、子クラスのインスタンスで使用されている場合に発生します。

利点

  • 複数の中間オブジェクトを必要とせずに(不必要なオーバーヘッドにつながる)、数式スタイルのコードを完全な方程式として記述することができます。

    MyVector3d tripleCrossProduct=(vector1.multiply(vector2)).multiply(vector3);
    

    これには、作成してガベージ コレクションを行わなければならない中間オブジェクトが作成されるという欠点があります。

    MyVector3d tripleCrossProduct=vector1;
    tripleCrossProduct.multiplyLocal(vec2);
    tripleCrossProduct.multiplyLocal(vec3);
    

    これは中間オブジェクトの作成を回避しますが、非常に不明確ですが、変数名tripleCrossProductは実際には 3 行目まで嘘です。ただし、メソッド チェーンがある場合、不要な中間オブジェクトを作成することなく、通常の数学的な方法で簡潔に記述できます。

    MyVector3d tripleCrossProduct=vector1.multiplyLocal(vector2).multiplyLocal(vector3);
    

    これはすべて、 vector1 が犠牲的であり、二度と使用する必要がないことを前提としています

  • そしてもちろん明らかな利点です。簡潔。上記の例のマナーで操作がリンクされていなくても、オブジェクトへの不要な参照を回避できます

    SomeObject someObject=new SomeObject();
    someObject
      .someOperation()
      .someOtherOperation();
    

NBMyVector3dは Java の実際のクラスとしては使用されていませんが、.multiply()メソッドが呼び出されたときにクロス積を実行すると想定されています。 ベクトル計算に精通.cross()していない人にとって「意図」がより明確になるように、 は使用されていません。

于 2013-06-07T09:04:21.990 に答える
24

メソッドチェーンは、プログラミング言語に関係なく流暢なインターフェースを実装する方法です。その主な利点 (読み取り可能なコード) は、いつ使用するかを正確に示します。読み取り可能なコードが特に必要ない場合は、API がメソッド呼び出しの結果としてコンテキスト/オブジェクトを返すように自然に設計されていない限り、使用を避けたほうがよいでしょう。

ステップ 1: Fluent Interface と Command-Query API の比較

コマンドクエリ API に対して流暢なインターフェイスを考慮する必要があります。理解を深めるために、コマンド クエリ API の箇条書き定義を以下に記述します。簡単に言えば、これは単なる標準的なオブジェクト指向コーディング アプローチです。

  • データを変更するメソッドは a と呼ばれますCommand。コマンドは値を返しません。
  • 値を返すメソッドは a と呼ばれますQuery。クエリはデータを変更しません。

コマンドクエリ API に従うと、次のような利点があります。

  • オブジェクト指向のコードを見ると、何が起こっているかがわかります。
  • 各呼び出しが個別に発生するため、コードのデバッグが容易になります。

ステップ 2: Command-Query API 上の Fluent Interface

しかし、なんらかの理由でコマンド クエリ API が存在し、実際に読みやすくなっています。では、流暢なインターフェースとコマンドクエリ API の両方の利点を得るにはどうすればよいでしょうか?

回答: 流れるようなインターフェイスは、コマンド クエリ API の上に実装する必要があります (コマンド クエリ API流れるようなインターフェイスで置き換えるのではなく)。流れるようなインターフェイスは、コマンド クエリ API のファサードと考えてください。そして結局のところ、それは流暢な「インターフェイス」と呼ばれます。これは、標準 (コマンドクエリ) API を介した読み取り可能または便利なインターフェイスです。

通常、コマンド クエリ API の準備ができたら (おそらく単体テストが行​​われ、デバッグが容易になるように洗練されます)、その上に流暢なインターフェイス ソフトウェア レイヤーを記述できます。つまり、流暢なインターフェイスは、コマンドクエリ API を利用してその機能を実現します。次に、利便性と可読性が必要な場合はいつでも流暢なインターフェイス (メソッド チェーンを使用) を使用します。ただし、実際に何が起こっているのか (例外のデバッグ時など) を理解したい場合は、いつでもコマンド クエリ API (古き良きオブジェクト指向コード) を掘り下げることができます。

于 2013-06-13T12:53:58.127 に答える
8

メソッドチェーンを使用することの欠点は、コードをデバッグするNullPointerExceptionことExceptionです。次のコードがあるとします。

String test = "TestMethodChain"; test.substring(0,10).charAt(11); //This is just an example

次に、上記のコードを実行すると、 String index out of range: 例外が発生します。リアルタイムの状況になり、そのようなことが発生すると、どの行でエラーが発生したかがわかりますが、チェーンされたメソッドのどの部分がそれを引き起こしたかはわかりません。そのため、データが常に来るか、エラーが適切に処理されることがわかっている場合は、慎重に使用する必要があります。

複数行のコードを記述したり、複数の変数を使用したりする必要がないなどの利点もあります。

多くのフレームワーク/ツールはこれを Dozer のように使用しており、コードをデバッグするときに、エラーの原因を見つけるためにチェーンの各部分を調べなければなりませんでした。

お役に立てれば。

于 2013-06-07T05:57:20.827 に答える
5

Martin Fowler による Fluent Interfaceについて読むことをお勧めします。

要約すると

  • 主にコマンド クエリ責任分離 (CQRS) の設計原則に違反するため、メソッドをチェーンしないでください。
  • ビジネスがそれらの操作について話す方法に近づけることで API の設計を改善し、それらを内部 DSL と考えてください。
  • API を汚染し、コードのクライアント/メンテナーに意図を明らかにできない可能性があるため、独立したメソッドの連鎖を避けるようにしてください。
于 2013-06-11T12:26:31.250 に答える
2

不変性関数型プログラミングを好む場合は、二度と戻りませんvoid

戻り値のない関数は、その副作用のためにのみ呼び出されます。

もちろん、これが当てはまらない場合もありますが、関数が返さvoidれることは、別の方法で試すためのヒントと見なすことができます。

于 2013-06-07T08:37:33.623 に答える
1

かなりの作業量です。特に継承が関係している場合。ビルダーパターンに関するこの素晴らしい記事をご覧ください

クライアントがビルダーパターン、不変オブジェクトなど、同じインスタンスで複数のメソッドを順番に呼び出すと予想される場合、これを実装することは非常に理にかなっています。

于 2013-06-07T05:12:51.650 に答える