16

1 つまたは 2 つのメソッドを何度も何度も呼び出さなければならないクラスがあります。メソッドは現在 を返しvoidます。thisメソッドをネストできるように、return にしたほうがよいのではないかと考えていました。それとも非常に非常に悪いと考えられていますか?または、悪い場合は、同じ型の新しいオブジェクトを返した方がよいでしょうか? またはどう思いますか?例として、加算器クラスの 3 つのバージョンを作成しました。

// Regular
class Adder
{
    public Adder() { Number = 0; }

    public int Number { get; private set; }

    public void Add(int i) { Number += i; }
    public void Remove(int i) { Number -= i; }
}

// Returning this
class Adder
{
    public Adder() { Number = 0; }

    public int Number { get; private set; }

    public Adder Add(int i) { Number += i; return this; }
    public Adder Remove(int i) { Number -= i; return this; }
}

// Returning new
class Adder
{
    public Adder() : this(0) { }
    private Adder(int i) { Number = i; }

    public int Number { get; private set; }

    public Adder Add(int i) { return new Adder(Number + i); }
    public Adder Remove(int i) { return new Adder(Number - i); }
}

最初のものは次のように使用できます。

    var a = new Adder();
    a.Add(4);
    a.Remove(1);
    a.Add(7);
    a.Remove(3);

他の 2 つは次のように使用できます。

    var a = new Adder()
        .Add(4)
        .Remove(1)
        .Add(7)
        .Remove(3);

唯一の違いはa、最初のケースはnew Adder()while であり、後者は最後のメソッドの結果であることです。

最初に見つけたのは、すぐに... 何度も何度も書くのが面倒です。そのため、他のバージョンのいずれかを使用したいと思います。

3 番目は、多くの String メソッドや IEnumerable 拡張メソッドなど、他の多くのメソッドと同じように機能します。var a = new Adder(); var b = a.Add(5);0 だったものと 5 だったものを持つことができるという点で、それには良い面があると思います。そして、最初の物体はいつ死にますか? 最初のメソッドが種類を返すのはいつですか? または?

とにかく、私は戻ってきたものが好きthisで、それを使うと思いますが、他の人がこのケースについてどう思うか知りたいです. そして、ベストプラクティスと見なされるもの。

4

8 に答える 8

22

「これを返す」スタイルは流暢なインターフェースと呼ばれることもあり、一般的な方法です。

于 2009-04-23T13:25:27.057 に答える
6

私は「流暢な構文」が好きで、2 番目の構文を使用します。結局のところ、流暢な構文に不快感を覚える人のために、最初にこれを使用することもできます。

加算器のようなインターフェイスを使いやすくする別のアイデア:

public Adder Add(params int[] i) { /* ... */ }
public Adder Remove(params int[] i) { /* ... */ }

Adder adder = new Adder()
  .Add(1, 2, 3)
  .Remove(3, 4);

私はいつも短くて読みやすいインターフェイスを作ろうとしていますが、多くの人はできるだけ複雑なコードを書きたいと思っています。

于 2009-04-23T13:26:50.173 に答える
2

チェーンはあると便利で、一部のフレームワークではコアになっています (たとえば、Linq 拡張機能と jQuery の両方で頻繁に使用されています)。

新しいオブジェクトを作成するかどうかreturn thisは、最初のオブジェクトがどのように動作するかによって異なります。

var a = new Adder();

var b = a.Add(4)
         .Remove(1)
         .Add(7)
         .Remove(3);

//now - should a==b ?

jQuery でチェーンすると、元のオブジェクトが変更されます。これが返されます。これは予想される動作です。そうしないと、基本的に UI 要素が複製されます。

Linq で連鎖すると、元のコレクションは変更されません。これも予想される動作です。チェーンされた各関数はフィルターまたは変換であり、元のコレクションは多くの場合不変です。

どのパターンがあなたの仕事に適していますか?

于 2009-04-23T13:36:15.660 に答える
1

単純なインターフェースの場合、特に実装が非常に簡単なため、「流暢な」インターフェースは非常に便利だと思います。流暢なインターフェースの価値は、理解の邪魔になる多くの余分な毛羽立ちをなくすことです。このようなインターフェースの開発には、特にインターフェースが関与し始めると、多くの時間がかかる場合があります。インターフェースの使用法がどのように「読み取られる」かについて心配する必要があります。私の考えでは、このようなインターフェイスの最も説得力のある用途は、保存される文字数ではなく、プログラマーの意図を伝える方法です。

あなたの特定の質問に答えるために、私は「これを返す」スタイルが好きです。流暢なインターフェイスの私の典型的な使用法は、一連のオプションを定義することです。つまり、クラスのインスタンスを作成し、そのインスタンスで流暢なメソッドを使用して、オブジェクトの目的の動作を定義します。はい/いいえのオプションがある場合 (ロギングなど)、「setLogging(bool state)」メソッドではなく、「WithLogging」と「WithoutLogging」の 2 つのメソッドを使用するようにします。これは多少手間がかかりますが、最終結果の明瞭さは非常に役に立ちます。

于 2009-04-23T13:36:05.720 に答える
0
  1. あなたの特定のケースでは、算術演算子をオーバーロードすることがおそらく最良の解決策です。

  2. Returning this(Fluent インターフェイス) は、式を作成するための一般的な方法です。単体テストとモック フレームワークでは、これが頻繁に使用されます。Fluent Hibernate は別の例です。

  3. 新しいインスタンスを返すことも良い選択かもしれません。これにより、クラスを不変にすることができます。一般に、これは良いことであり、マルチスレッドの場合には非常に便利です。ただし、不変性が役に立たない場合は、オブジェクト作成のオーバーヘッドについて考えてください。

于 2009-04-23T13:31:00.587 に答える
0

Adder と呼ぶなら、これを返すことにします。ただし、Adder クラスに回答が含まれているのはちょっと奇妙です。

MyNumber のようなものにして、Add() メソッドを作成することを検討してください。

理想的には(IMHO)、インスタンス内に保存されている数値は変更されませんが、新しい値で新しいインスタンスが作成され、それが返されます。

class MyNumber
{
    ...

    MyNumber Add( int i )
    {
        return new MyNumber( this.Value + i );
    }
}
于 2009-04-23T13:31:18.073 に答える
0

これを考えてみてください: 5 年後にこのコードに戻ってきた場合、これはあなたにとって意味のあるものになるでしょうか? もしそうなら、あなたは先に進むことができると思います。

ただし、この特定の例では、+and-演算子をオーバーロードすると、物事がより明確になり、同じことが達成されるように見えます。

于 2009-04-23T13:25:12.987 に答える
0

2 番目と 3 番目のソリューションの主な違いは、これの代わりに新しいインスタンスを返すことで、特定の状態のオブジェクトを「キャッチ」して、そこから続行できることです。

var a = new Adder() .Add(4);

var b = a.Remove(1);

var c = a.Add(7) .Remove(3);

この場合、b と c の両方が、開始点として a でキャプチャされた状態を持ちます。Steve Freeman 著、Growing Object-Oriented Software の Guided by Tests でテスト ドメイン オブジェクトを構築するためのパターンについて読んでいるときに、この慣用句に出くわしました。ナット・プライス

インスタンスの有効期間に関する質問について: Remove または Add の呼び出しが返されるとすぐに、インスタンスがガベージ コレクションの対象になると予想されます。

于 2009-04-23T18:51:27.573 に答える