セッターに「これ」を返すのは悪い習慣ですか?


249

Javaのセッターに「これ」を返すようにするのは良いことですか、悪いことですか?

public Employee setName(String name){
   this.name = name;
   return this;
}

このパターンは、次のようにセッターをチェーンできるので便利です。

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));

これの代わりに:

Employee e = new Employee();
e.setName("Jack Sparrow");
...and so on...
list.add(e);

...しかし、それは一種の標準的な慣習に反します。セッターが何か便利なことをできるからといって価値があるのではないでしょうか。このパターンがいくつかの場所(JMock、JPAなど)で使用されているのを見てきましたが、一般的ではないようで、このパターンがどこでも使用されている非常に明確に定義されたAPIでのみ使用されます。

更新:

私が説明したことは明らかに有効ですが、私が本当に探しているのは、これが一般的に受け入れられるかどうか、および落とし穴や関連するベストプラクティスがあるかどうかについての考えです。Builderパターンについては知っていますが、私が説明しているものより少し複雑です。JoshBlochが説明しているように、オブジェクトを作成するための静的なBuilderクラスが関連付けられています。


1
このデザインパターンは少し前に見たので、可能な限りこれを行います。メソッドがジョブを実行するために何かを明示的に返す必要がない場合、メソッドはを返しますthis。時には、関数を変更して、値を返すのではなく、オブジェクトのメンバーを操作して、これを実行できるようにすることもあります。素晴らしいです。:)
反転14

4
伸縮式セッターが自分自身とビルダーを返す場合、setName(String name)ではなくwithName(String name)を使用することを好みます。あなたが指摘したように、セッターの一般的な慣行と期待はvoidを返すことです。「非標準」設定主体は、など既存の枠組みなどのJPAエンティティマネージャ、春、とうまく動作しない可能性があります
oᴉɹǝɥɔ

各呼び出しの前に改行を導入してください:)そして、これを尊重しない場合はIDEを構成するか、適切なものを取得してください。
MauganRa 2017

広く使用されているフレームワーク(SpringやHibernateなど)は、(少なくとも以前は使用されていた)void-setters規約に厳密に準拠します
Legna

回答:


83

特に問題はないと思いますが、それは単なるスタイルの問題です。次の場合に役立ちます。

  • 一度に多くのフィールドを設定する必要があります(構築時を含む)
  • コードの作成時に設定する必要があるフィールドがわかっている。
  • 設定するフィールドにはさまざまな組み合わせがあります。

この方法の代替案は次のとおりです。

  1. 1つのメガコンストラクター(欠点:多くのnullまたはデフォルト値を渡す可能性があり、どの値が何に対応するかを知るのが難しくなります)
  2. いくつかのオーバーロードされたコンストラクター(欠点:数が多くなると扱いにくくなる)
  3. ファクトリー/静的メソッド(欠点:オーバーロードされたコンストラクターと同じ-数が多いと扱いにくくなる)

一度にいくつかのプロパティのみを設定する場合は、「これ」を返す価値はないと思います。後でステータス/成功インジケータ/メッセージのような何か他のものを返すことにした場合、それは確かに落ちます。


1
まあ、一般的に、慣例により、セッターから何も返さない。
Ken Liu、

17
おそらく最初からではないかもしれませんが、セッターは必ずしも元の目的を維持するわけではありません。以前は変数であったものが、いくつかの変数を含む状態に変化したり、他の副作用が発生したりする可能性があります。一部のセッターは以前の値を返す可能性があり、他のセッターは例外が原因で失敗が多すぎる場合に失敗インジケーターを返す可能性があります。ただし、これは別の興味深い点を提起します。使用しているツール/フレームワークが戻り値を持つときにセッターを認識しない場合はどうなりますか?
トムクリフト

12
@Tomの良い点は、これを行うと、ゲッターとセッターの「Java Bean」の規約に違反することです。
アンディホワイト

2
@TomClift「Java Bean」の規則に違反すると問題が発生しますか?戻り値の型、またはメソッドパラメータとメソッド名のみを調べる「Java Bean」規則を使用するライブラリですか。
Theo Briscoe、

3
これがビルダーパターンが存在する理由です。セッターは何かを返さず、代わりに必要に応じてビルダーを作成し、必要なコードが少なくなります。:)
RicardoE

106

それは悪い習慣ではありません。それはますます一般的な習慣です。ほとんどの言語では、不要な場合は返されたオブジェクトを処理する必要がないため、「通常の」セッターの使用法の構文は変更されませんが、セッターをチェーン化できます。

これは一般にビルダーパターンまたは流暢なインターフェイスと呼ばれます

これはJava APIでも一般的です。

String s = new StringBuilder().append("testing ").append(1)
  .append(" 2 ").append(3).toString();

26
これはビルダーでよく使用されますが、「これは... Builderパターンと呼ばれます」とは言えません。
ローレンスゴンサルベス

10
流暢なインターフェイスの理論的根拠の一部は、コードを読みやすくすることです。書く方が便利だと思いましたが、読みづらい気がします。それは私がそれについて持っている唯一の本当の意見の相違です。
ブレントはコードを

30
それは列車事故のアンチパターンとしても知られています。問題は、nullポインター例外スタックトレースにこのような行が含まれている場合、どの呼び出しがnullを返したかがわからないことです。つまり、連鎖は絶対に避けなければならないというわけではありませんが、悪いライブラリ(特に自作)には注意してください。
ddimitrov

18
あなたが戻ってそれを制限するよう@ddimitrov aslong これをそれが(最初のinvokationがNPEをスローする可能性)が問題になることはない
ステファン・

4
読みやすさを損なう箇所に改行とインデントを配置することを前提として、書き込みと読み取りの方が簡単です。(それはbla.foo.setBar1(...) ; bla.foo.setBar2(...)あなたが書くことができるときのような繰り返しコードの冗長な混乱を避けるためですbla.foo /* newline indented */.setBar1(...) /* underneath previous setter */ .setBar2(...)(このようなSOコメントで改行を使用することはできません:-( ...このようなセッター10以上またはより複雑な呼び出しを考慮して要点が得られることを願っています)
Andreas Dietrich

90

要約する:

  • これは「滑らかなインターフェース」または「メソッドチェーン」と呼ばれます。
  • これは「標準の」Javaではありませんが、最近はもっと見られるようになります(jQueryでうまく機能します)
  • これはJavaBean仕様に違反しているため、さまざまなツールやライブラリ、特にJSPビルダーやSpringで機能しなくなります。
  • JVMが通常行う最適化を妨げる可能性があります
  • コードをクリーンアップすると考える人もいれば、「恐ろしい」と考える人もいます。

言及されていない他のいくつかの点:

  • これは、各関数が1つ(そして1つだけ)のことを実行するという原則に違反しています。あなたはこれを信じるかどうかはわかりませんが、Javaではうまくいくと思います。

  • IDEはこれらを生成しません(デフォルト)。

  • 最後に、これが実際のデータポイントです。このように構築されたライブラリの使用に問題がありました。Hibernateのクエリビルダーは、既存のライブラリでのこの例です。Queryのset *メソッドはクエリを返すため、シグネチャを見てもその使用方法を知ることはできません。例えば:

    Query setWhatever(String what);
  • それは曖昧さをもたらします:メソッドが現在のオブジェクト(あなたのパターン)を変更するか、あるいはおそらくQueryは本当に不変(非常に人気があり、価値のあるパターン)であり、メソッドは新しいものを返します。ライブラリを使いにくくするだけで、多くのプログラマーはこの機能を利用しません。セッターがセッターである場合、それを使用する方法はより明確になります。


5
ところで、それは「流動的」ではなく「流動的」です...音声言語のように一連のメソッド呼び出しを構造化できるので。
Ken Liu

1
不変性に関する最後のポイントは非常に重要です。最も簡単な例は文字列です。Java開発者は、Stringでメソッドを使用すると、まったく新しいインスタンスではなく、変更されたインスタンスを取得することを期待しています。流れるようなインターフェイスでは、返されるオブジェクトが新しいインスタンスではなく「this」であることをメソッドドキュメントで言及する必要があります。
MeTTeO 2015

7
全体的には同意しますが、これは「たった1つのことを行う」という原則に違反することには同意しません。戻ることthisはほとんど複雑なロケット科学ではありません。:-)
user949300

追加のポイント:コマンドとクエリの分離の原則にも違反しています。
Marton_hun

84

私はこれに「with」メソッドを使用することを好みます:

public String getFoo() { return foo; }
public void setFoo(String foo) { this.foo = foo; }
public Employee withFoo(String foo) {
  setFoo(foo);
  return this;
}

したがって:

list.add(new Employee().withName("Jack Sparrow")
                       .withId(1)
                       .withFoo("bacon!"));

警告:このwithX構文は一般に不変オブジェクトの「セッター」を提供するために使用されるため、これらのメソッドの呼び出し元は、既存のインスタンスを変更するのではなく、新しいオブジェクトを作成することを合理的に期待する場合があります。多分もっと合理的な言い回しは次のようなものになるでしょう:

list.add(new Employee().chainsetName("Jack Sparrow")
                       .chainsetId(1)
                       .chainsetFoo("bacon!"));

chainsetXyz()命名規則を使用すると、実質的に誰もが満足するはずです。


18
+1興味深い慣習のため。私は自分のコードでそれを採用するつもりはありません。すべてのクラスフィールドに、a get、a が必要になったようです。しかし、それはまだ興味深い解決策です。:)setwith
ポールマンタ2011年

1
それは、セッターを呼び出す頻度に依存します。これらのセッターが頻繁に呼び出される場合、他の場所でコードを簡略化するため、セッターを追加することは余分な手間をかける価値があることがわかりました。YMMV
2011年

2
そして、これをProject Lombok@Getter/@Setter注釈に追加した場合...チェーニングには素晴らしいでしょう。または、JQueryとJavaScriptの悪魔が使用するKestrelコンビネーターgithub.com/raganwald/Katy)のようなものを使用することもできます。
Ehtesh Choudhury 2012

4
@ AlikElzin-kilaka実は私は気づいたのJava 8の使用でjava.time不変クラスこのパターン、例えばLocalDate.withMonth、withYearなど
qualidafial

4
with接頭辞は異なる規則です。@qualidafialが例を示したので。接頭辞が付けられたメソッドwithは返すべきではthisなく、現在のインスタンスのような新しいインスタンスですが、with、変更されます。これは、オブジェクトを不変にしたいときに行われます。そのため、メソッドの接頭辞が表示された場合with、同じオブジェクトではなく、新しいオブジェクトを取得すると想定しています。
tempcke 2018年

26

'this'セッターから戻りたくないが2番目のオプションを使用したくない場合は、次の構文を使用してプロパティを設定できます。

list.add(new Employee()
{{
    setName("Jack Sparrow");
    setId(1);
    setFoo("bacon!");
}});

余談ですが、C#では少しクリーンだと思います。

list.Add(new Employee() {
    Name = "Jack Sparrow",
    Id = 1,
    Foo = "bacon!"
});

16
ダブルブレースの初期化は、匿名の内部クラスを作成するため、equalsで問題が発生する可能性があります。c2.com/cgi/wiki?DoubleBraceInitialization
Csaba_Hを

@Csaba_H明らかにその問題は、equalsメソッドをぶつけた人の責任です。equalsあなたが何をしているのか知っているなら、匿名クラスを扱うとてもきれいな方法があります。
AJMansfield 2014年

そのための新しい(匿名)クラスを作成しますか?すべてのインスタンスについて?
user85421

11

これは、getter / setterの規則を破るだけでなく、Java 8メソッド参照フレームワークも破ります。MyClass::setMyValueはでありBiConsumer<MyClass,MyValue>myInstance::setMyValueConsumer<MyValue>です。setter returnがある場合this、それはもはやの有効なインスタンスでConsumer<MyValue>はなく、Function<MyValue,MyClass>であり、それらのsetterへのメソッド参照を使用するものはすべて無効になります(それらがvoidメソッドであると想定)。


2
JavaにJVMだけでなく、戻り値の型によってオーバーロードする方法があったら、それはすばらしいことです。これらの重大な変更の多くは簡単にバイパスできます。
Adowrath 2017年

1
Consumer<A>Function<A,B>のデフォルト実装を提供することにより、両方を拡張する機能インターフェイスをいつでも定義できますvoid accept(A a) { apply(a); }。次に、どちらか一方として簡単に使用でき、特定のフォームを必要とするコードを壊しません。
スティーブK

ああ!これは明らかに間違っています!これは、void-compatibilityと呼ばれます。値を返すセッターは、コンシューマーとして機能できます。ideone.com/ZIDy2M
Michael

8

私はJavaを知りませんが、C ++でこれを行いました。他の人々は、それが行を非常に長くし、非常に読みにくくすると言っていましたが、私はこのように何度もそれをしました:

list.add(new Employee()
    .setName("Jack Sparrow")
    .setId(1)
    .setFoo("bacon!"));

これはさらに良いです:

list.add(
    new Employee("Jack Sparrow")
    .Id(1)
    .foo("bacon!"));

少なくとも、私は思います。しかし、私に反対票を投じて、希望があれば私をひどいプログラマーと呼んでも構いません。また、Javaでこれを実行することさえ許可されているかどうかはわかりません。


「さらに良い」は、最新のIDEで使用可能なフォーマットソースコードの機能に適していません。残念ながら。
するThorbjörnRavnアンデルセン

おそらくあなたは正しいです...私が使用した唯一の自動フォーマッターはemacsの自動インデントです。
カーソンマイヤーズ

2
ソースコードフォーマッタは、チェーン内の各メソッド呼び出しの後に単純な//で強制できます。それはあなたのコードを少し醜くしますが、あなたの垂直方向の一連のステートメントを水平方向に再フォーマットするほどではありません。
10

@qualidafial //すでに折り返された行を結合しないようにIDEを構成する場合、各メソッドの後に必要はありません(例:Eclipse>プロパティ> Java>コードスタイル>フォーマッタ>行の折り返し>既に折り返された行を結合しない)。
DJDaveMark

6

「流暢なインターフェース」と呼ばれるこの計画(しゃれた意図)は、現在非常に人気が高まっています。許容範囲ですが、実際には私のお茶ではありません。


6

voidを返さないため、有効なJavaBeanプロパティセッターではなくなりました。あなたが視覚的な「Bean Builder」ツールを使用している世界の7人のうちの1人であるか、JSP-bean-setProperty要素を使用している17人のうちの1人である場合、それは問題になるかもしれません。


SpringのようなBean対応のフレームワークを使用する場合にも重要です。
ddimitrov 2010年

6

少なくとも理論的には、呼び出し間で誤った依存関係を設定することにより、JVMの最適化メカニズムに損傷を与える可能性があります。

これは構文上の砂糖であるはずですが、実際には、超インテリジェントJava 43の仮想マシンに副作用を引き起こす可能性があります。

それが私が反対票を投じる理由です、それを使用しないでください。


10
興味深い...これについてもう少し詳しく説明していただけますか?
Ken Liu、

3
スーパースカラープロセッサが並列実行を処理する方法について考えてみてください。2番目のsetメソッドを実行するオブジェクトは最初のsetメソッドに依存しますが、プログラマーはそれを知っています。
マリアン

2
私はまだついていません。2つの別々のステートメントでFooを設定し、次にBarを設定した場合、Barを設定しているオブジェクトは、Fooを設定しているオブジェクトとは異なる状態になります。したがって、コンパイラもこれらのステートメントを並列化できませんでした。少なくとも、不当な前提を導入しないとどうなるのかわかりません(私はそれについて何も知らないので、Java 43が実際には1つのケースで並列化を実行し、他のケースでは実行しないことを否定しません。一方のケースでは不当な仮定があり、もう一方のケースではありません)。
masonk 2011

12
わからない場合は、テストしてください。 -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining java7 jdkは確実にチェーンされたメソッドをインライン化し、voidセッターをホットとしてマークし、それらをインライン化するために必要な同じ回数の反復を実行します。JVMのopcodeプルーニングアルゴリズムの能力を過小評価していると考えてください。これを返すことがわかっている場合は、jrs(java returnステートメント)オペコードをスキップし、これをスタックに残します。
Ajax

1
アンドレアス、私は同意しますが、非効率的なコードのレイヤーを重ねると問題が発生します。99%明確にコーディングする必要がありますが、このあたりでよく言われます。しかし、現実的になり、長年の経験を使用して、一般的なアーキテクチャの意味で時期尚早に最適化する必要がある場合もあります。
LegendLength 2017

6

それは全く悪い習慣ではありません。ただし、JavaBeans Specとの互換性はありません。

そして、それらの標準的なアクセサに依存する多くの仕様があります。

いつでもそれらを共存させることができます。

public class Some {
    public String getValue() { // JavaBeans
        return value;
    }
    public void setValue(final String value) { // JavaBeans
        this.value = value;
    }
    public String value() { // simple
        return getValue();
    }
    public Some value(final String value) { // fluent/chaining
        setValue(value);
        return this;
    }
    private String value;
}

これらを一緒に使用できます。

new Some().value("some").getValue();

ここに不変オブジェクトの別のバージョンがあります。

public class Some {

    public static class Builder {

        public Some build() { return new Some(value); }

        public Builder value(final String value) {
            this.value = value;
            return this;
        }

        private String value;
    }

    private Some(final String value) {
        super();
        this.value = value;
    }

    public String getValue() { return value; }

    public String value() { return getValue();}

    private final String value;
}

今、これを行うことができます。

new Some.Builder().value("value").build().getValue();

2
編集が拒否されましたが、ビルダーの例は正しくありません。まず、.value()は何も返さず、someフィールドも設定しません。次に、セーフガードを追加somenullてbuild()に設定するSome必要がありbuilder.value()ます。そうすると、本当に不変です。そうしないと、同じBuilderインスタンスを再度呼び出すことができます。そして最後に、はい、あなたはビルダーを持っていますが、あなたはSomeまだパブリックコンストラクタを持っています、つまり、ビルダーの使用を公然と主張しない、つまり、ユーザーがカスタムを設定するメソッドを試すか検索する以外にそれを知らないということですvalueまったく。
Adowrath 2017年

@Adowrath答えが正しくない場合は、自分の答えを書いてください。誰かの形を編集して形にしようとしないでください
CalvT

1
@JinKwonグレート。ありがとう!以前失礼なように見えた場合はごめんなさい。
Adowrath 2017

1
@Adowrath機能強化に関するコメントがあれば、遠慮なくお寄せください。ちなみに、あなたの編集を拒否したのは私ではありません。:)
Jin Kwon

1
分かった分かった。^^そして、新しいバージョンに感謝します。これにより、実際に変更可能な「Immutable-Some」ビルダーが提供されます。そして、それは私の編集の試みよりも賢い解決策です。
Adowrath 2017

4

アプリケーション全体で同じ規則を使用する場合、問題はないようです。

一方で、アプリケーションの既存の部分が標準の規則を使用している場合は、それに準拠し、より複雑なクラスにビルダーを追加します

public class NutritionalFacts {
    private final int sodium;
    private final int fat;
    private final int carbo;

    public int getSodium(){
        return sodium;
    }

    public int getfat(){
        return fat;
    }

    public int getCarbo(){
        return carbo;
    }

    public static class Builder {
        private int sodium;
        private int fat;
        private int carbo;

        public Builder sodium(int s) {
            this.sodium = s;
            return this;
        }

        public Builder fat(int f) {
            this.fat = f;
            return this;
        }

        public Builder carbo(int c) {
            this.carbo = c;
            return this;
        }

        public NutritionalFacts build() {
            return new NutritionalFacts(this);
        }
    }

    private NutritionalFacts(Builder b) {
        this.sodium = b.sodium;
        this.fat = b.fat;
        this.carbo = b.carbo;
    }
}

1
これはまさに、Builderパターンが修正するように設計されたものです。Java 8のラムダを壊さず、気の利いたJavaBeansツールを壊さず、JVMで最適化の問題を引き起こしません(オブジェクトはインスタンス化時にのみ存在するため)。また、単にビルダーを使用しないことで発生する「方法が多すぎるコンストラクター」の問題を解決し、ダブルブレースの匿名クラスによるヒープ汚染を排除します。
ndm13

興味深い点-クラスのほとんど何も不変ではない(たとえば、高度に構成可能なGUI)場合は、おそらくビルダーを完全に回避できることに気づきます。
フィリップグイン


3

私は「これ」のリターンを持つセッターを支持しています。Beanに準拠していなくてもかまいません。「=式/ステートメント」を使用しても問題ない場合は、値を返すセッターで問題ありません。


2

私は以前このアプローチを好んでいましたが、私はそれに反対しました。

理由:

  • 読みやすさ。各setFoo()を別々の行に置くと、コードが読みやすくなります。通常は、コードを1回書くよりも何度も何度もコードを読みます。
  • 副作用:setFoo()はフィールドfooのみを設定し、それ以外は設定しないでください。これを返すことは余分な「それは何でしたか」です。

私が見たビルダーパターンは、setFoo(foo).setBar(bar)規約を使用せず、さらにfoo(foo).bar(bar)を使用しています。おそらくそれらの理由のためでしょう。

それはいつものように好みの問題です。私は「最小の驚き」アプローチが好きです。


2
副作用については同意します。ものを返すセッターは名前に違反します。あなたはfooを設定していますが、オブジェクトを取り戻しますか?これは新しいオブジェクトですか、それとも古いオブジェクトを変更しましたか?
クランチドッグ2009

2

この特定のパターンは、メソッドチェーンと呼ばれます。ウィキペディアリンク、これにはさまざまなプログラミング言語でどのように行われるかについてのより多くの説明と例があります。

PS:特定の名前を探していたので、ここに残しておくことを考えました。


1

ひと目で:「おどろく!」

さらに考えて

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));

実際よりもエラーが発生しにくい

Employee anEmployee = new Employee();
anEmployee.setName("xxx");
...
list.add(anEmployee);

とても面白いです。ツールバッグにアイデアを追加しています...


1
いいえ、それはまだ恐ろしいです。保守の観点からは、後者の方が読みやすいので優れています。さらに、CheckStyleのような自動化されたコードチェッカーは、デフォルトで行を80文字に強制します。コードはとにかく折り返され、可読性/保守性の問題が複雑になります。そして最後に-それはJavaです。とにかくバイトコードにコンパイルする場合は、すべてを1行で記述することにはメリットがありません。
OMGポニー

1
個人的には、前者の方が読みやすいと思います。この方法で複数のオブジェクトを作成する場合は特にそうです。
ケン劉

@ケン:メソッドをコーディングします。1つのコピーを流暢な形式で書きます。他の別のコピー。次に、2つのコピーをカップルに渡して、どちらが読みやすいかを尋ねます。読み取りが速く、コードが速くなります。
OMGポニー

ほとんどのツールと同様に、使いすぎても簡単です。jQueryはこの手法を重視しているため、実際に読みやすさを損なうことが判明した長い呼び出しチェーンになりがちです。
staticsan 2009

2
各ドットの前に改行があり、インデントされていれば問題ありません。次に、2番目のバージョンと同じくらい読みやすくなります。list最初は冗長がないため、実際にはもっと多くのことです。
MauganRa 2017

1

はい、いいアイデアだと思います。

私が何かを追加できるとしたら、この問題はどうですか?

class People
{
    private String name;
    public People setName(String name)
    {
        this.name = name;
        return this;
    }
}

class Friend extends People
{
    private String nickName;
    public Friend setNickName(String nickName)
    {
        this.nickName = nickName;
        return this;
    }
}

これは動作します:

new Friend().setNickName("Bart").setName("Barthelemy");

これはEclipseでは受け入れられません。:

new Friend().setName("Barthelemy").setNickName("Bart");

これは、setName()がFriendではなくPeopleを返し、PeoplesetNickNameがないためです。

クラスの名前の代わりにSELFクラスを返すセッターをどのように作成できますか?

このようなものは問題ありません(SELFキーワードが存在する場合)。これはとにかく存在しますか?

class People
{
    private String name;
    public SELF setName(String name)
    {
        this.name = name;
        return this;
    }
}

1
それを受け入れないEclipse以外のJavaコンパイラがいくつかあります:)。基本的に、Java型システムのファウルを実行しています(これは静的であり、一部のスクリプト言語のように動的ではありません)。setNickName()を設定するには、setName()から取得したものをフレンドにキャストする必要があります。そのため、残念ながら、継承階層の場合、これにより可読性の利点の多くが排除され、そうでなければこの有用な可能性のある手法があまり有用ではなくなります。
Cornel Masson 2012年

5
ジェネリックを使用します。class Chainable <Self extends Chainable> {public Self doSomething(){return(Self)this;}}技術的にタイプセーフではありません(大文字小文字を区別できないSelf型でクラスを実装するとクラスキャストされます)が、正しい文法であり、サブクラスは独自の型を返します。
Ajax

加えて:Baptisteが使用しているこの「SELF」は自己型と呼ばれ、多くの言語には存在しません(Scalaは現在考えられる唯一の言語です)。AjaxによるGenericsの使用は、いわゆるセルフタイプの欠如に対処しようとしたテンプレートパターン」を、定期的な、しかし、いくつかの欠点を持っている:(からclass C<S extends C<S>>平野よりも安全である、S extends C。)の場合A extends B、及びB extends C<B>、あなたがAを持って、あなただけのそのAを知っていますAがすべてのメソッドをオーバーライドしない限り、Bが返されます。b)ローカルの非rawを表すことはできませんC<C<C<C<C<...>>>>>
Adowrath 2017

1

一般的には良い方法ですが、set-type関数でブール型を使用して、操作が正常に完了したかどうかを判断する必要がある場合もあります。これも1つの方法です。一般的に、これが良いとかベッドだとか言うドグマはありません。もちろん、それは状況から来ています。


2
例外を使用してエラー状態を示すのはどうですか?多くのCプログラマーが苦労して学んだように、エラーコードは簡単に無視できます。例外は、スタックが処理可能なポイントまで泡立つ可能性があります。
ddimitrov

通常は例外が望ましいですが、例外を使用できない場合はエラーコードも役立ちます。
Narek

1
こんにちは@Narek、おそらくあなたは例外ではなく、セッターでエラーコードを使用することが望ましい場合について詳しく説明できますか?なぜですか?
ddimitrov

0

ステートメントから

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));

私は2つのものを見ています

1)意味のないステートメント。2)読みやすさの欠如。


0

これは読みにくいかもしれません

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!")); 

またはこれ

list.add(new Employee()
          .setName("Jack Sparrow")
          .setId(1)
          .setFoo("bacon!")); 

これは次の方法よりも読みやすくなっています。

Employee employee = new Employee();
employee.setName("Jack Sparrow")
employee.setId(1)
employee.setFoo("bacon!")); 
list.add(employee); 

8
すべてのコードを1行にまとめようとしないと、かなり読みやすいと思います。
Ken Liu、

0

私はかなり長い間セッターを作成してきましたが、唯一の実際の問題は、厳密なgetPropertyDescriptorsを使用してBeanリーダー/ライターBeanアクセサーを取得するライブラリにあります。このような場合、Javaの「bean」には期待したような書き手がありません。

たとえば、私は確実にテストしていませんが、json / mapsからJavaオブジェクトを作成するときに、Jacksonがそれらをセッターとして認識しないことに驚かないでしょう。私はこれについて間違っていることを願っています(すぐにテストします)。

実際、私は軽量のSQL中心のORMを開発しており、これを返す認識されたセッターにgetPropertyDescriptorsにいくつかのコードを追加する必要があります。


0

ずっと前の答えですが、私の2セント...それで結構です。この流暢なインターフェースがもっと頻繁に使われたらいいのに。

「factory」変数を繰り返しても、以下の情報は追加されません。

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Foo.class);
factory.setFilter(new MethodFilter() { ...

これはきれいです、私見:

ProxyFactory factory = new ProxyFactory()
.setSuperclass(Properties.class);
.setFilter(new MethodFilter() { ...

もちろん、すでに述べた回答の1つとして、継承やツールなどの一部の状況では、これを正しく行うためにJava APIを微調整する必要があります。


0

可能であれば、他の言語構造を使用することをお勧めします。たとえば、Kotlinでは、withapply、またはletを使用ます。このアプローチを使用する場合、セッターからインスタンスを返す必要はありません。

このアプローチにより、クライアントコードは次のようになります。

  • 戻り値の種類に関係なく
  • メンテナンスが簡単
  • コンパイラの副作用を回避する

下記は用例です。

val employee = Employee().apply {
   name = "Jack Sparrow"
   id = 1
   foo = "bacon"
}


val employee = Employee()
with(employee) {
   name = "Jack Sparrow"
   id = 1
   foo = "bacon"
}


val employee = Employee()
employee.let {
   it.name = "Jack Sparrow"
   it.id = 1
   it.foo = "bacon"
}

0

APIを作成している場合は、「return this」を使用して、一度しか設定されない値を設定します。ユーザーが変更できる他の値がある場合は、代わりに標準のvoidセッターを使用します。

しかし、それは実際には好みの問題であり、私の意見では、セッターのチェーンはかなりクールに見えます。


0

これがJavaBeans仕様に違反していると主張するすべての投稿者に同意します。これを保持する理由はありますが、このBuilderパターン(ほのめかした)の使用がその場所にあると私は感じています。それがどこでも使用されていない限り、それは受け入れられるべきです。私にとって「それは場所」は、エンドポイントが「build()」メソッドの呼び出しであるところです。

もちろん、これらすべてを設定する方法は他にもありますが、ここでの利点は、1)多くのパラメーターのパブリックコンストラクターと2)部分的に指定されたオブジェクトを回避できることです。ここでは、ビルダーに必要なものを収集させ、最後にその「build()」を呼び出します。これにより、部分的に指定されたオブジェクトが構築されないようにすることができます。代替案は「パラメータオブジェクト」ですが、そのIMHOは問題を1レベル戻します。

多くのパラメーターのコンストラクターは、同じタイプの引数が多く渡される可能性が高くなるため、パラメーターに間違った引数を渡すことが容易になるため、嫌いです。オブジェクトが完全に設定される前に使用される可能性があるため、多くのセッターを使用するのは嫌いです。さらに、以前の選択に基づいてデフォルト値を持つという概念は、「build()」メソッドを使用するほうが適切です。

つまり、適切に使用すれば、良い習慣だと思います。


-4

悪い癖:セッターがゲッターをゲット

メソッドを明示的に宣言することについてはどうですか

setPropertyFromParams(array $hashParamList) { ... }

自動補完、リファクタリング、およびボイラープレートコードの読みやすさには適さない
Andreas Dietrich

理由:1)順序を覚えるか、ドキュメントから読み取る必要があります。2)コンパイル時の型安全性をすべて失います。3)値をキャストする必要があります(これと2)ダイナミックでは問題ありません。当然の言語)、4)あなたがすることができない)、この有効すべての呼び出しで、配列の長さをチェックする以外、および5を拡張する場合は、あなたが何かを変えることが順序または特定の値の存在さえも、あなたがすることができないこともないのランタイムをチェック疑いもなく時間もコンパイルしないでください。セッターあり:1)、2)、3):問題ありません。4)新しいメソッドを追加しても何も壊れません。5)明示的なエラーメッセージ。
Adowrath 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.