アレン・ホルブは「get/set関数を使用しないでください」と書いた、彼は正しいですか? [複製

StackOverflow https://stackoverflow.com/questions/996179

質問

アレン・ホルブは以下を書きました、

カップリングなしではプログラムを作成することはできません。それにもかかわらず、OO(オブジェクト指向)の教訓を追う奴隷的に結合を最小限に抑えることができます(最も重要なのは、オブジェクトの実装を使用するオブジェクトから完全に隠す必要があることです)。たとえば、オブジェクトのインスタンス変数(定数ではないメンバーフィールド)は、常にプライベートでなければなりません。限目。例外なく。これまで。私は真剣です。 (保護された方法を効果的に使用することがありますが、保護されたインスタンス変数は憎悪です。)

それは合理的に聞こえますが、彼は続けて言います、

あなたがすべき get/set関数を使用しないでください 同じ理由で、フィールドを公開するための過度に複雑な方法があります(ただし、基本型の値ではなく本格的なオブジェクトを返すアクセス関数は、返されたオブジェクトのクラスが設計の重要な抽象化である状況では合理的です。 )。

率直に言って、それは私にとって非常識に聞こえます。

私は情報が隠れている原則を理解していますが、アクセッサとミューテーターがなければ、Java Beanを使用できませんでした。モデル以来、モデル内のアクセサーなしでMVCデザインにどのように従うかわかりません できません ビューをレンダリングする責任を負います。

しかし、私は若いプログラマーであり、毎日オブジェクト指向のデザインについて詳しく学びます。おそらく、より多くの経験を持つ人は、この問題を検討することができます。

参照のためのアレン・ホルブの記事


関連する質問:

役に立ちましたか?

解決

私はあなたが一般的に変更を避けるべきだとあなたに言うHOLUBに問題はありません オブジェクトのが、代わりに、この目的を達成するために統合された方法(動作の実行)に頼ります。 Corletkが指摘しているように、最高レベルの抽象化について長く一生懸命に考えることには知恵があり、カプセル化について最終的に実行できるゲッター/セッターでは無意識のうちにプログラミングするだけではありません。

しかし、私はあなたがセッターを使用しないでください、またはプリミティブタイプにアクセスしないでください。確かに、このレベルの純度を維持するために必要な努力は 全て ケースは、適切に実装されたプロパティを使用するよりも、コードの複雑さを引き起こす可能性があります。長期的な痛みを犠牲にして、短期的な利益のためにルールをスカートしているときに知るのに十分な感覚が必要です。

Holubはあなたが違いを知ることを信頼していません。違いを知ることがあなたを専門家にするものだと思います。

他のヒント

その記事を注意深く読んでください。 Holubは、Getters and Settersが邪悪な「デフォルトアンチパッターン」であるという点を押し進めています。これは、システムを設計するときに滑り込む悪い習慣です。できるからです。

思考プロセスは線に沿って行う必要があります。このオブジェクトは何ですか 行う?その責任は何ですか?その行動は何ですか?それは何を知っていますか?これらの質問について長く一生懸命に考えると、可能な限り最高レベルのインターフェイスを公開するクラスの設計に自然につながります。

車は良い例です。明確に定義された標準化された高レベルのインターフェイスを公開します。私は自分自身に心配していません setSpeed(60)...それはMPHまたはkm/hですか?私はただ加速、クルーズ、減速します。詳細について考える必要はありません setSteeringWheelAngle(getSteeringWheelAngle()+Math.rad(-1.5)), 、私はただ turn(-1.5), 、そして詳細が世話されます フードの下.

「すべてのクラスが何に使用されるか、それが何をするか、それが何を表すか、そしてそれらの要件を満たす可能性の高い最高レベルのインターフェイスを公開することができる、そして把握することができる。プログラマーは、各クラスが何であるかを正確に判断するために必要な分析を行うのが面倒です。したがって、「それは何でもできる」という道を進みます。ゲッターとセッターは邪悪です!

クラスの実際の要件が事前に知られていない場合があります。それはクールで、ただ警戒し、今のところGetter/Setter Antipatternを使用しますが、あなたが知っているとき、経験を通してクラスが使用されているものを知っていると、おそらくDirty Lowレベルのインターフェイスをカムバックしてクリーンアップしたいと思うでしょう。 「そもそも吸盤を書いたときに知っていたもの」に基づいたリファクタリングは、コースのパーです。スタートを切るためにすべてを知る必要はありません。それは、あなたが知るほど、より少ないリワークが必要になる可能性が高いということです。

それが彼が促進しているメンタリティです。ゲッターとセッターは、簡単に陥ることができます。

はい、豆は基本的にゲッターとセッターが必要ですが、私にとっては特別なケースです。豆は名詞、物、具体的な識別可能な(物理ではないにしても)オブジェクトを表します。実際に自動的な動作を持っているオブジェクトの多くはありません。ほとんどの場合、物事は人間を含む外力によって操作され、生産的なものを作ります。

daisy.setColor(Color.PINK) 完全に理にかなっています。他に何ができますか?たぶん、花を作るためにバルカンの心が熟しています 欲しいです ピンクになる?うーん?

ゲッターとセッターは彼らの「邪悪」を持っていますか?場所。それはただ、本当に良いooのことと同じように、私たちはそれらを過剰に使用する傾向があります。なぜなら、それらは安全で馴染みがあり、単純なことは言うまでもなく、したがって、noobsが少なくとも彼らが彼らについて見たり聞いたりしなかった場合、少なくとも彼らが彼らについて見たり聞いたりしなければ、それはより良いかもしれません。 Dはマインドメルドのことを習得しました。

アレン・ホルブが言おうとしたことは、言い換えたと思います これ 記事は次のとおりです。

ゲッターとセッターは、特にカプセル化したい変数に役立ちますが、すべての変数にそれらを使用する必要はありません。実際、すべての変数にそれらを使用することは、厄介なコードの臭いです。

問題のあるプログラマーが持っていて、アレン・ホルブがそれを指摘するのに正しかったのは、すべての変数にゲッター/セッターを使用することがあるということです。そして、カプセル化の目的は失われます。

(私は.NET「プロパティ」角度からこれに来ていることに注意してください)

まあ、単に - 私は彼に同意しません。彼はあなたの呼び出しコードを破ることができるので、リターンタイプのプロパティが悪いことであることについて大きな大騒ぎをします - しかし まさに メソッド引数にも同じ引数が適用されます。また、メソッドも使用できない場合は?

わかりました、メソッド引数は変換の拡大として変更される可能性がありますが、....なぜ...また、c#で注意してください var キーワードは、この知覚された痛みの多くを軽減する可能性があります。

アクセサーはそうです いいえ 実装の詳細。それらはパブリックAPI /契約です。うん、あなたが抗議を破った場合、あなたは問題を抱えています。それはいつ驚きになりましたか?同様に、アクセサーが非自明であることは珍しくありません - つまり、彼らは以上にします ただ ラップフィールド;計算、ロジックチェック、通知などを実行し、状態のインターフェイスベースの抽象化を可能にします。ああ、そして多型 - など。

補助者の冗長性(p3?4?) - c#: public int Foo {get; private set;} - 仕事が完了しました。

最終的に、すべてのコードは、コンパイラに対する意図を表現する手段です。プロパティは、タイプセーフ、契約ベース、検証可能、拡張可能、多型の方法でそれをさせてくれます。ありがとう。なぜこれを「修正」する必要があるのですか?

ゲッターとセッターは、プライベート変数を公開するためにマスクにすぎません。

Holubがすでに言ったことを繰り返す意味はありませんが、その核心は、クラスが状態だけでなく行動を表すべきであるということです。

私はアレン・ホルブでさらにグーグルを追加しましたが、彼はJavaコミュニティで敵のシェアを持っているようです。

最後のものは特に尖っています。コメンテーターのテキストは斜体です。

GetIdentityは「Get」から始まりますが、フィールドを返すだけではないため、アクセサではありません。合理的な動作を持つ複雑なオブジェクトを返します

ああ、待ってください...それなら、原始的なタイプの代わりにオブジェクトを返す限り、アクセサーを使用しても大丈夫ですか?今ではそれは別の話ですが、それは私にとっても同じくらい馬鹿げています。オブジェクトが必要な場合もあれば、プリミティブタイプが必要な場合もあります。

また、アレンは、同じトピックに関する彼の前のコラム以来、彼の立場を根本的に柔らかくしたことに気づきました。たぶん彼は数年後に、俳優が結局のところ目的を果たしていることに気づいた...

私は実際にUIコードをビジネスロジックに入れていないことに留意してください。 AWT(抽象ウィンドウツールキット)またはスイングの観点からUIレイヤーを書きました。どちらも抽象化レイヤーです。

良いもの。 SWTで申請書を書いている場合はどうなりますか?その場合、「抽象」は本当に「抽象的」ですか?それに直面するだけです:このアドバイスは、単にあなたのビジネスロジックにUIコードを書くことにつながります。なんて素晴らしい原則でしょう。結局のところ、このプラクティスをプロジェクトで行うことができる最悪の設計上の決定の1つとして特定してから、少なくとも10年のようでした。

私の問題は、初心者のプログラマーが時々インターネット上の記事につまずいて、私がすべきよりも信用を与えていることです。おそらくこれはそのようなケースの1つです。

このようなアイデアが私に提示されたとき、私は私が使用しているライブラリとフレームワークを見たいと思っています。

たとえば、一部は同意しませんが、Java Standard APIが好きです。私もスプリングフレームワークが好きです。これらのライブラリのクラスを見ると、内部変数を公開するためだけにあるセッターやゲッターが非常にめったにないことに気付くでしょう。方法があります 名前が付けられました GetXですが、それは従来の意味でのゲッターであるという意味ではありません。

だから、彼にはポイントがあると思うし、それはこれだと思う:あなたがプレスするたびにEclipse(またはあなたの選択のIDE)で「Genate Getters/Setters」を選択するたびに、あなたは一歩下がって、あなたが何をしているのか疑問に思うべきだ。この内部表現を公開することは本当に適切ですか、それともいくつかのステップでデザインを台無しにしましたか?

私は彼がGet/Setを決して使用しないと言っているとは思わないが、むしろフィールドにGet/Setを使用することは、フィールドを公開するよりも良いとは思わない(例:Public String Name vs. public String name {get; set;})。

get/setを使用すると、OOの情報が隠れていることが制限され、潜在的に悪いインターフェイスにロックされます。

上記の例では、名前は文字列です。後でデザインを変更して複数の名前を追加したい場合はどうなりますか?インターフェイスは1つの文字列のみを公開したため、既存の実装を破らずに追加することはできません。

ただし、get/setを使用する代わりに、最初にadd(string name)などのメソッドがある場合、内部的にはsingularlyに名前を処理したり、リストに追加したり、追加方法を追加したり、追加したり、追加メソッドを追加したりすることができます。その他の名前。

OOの目標は、抽象化のレベルで設計することです。あなたが絶対にしなければならないよりも多くの詳細を公開しないでください。

この教義を壊したget/setでプリミティブタイプを巻き付けただけの可能性があります。

もちろん、これはOOの目標を信じている場合です。ほとんどの人は、実際にはそうではなく、機能的なコードをグループ化するための説得力のある方法としてオブジェクトを使用するだけではないことがわかります。

パブリック変数は、クラスが実際の一貫性のないデータの束にすぎない場合、または実際には本当に基本的なもの(ポイントクラスなど)である場合に意味があります。一般に、クラスにおそらく公開されるべきではないと思われる変数がある場合、それはクラスに何らかの一貫性があり、変数には維持されるべき特定の関係があるため、すべての変数がプライベートでなければなりません。

ゲッターとセッターは、ある種の一貫したアイデアを反映するときに理にかなっています。たとえば、ポリゴンクラスでは、指定された頂点のxおよびy座標には、クラスの境界外に意味があります。ゲッターを持つことはおそらく理にかなっており、セッターを持つことはおそらく理にかなっています。銀行口座のクラスでは、残高はおそらくプライベート変数として保存され、ほぼ間違いなくゲッターが必要です。セッターがある場合は、監査可能性を維持するためにログインする必要があります。

パブリック変数よりもゲッターとセッターにはいくつかの利点があります。インターフェースと実装の一部を分離します。ポイントがあるからといって .getX() 関数はxが必要なことを意味しません。 .getX().setX() 放射状座標でうまく機能するようにすることができます。もう1つは、セッター内でクラスを一貫性に保つために必要なことを何でもすることにより、クラスの不変剤を維持することが可能であるということです。もう1つは、銀行口座残高のログのように、セットにトリガーする機能を持つことができることです。

ただし、より抽象的なクラスの場合、メンバー変数は個々の重要性を失い、コンテキストでのみ意味があります。たとえば、C ++ストリームクラスのすべての内部変数を知る必要はありません。要素を出し入れする方法と、他のさまざまなアクションを実行する方法を知る必要があります。正確な内部構造を頼りにした場合、コンパイラやバージョン間で任意に異なる可能性のある詳細に揺れ動くでしょう。

ですから、私はプライベート変数をほぼ排他的に使用していると言います。ゲッターとセッターは、オブジェクトの動作に本当の意味があり、そうでないことです。

ゲッターとセッターがしばしば使いすぎであるからといって、それらが役に立たないというわけではありません。

ゲッター/セッターの問題は、彼らがカプセル化を偽造しようとすることですが、実際には内部を露出させることでそれを破ります。第二に、彼らは2つの別々のことをしようとしています - 彼らの状態へのアクセスを提供し、制御する - そして、どちらもそれほどうまくいかないことになります。

get/setメソッドを呼び出すと、変更したいフィールドの名前(または良いアイデアを持っている)を最初に知る必要があり、次にそのタイプを知る必要があるため、カプセル化が壊れます。あなたは電話することができませんでした

setPositionX("some string");

フィールドの名前とタイプがわかっていて、セッターが公開されている場合、誰でもその方法を公共の場であるかのように呼び出すことができます。そもそもそれは公共の場です。

状態へのアクセスを許可しますが、同時にそれを制御しようとすることにより、get/setメソッドは物事を混乱させ、最終的にはボイラープレートを使用しないか、誤解を招くことになります。ユーザーが期待しない効果。エラーチェックが必要な場合は、

public void tryPositionX(int x) throws InvalidParameterException{
    if (x >= 0)
        this.x = x;
    else
        throw new InvalidParameterException("Holy Negatives Batman!");
}

または、追加のコードが必要な場合は、メソッド全体が行うことに基づいて、より正確な名前と呼ばれる可能性があります。

tryPositionXAndLog(int x) throws InvalidParameterException{
    tryPositionX(x);
    numChanges++;
}

私見では、何かを機能させるためにゲッター/セッターを必要とすることは、多くの場合、デザインの悪い症状です。 「tell、尋ねないで」の原則を使用するか、オブジェクトが最初に状態データを送信する必要がある理由を再考します。状態ではなくオブジェクトの動作を変更する方法を公開します。その利点には、メンテナンスの容易さと拡張性の向上が含まれます。

あなたはMVCについても言及し、その場合、モデルはその見解に責任を負うことはできないと言います アレン・ホルブは、「give-me-a-jcomponent-tat represents-your-Identityクラス」を持つことにより、抽象化層を作成する例を示します。 彼は「システムの残りの部分からアイデンティティが表される方法を分離するだろう」と彼は言います。私はそれがうまくいくかどうかについてコメントするのに十分な経験がありませんが、表面的にはまともなアイデアのように聞こえます。

公共のゲッター/セッターは、実装の詳細へのアクセスを提供する場合に悪いです。しかし、オブジェクトのプロパティへのアクセスを提供し、これにゲッター/セッターを使用することは合理的です。たとえば、車にカラープロパティがある場合、クライアントにゲッターを使用して「観察」させることは許容されます。一部のクライアントが車をリクセアする機能を必要とする場合、クラスはセッターを提供できます(「リクロース」はより明確な名前です)。オブジェクトにプロパティがどのように保存されているか、それらがどのように維持されるかなどをクライアントに知らせないことが重要です。

うーん...彼はカプセル化の概念を聞いたことがない。クラスのメンバーへのアクセスを制御するために、ゲッターとセッターのメソッドが導入されています。すべてのフィールドを公開できるようにすることで...誰でも、オブジェクト全体を完全に無効にするために、彼らが望む価値をすべて書くことができます。

誰かがカプセル化の概念に少しあいまいである場合に備えて、こちらを読んでください:

カプセル化(コンピューターサイエンス)

...そして、それらが本当に邪悪な場合、.NETはプロパティの概念を言語に組み込むでしょうか? (少しきれいに見えるゲッターとセッターの方法)

編集

この記事は、カプセル化に言及しています:

"ゲッターとセッターは、特にカプセル化したい変数に役立ちますが、すべての変数にそれらを使用する必要はありません。実際、すべての変数にそれらを使用することは、厄介なコードの臭いです。"

この方法を使用すると、長期的にはコードを維持するのが非常に難しくなります。フィールドをカプセル化する必要がある年に及ぶプロジェクトを途中で見つけた場合、ソフトウェアのどこでもそのフィールドのすべてのリファレンスを更新して利益を得る必要があります。前もって適切なカプセル化を使用し、後で頭痛を安全に使用するのはずっと賢く聞こえます。

ゲッターとセッターは、クラスの外でアクセスまたは変更する必要がある変数にのみ使用する必要があると思います。そうは言っても、変数が静的でない限り、変数は公開されるべきではないと思います。これは、静的ではない変数をパブリックにすることで、それらが望ましくないことにつながる可能性があるためです。パブリック変数を不注意に使用している開発者がいるとしましょう。その後、彼は別のクラスから変数にアクセスし、意味なしにそれを変更します。今、彼はこの事故の結果として彼のソフトウェアにエラーを持っています。だからこそ、私はゲッターとセッターの適切な使用を信じていますが、すべてのプライベートまたは保護された変数にそれらを必要としません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top