なぜプライベートフィールドがあるのか​​、十分に保護されていないのですか?


265

privateクラスのフィールド/プロパティ/属性の可視性は有用ですか?OOPでは、遅かれ早かれ、クラスのサブクラスを作成することになります。その場合は、実装を完全に修正し、理解できると便利です。

クラスをサブクラス化するときに最初に行うことの1つは、多数のprivateメソッドをに変更することprotectedです。ただし、外界から詳細を隠すことは重要です。そのため、必要なのprotectedは単なるではなく、ですpublic

私の質問は:privateではなくprotected、優れたツールである重要なユースケースについて知っていますか、または2つのオプション " protectedpublic"でOOP言語に十分でしょうか?



236
投票者へ:私もOPの前提に強く反対していますが、この質問は完全に首尾一貫しており、回答する価値があるため、この質問を支持しています。はい、OPになぜこれが間違っているのかを伝える必要がありますが、その方法は答え書く(または既存の答えの編集を提案する)ことです。
-Ixrec

18
派生クラスは外界の一部です。
CodesInChaos

20
protectedは、常にアクセスが継承階層にロックされることを意味しないことを忘れないでください。Javaでは、パッケージレベルのアクセスも許可します。
berry120

8
私の教授は、「子供には伝えたくないものがある。私は自分の野原だ」と言っていました。
18年

回答:


225

あなたが言うように、protectedまだ「実装を完全に変更する」能力が残っているからです。クラス内の何も本当に保護しません。

クラス内のコンテンツを「真に保護する」ことに関心があるのはなぜですか?そうなければ、クライアントコードを壊さずに実装の詳細を変更することは不可能だからです。別の言い方をすれば、サブクラスを作成する人は、元の基本クラスを作成した人の「外界」でもあります。

実際には、protectedメンバーは本質的にクラスの「サブクラス用のパブリックAPI」であり、publicメンバーと同様に安定性と下位互換性を維持する必要があります。真のprivateメンバーを作成する能力がなければ、(悪意のない)クライアントコードが何らかの形で依存する可能性を排除できないため、実装内のも安全に変更できません。それ。

ちなみに、「OOPでは、遅かれ早かれ、クラスのサブクラスを作成します」は技術的には真実ですが、あなたの議論は、「遅かれ早かれ、あなたはサブクラスを作成する」すべてのクラス」はほとんど間違いなくそうではありません。


11
これがprivate実際に私にとって初めてだったので、できれば+1以上を投げます。libパースペクティブをより頻繁に使用する必要があります。そうしないと、(Cに似た)「絶対制御、絶対責任」コーディングの考え方が好きな人は、「自分を自分から守る」というフラグを立てることができます。私はprivate以前も使用していたことに注意してください、私はいつも良いドキュメントを感じていて、_fooおそらくそれをいじってはいけないことを示すような命名規則は、より良くないとしても同等でした。「何も壊れない」と確定的に言うことができるのは、正当な、private唯一の機能です。
-abluejelly

私はもともと公共図書館とフレームワークのコードのケースを無視し、「クライアントコード」の観点からのみ多かれ少なかれ考えました。内部実装の最適化は私の質問の良い例ですが、実際にこれが実際に起こるかどうかを自問します(特に、多くの人がクラスをコードの1000行以下にすることを推奨する場合)。一般的に、私はRubyのアプローチが好きです。プライベートは一種の推奨事項です。「ここにドラゴンがいます、注意して進めてください」。
アダムリブシャ

9
@AdamLibušaコードが公開されている場合、これははるかに大きな問題ですが、クラスのすべてのクライアントの作成者であっても適用されます。問題は、特定のリファクタリングが不可能であることから、特定のリファクタリングが退屈でエラーが発生しやすいものに変わるだけです。私の経験では、最適化は実際にこれらのリファクタリングの最も一般的な理由ではありません(私は主にJavascriptを実行します)。本当に堅牢な修正。
Ixrec

5
「遅かれ早かれ、あなたはすべてのクラスのサブクラスを作成するつもりです」はほとんど間違いなくそうではありません。」さらに重要なことは、ほとんど確実にそうではなく、クラスのすべての関数をオーバーライドし、クラスのすべてのデータ要素の使用法を変更することです。クラスが何らかの意味を持つためには、論理的に石で書かれたものが必要です。
ジェイ

1
できれば+1以上投げます =>それが賞金@abluejellyと呼ばれるものです
Thomas Ayoub

256

OOPでは、遅かれ早かれ、クラスのサブクラスを作成します

これは間違っています。すべてのクラスがサブクラス化されることを意図しているわけではなく、静的に型付けされたOOP言語の中には、それを防ぐ機能final(たとえば、JavaおよびC ++)やsealed(C#)を備えているものもあります。

理解し、実装を完全に変更できると便利です。

いいえ、ちがいます。クラスがパブリックインターフェイスを明確に定義し、継承された場合でも不変式を保持できると便利です。

一般に、アクセス制御は区分化に関するものです。コードの残りの部分との相互作用を詳細に理解する必要なく、コードの個々の部分を理解する必要があります。プライベートアクセスはそれを許可します。すべてが少なくとも保護されている場合、基本クラスがどのように機能するかを理解するために、すべてのサブクラスが何をするかを理解する必要があります。

または、Scott Meyersの観点から言えば、クラスのプライベートな部分は、有限量のコード(クラス自体のコード)の影響を受けます。

パブリック部分は、存在するすべてのコード、およびまだ記述されていないすべてのコードによって潜在的に影響を受けます。これは無限のコードです。

保護された部分は、既存のすべてのサブクラスと、まだ記述されていないすべてのサブクラスの影響を受ける可能性がありますが、これも無限のコードです。

結論は、保護されたものは公共の場よりもほとんど得られないのに対して、私的なものは実際の改善をもたらしたということです。疑わしいのはプライベートではなく、保護されたアクセス指定子の存在です。


34
「無限のコードの影響を受ける」という理論的シナリオの+1
Broken_Window

13
virtualこの回答で概説されている理由により、明示的にとしてマークされていない限り、C#デザイナーが継承メソッドのオーバーライドを禁止することを実際に決定したことにも注意する価値があります。
ウィルVousden

11
または簡単に言うとprotected、データメンバーではなくメソッド用です。
マチューM.

7
今は見つけることができませんが、@ EricLippertからsealed、.netのライブラリのMSの大きな部分とIIRCが残りをロックしたかった理由についてよく書かれた答えを読んだことを覚えています。サードパーティの継承者が内部値に触れることを許可した瞬間に、オブジェクトの内部状態に関する設計不変条件を信頼できなくなるため、すべてのメソッドに膨大な量の検証/健全性チェックを追加する必要があります。
ダン・ニーリー

4
@ThorbjørnRavnAndersen「開発中だがリリースされていないとき」-クラスは一体どうやって知るべきなのか?リリースバージョンをテストすることさえできないときに、リリースバージョンとは異なるテストバージョンをコンパイルしますか?とにかく、テストではプライベートなものにアクセスする必要はありません。
セバスチャンレッド

33

はい、プライベートフィールドは絶対に必要です。今週は、辞書に入れるものを制御するカスタム辞書の実装を書く必要がありました。辞書フィールドを保護または公開する場合、私が非常に慎重に記述したコントロールは簡単に回避できたはずです。

プライベートフィールドは、通常、データが元のコーダーが予期したとおりであることを保証するためのものです。すべてを保護/公開し、これらの手順と検証を通じてコーチと馬に乗ります。


2
「コーチと馬に乗って」何でも+1。これは素晴らしいフレーズです。
ニックハートリー

2
誰かがあなたのクラスをサブクラス化する必要がある場合、おそらく彼はあなたのセーフガードにアクセスできるはずですか?そして、誰かが何らかの目標を達成するためにセーフガードを変更したくない場合は、おそらくコードを共有しないでください。Rubyではこのように機能します-プライベートは多かれ少なかれ推奨事項です。
アダムリブシャ

3
@AdamLibuša「コードを共有しないでください」?DLLを公開するとすぐに、コードを共有します- 特にデフォルトでリフレクションをサポートする言語では、すべての構造とメソッドとすべてが世界中に表示されます。誰もが「あなたのコード」で好きなことを行うことができます- private「これらに触れないでください」と言うだけの方法であり、コンパイラ規約内で強制されます。.NETのようなシステムでは、これも重要なセキュリティの意味を持ちます-完全な信頼(基本的にはadmin / rootアクセスと同等)がある場合にのみ、他のプライベートに触れることができます。
ルアーン

2
@AdamLibušaあなたの混乱は主に、さまざまな言語が取ったさまざまなOOPアプローチに起因すると思います。OOPのルート(最初に定義したとおり)はメッセージングです。つまり、応答するメッセージを除き、すべてがプライベートです。ほとんどのOOPish言語では、これは「データを非公開にする」として公開されています。これは、パブリックインターフェイスをできるだけ小さくする方法です。ユーザー(サブクラスまたは別のクラス)がクラスを操作する唯一の方法は、定義したパブリックインターフェイスを使用することです。通常、ハンドルとペダルを使用して車を運転する方法と同様です。)
Luaan

3
@Luaan +1は、他の人のプライベートに触れても大丈夫です!
ナイジェルタッチ

12

オブジェクト指向プログラムの正確性について正式に推論しようとするとき、オブジェクト不変式を含むモジュール式アプローチを使用するのが一般的です。このアプローチでは

  1. メソッドには、事前条件と事後条件(契約)が関連付けられています。
  2. オブジェクトには不変条件が関連付けられています。

オブジェクトに関するモジュラー推論は次のように進みます(少なくとも最初は近似値まで)

  1. オブジェクトのコンストラクターが不変式を確立することを証明する
  2. 非プライベートメソッドごとに、オブジェクトの不変条件とメソッドの前提条件が入り口で保持されると仮定し、その後、コードの本体がメソッドの出口で事後条件と不変条件が保持することを意味することを証明します

object A上記のアプローチを使用して検証することを想像してください。そして今、検証したいmethod gobject B呼び出すmethod fobject A。モジュラー推論によりmethod g、の実装を再検討する必要なく推論することができますmethod f。呼び出しサイトの不変object A条件と前提条件を確立できれば、事後条件をメソッド呼び出しの動作の要約として取ることができます。さらに、呼び出しが戻った後も、不変式が保持されることもわかります。method fmethod g,method fA

推論のこのモジュール性は、大きなプログラムについて正式に考えることを可能にするものです。各メソッドについて個別に推論し、次にこの推論の結果を構成して、プログラムの大部分について推論することができます。

このプロセスでは、プライベートフィールドは非常に便利です。オブジェクトの不変式がそのオブジェクトの2つのメソッドコール間で保持され続けることを知るために、通常、オブジェクトが介入期間中に変更されないという事実に依存します。

オブジェクトがプライベートフィールドを持たないコンテキストで機能するモジュラー推論の場合、別のオブジェクトによって設定されたフィールドが何であれ、不変式が常に(フィールドの後に)再確立されることを保証する方法が必要です。セットする)。オブジェクトのフィールドがどの値を持っているかに関係なく、プログラムの正確さについて推論するのに役立つオブジェクト不変式を想像することは困難です。フィールドアクセスに関する複雑な規則を考案する必要があるでしょう。また、おそらくモジュール式の推論能力の一部(最悪の場合はすべて)も失われます。

保護フィールド

保護されたフィールドは、モジュール式に推論する能力の一部を復元します。言語によっては、protectedすべてのサブクラスまたはすべてのサブクラスと同じパッケージクラスにフィールドを設定する機能が制限される場合があります。私たちが書いているオブジェクトの正確さについて推論しているとき、すべてのサブクラスにアクセスできない場合がよくあります。たとえば、後で大きなプログラム(またはいくつかの大きなプログラム)で使用されるコンポーネントまたはライブラリを作成している場合があります。その一部はまだ作成されていない場合もあります。通常、サブクラス化されるかどうか、どのような方法でサブクラス化されるかはわかりません。

ただし、通常、サブクラスは、拡張するクラスのオブジェクトの不変式を維持する義務があります。したがって、保護が「サブクラス」のみを意味し、サブクラスが常にスーパークラスの不変式を維持するように訓練されている言語では、プライベートの代わりに保護を使用する選択は最小限のモジュール性のみを失うと主張することができます。

私は正式な推論について話してきましたが、多くの場合、プログラマーがコードの正確性について非公式な理由をとると、同様の種類の引数に依存することもあると考えられます。


8

privateクラス内の変数は、ブロック内のステートメントがステートメントよりも優れprotectedているという同じ理由で優れています。そのことで、人間のプログラマがエラーを起こしやすいです。 breakswitchgoto label

protected変数gotoがスパゲッティコードの作成に役立つように、変数は意図しない悪用(プログラマーの間違い)に役立ちます。

protectedクラス変数を使用してバグのない動作するコードを書くことは可能ですか?はい、もちろん!を使用してgoto、バグのない作業コードを書くことができるように、しかし、決まり文句にあるように、「できるからといって、そうすべきだという意味ではありません!」

クラス、そして実際にオブジェクト指向のパラダイムは、不幸なエラーを起こしやすい人間のプログラマーがミスを犯すのを防ぐために存在します。人的ミスに対する防御は、クラスに組み込まれた防御手段と同じくらい優れています。クラスを実装protectedすることは、要塞の壁に巨大な穴を開けることに相当します。

基本クラスには、派生クラスの知識はまったくありません。基本クラスに関しては、派生クラスがバックドアのように振る舞うゲッター/セッターを作成するのを止めるものは何もないので、protected実際にはを超える保護は提供しません。publicpublic

基本クラスが内部実装の詳細への妨げられないアクセスを許可する場合、クラス自体がミスを防ぐことができなくなります。基本クラスには、派生クラスの知識がまったくないため、派生クラスでのミスを防ぐ方法はありません。

基本クラスでできる最善の方法は、実装を可能な限り隠しprivate、派生クラスまたはクラス外の何かからの変更を壊さないように十分な制限を設けることです。

最終的には、ヒューマンエラーを最小限に抑えるための高レベル言語が存在します。ヒューマンエラーを最小限に抑えるための優れたプログラミングプラクティス(SOLID原則など)も存在します。

優れたプログラミング手法を無視するソフトウェア開発者は、失敗する可能性がはるかに高く、壊れた保守不可能なソリューションを作成する可能性が高くなります。優れた慣行に従う人は、失敗する可能性がはるかに低く、実用的な保守可能なソリューションを生み出す可能性が高くなります。


ダウンボッターに-この回答について何を変更/改善できますか?
ベンコットレル

私は反対票を投じませんでしたが、アクセスレベルをbreak / gotoと比較しますか?
imel96

@ imel96いいえ、それらが回避された理由を比較し、「ベストプラクティス」(特に新しいコードを書くため)で落胆しています。すなわち、有能なプログラマーはpublic、維持できないコードに役立つので、実装の詳細を避けるでしょう。有能なプログラマーはgoto、保守不能なコードに向いているので避けるでしょう。ただし、現実の世界では、レガシーコードの恐ろしい混乱に紛れてしまい、使用するgoto以外に選択肢がない場合があります。その同じ理由で、パブリック/保護された実装の詳細を使用する以外に選択肢がない場合があります。
ベンコットレル

重大度は大きさが異なり、比類のないものです。publicプロパティ/インターフェイスのみを持つコードで生きることはできますが、のみを使用するコードでは生きられませんgoto
imel96

2
@ imel96 gotoあなたはそのような記事を読んだからといって、それを使用するコードで働いたことがありますか?私はそれを使用する古代のコードで2年間働いてきたので、なぜ goto悪なの理解しています。そして、「クラス」の実装の詳細がどこにでも漏れておりpublicfriend指定子がクイック/イージー/ダーティハックとして使用されるコードでさらに長い時間を費やしました。「実装の詳細を公開する」ことは、goto絶対にできるのと同じレベルの重大度で絡み合ったスパゲッティの混乱を引き起こさないという議論を受け入れません。
ベンコットレル

4

継承可能なクラスには、オブジェクト参照の所有者と派生クラスの2つのコントラクトがあります。パブリックメンバーは参照ホルダーとの契約に拘束され、保護メンバーは派生クラスとの契約に拘束されます。

メンバーprotectedを作成すると、より汎用性の高い基本クラスになりますが、多くの場合、クラスの将来のバージョンが変更される可能性が制限されます。メンバーを作成privateすると、クラス作成者はクラスの内部動作をより柔軟に変更できますが、そのクラスから有効に派生できるクラスの種類が制限されます。

例として、List<T>.NETでは、バッキングストアをプライベートにします。それが保護されていれば、派生型は他の方法では不可能ないくつかの有用なことを行うことができますが、将来のバージョンでList<T>は、数百万のアイテムを保持するリストであっても、その不格好なモノリシックバッキングストアを永遠に使用する必要があります。バッキングストアをプライベートにすると、List<T>派生クラスを壊すことなく、将来のバージョンでより効率的なバッキングストアを使用できるようになります。


4

だれかがクラスを書いたとき、誰がそのクラスを道の下に広げるかもしれないか、どんな理由で知らないかという重要な仮定があると思います。この仮定を考えると、プライベートにするすべての変数は、将来の開発の道を断ち切る可能性があるため、あなたの議論は完全に理にかなっています。ただし、その仮定は拒否します。

その仮定が拒否された場合、考慮すべきケースは2つだけです。

  1. 元のクラスの作成者は、なぜそれが拡張されるのかについて非常に明確なアイデアを持っていました(例えば、BaseFooであり、今後いくつかの具体的なFoo実装があります)。

この場合、作成者は、誰かがクラスを拡張することとその理由を知っているため、何を保護し、何をプライベートにするかを正確に知ることができます。プライベート/保護された区別を使用して、サブクラスを作成するユーザーに並べ替えのインターフェイスを伝えています。

  1. 子クラスの作成者は、ある動作を親クラスにハッキングしようとしています。

このケースはまれである必要があり(正当ではないと主張することもできます)、元のコードベースの元のクラスを変更することよりも好ましくありません。それはまた、悪いデザインの症状かもしれません。そのような場合、行動にハッキングする人は、友人(C / C ++)やsetAccessible(true)(Java)のような他のハックを使用することを好みます。

その仮定を拒否するのは安全だと思います。

これは一般に、継承より合成の概念にフォールバックします。継承は、コードの再利用を減らす理想的な方法としてよく教えられますが、コードの再利用の最初の選択肢になることはめったにありません。私は単純なノックダウンの議論を持っていませんし、理解するのはかなり難しく、議論が多いかもしれません。しかし、ドメインモデリングの経験から、クラスを誰が継承するのか、そしてその理由を明確に理解していないと、継承をほとんど使用しないことがわかりました。


2

3つのアクセスレベルすべてにユースケースがありますが、OOPはそれらのいずれかを欠いて不完全です。通常は

  • すべての変数/データメンバーをprivateにします。外部から誰かがあなたの内部データを台無しにしたくない。また、パブリックまたは保護されたインターフェイスに補助機能(いくつかのメンバー変数に基づいた計算を考える)を提供するメソッド-これは内部使用専用であり、将来変更または改善したい場合があります。
  • クラスの一般的なインターフェイスをpublicにします。それが、元のクラスのユーザーが操作することになっているものであり、派生クラスもどのように見えるべきだと思うかです。適切なカプセル化を提供するために、これらは通常メソッド(およびヘルパークラス/構造、列挙、typedef、ユーザーがメソッドを操作するために必要なもの)のみであり、変数ではありません。
  • クラスの機能を拡張/特化したいが、パブリックインターフェイスの一部であってはならない人に役立つ保護されたメソッドを宣言します。実際、通常、プライベートメンバーを必要に応じてprotectedに上げます。疑わしい場合は、あなたがそれを知るまで
    1. あなたのクラスはサブクラス化することができます/可能性があります/
    2. サブクラス化のユースケースが何であるかを明確に把握します。

そして、正当な理由がある場合にのみ、この一般的なスキームから逸脱します。「外部から自由にアクセスできる場合、これにより私の生活が楽になる」ことに注意してください(そして、ここの外部にはサブクラスも含まれます)。クラス階層を実装するとき、私はしばしば保護されたメンバーを持たないクラスから始めます、それらをサブクラス化/拡張/特化するまで、フレームワーク/ツールキットの基本クラスになり、時には元の機能の一部を1レベル上に移動します。


1

おそらくもっと興味深い質問は、なぜプライベート以外のフィールドが必要なのかということです。サブクラスがスーパークラスのデータとやり取りする必要がある場合、2つの間の直接的なカップリングが直接作成されますが、2つの間のやり取りを提供するメソッドを使用すると、間接的なレベルで変更が可能になりますそうでなければ非常に難しいスーパークラス。

多くの言語(RubyやSmalltalkなど)はパブリックフィールドを提供しないため、開発者はクラスの実装に直接結合することをお勧めしませんが、さらに進んでプライベートフィールドしか持たないのはなぜですか?一般性が失われることはありません(スーパークラスは常にサブクラスの保護されたアクセサーを提供できるため)が、クラスが常にサブクラスから少なくともある程度分離されるようにします。なぜこれがより一般的な設計ではないのですか?


1

ここでは多くの良い答えがありますが、とにかく2セントを投入します。:-)

プライベートは、グローバルデータが悪いのと同じ理由で良いです。

クラスがデータプライベートを宣言する場合、このデータを混乱させる唯一のコードはクラス内のコードであることを完全に知っています。バグがある場合、このデータを変更する可能性のあるすべての場所を見つけるために、作成全体を検索する必要はありません。あなたはそれがクラスにあることを知っています。コードを変更し、このフィールドの使用方法について何かを変更する場合、このフィールドを使用する可能性のあるすべての場所を追跡し、計画された変更がそれらを破壊するかどうかを調べる必要はありません。クラス内には唯一の場所があります。

ライブラリ内にあり、複数のアプリで使用されているクラスに変更を加える必要が何度もありました。また、何も知らないアプリを壊さないように非常に注意深く踏まなければなりません。パブリックデータと保護データが多いほど、トラブルが発生する可能性が高くなります。


1

反対意見を述べる価値があると思います。

理論的には、他の回答に記載されているすべての理由でアクセスレベルを制御した方がよいでしょう。

実際には、コードをレビューするときにあまりにも頻繁に、プライベートを使用したい人、プライベートから保護されたアクセスレベルを変更する人、そして保護されていない人から公共の人へのアクセスレベルを変更します。ほとんどの場合、クラスプロパティの変更には、セッター/ゲッターの変更が伴います。これらは私の時間(コードレビュー)とそれら(コードの変更)の多くを無駄にしました。

また、クラスが修正のために閉じられていないことを意味します。

それは、必要に応じていつでも変更できる内部コードでした。コードを変更するのがそれほど簡単ではない場合、サードパーティのコードでは状況はさらに悪化します。

では、面倒だと思うプログラマーは何人いるでしょうか?さて、プライベートを持たないプログラミング言語を使用している人はどれくらいいますか?もちろん、プライベートな指定子がないため、人々はこれらの言語を使用しているだけではありませんが、言語を簡素化するのに役立ち、シンプルさが重要です。

いも、それは動的/静的型付けに非常に似ています。理論的には、静的型付けは非常に優れています。実際には、それだけで、エラーの2%のように防ぎ、動的型付けの不合理な効果を...。privateを使用すると、おそらくそれ以下のエラーを防ぐことができます。

SOLIDの原則は良いと思います。一般、保護、非公開でクラスを作成することよりも、人々がそれらに関心があることを望みます。


1
サードパーティのコードを使用するときにコードを変更する必要がある場合は、適切に設計されていないか、うまく再利用されていません。非抽象クラスは、カプセル化することでいつでも再利用できますが、実際には、サブクラスを作成する必要はほとんどありません。
リトルサンティ

0

また、なぜprotected不十分なのかという別の実用的な例を追加したいと思います。私の大学では、最初の年に、デスクトップバージョンのボードゲームを開発しなければならないプロジェクトに取り組みます(後にAIが開発され、ネットワークを介して他のプレイヤーに接続されます)。テストフレームワークを含め、それらを開始するために、いくつかの部分的なコードが提供されます。メインゲームクラスのプロパティの一部は、protectedこのクラスを拡張するテストクラスがアクセスできるように公開されています。ただし、これらのフィールドは機密情報ではありません。

ユニットのためのTAとして、私は多くの場合、学生は、単純にすべての追加されたコードの作成を参照してくださいprotectedpublic(彼らは他の見たせいかprotectedpublicものを、彼らはスーツに従うべきであると仮定しました)。私は彼らに保護レベルが不適切である理由を尋ねます、そして多くはその理由を知りません。答えは、サブクラスに公開している機密情報は、別のプレイヤーがそのクラスを拡張し、ゲームの非常に機密情報にアクセスすることでごまかすことができることを意味するということです(基本的に、相手の隠された場所、いくつかのクラスを拡張することにより、戦艦ボード上で敵の駒を見ることができました)。そのため、ゲームのコンテキストではコードが非常に危険になります。

それ以外にも、サブクラスに対してもプライベートなものを保持する他の多くの理由があります。何をしているのかを必ずしも知らない人(ほとんどの場合、ここでコードを使用している他の人のことを考えている)によって変更された場合、クラスの正しい動作を台無しにする可能性のある実装の詳細を隠すことがあります。


1
分かりません。ゲームの実行中にプレイヤーがクラスを動的に拡張しない限り、これを使用してチートを行うことができますか?これは、信頼できないコードをコードベースにインポートしていることを意味します。生徒にコンパイルされたクラスを提供し、実装の詳細を変更することで課題の不正行為を防ぐと言っている場合、保護レベルを設定しても課題の安全性は向上しません。学生はライブラリを逆コンパイルしたり、リフレクションを使用して自分の利点を生かすことができます。もちろん、これはあなたが求めている施行レベルに依存します。
サム

@sam一般的に、コードは、次に変更する人がコードベース全体を完全に知る必要がないという前提で作成する必要があります。それは時々オリジナルの作者でさえあるかもしれません(時間が経つ、睡眠不足...)。不正行為は、学生が肉体化するためのスケルトンコードを与えられたり、触れてはならないロジックを変更したりする可能性があります。
フィルレロ

0

プライベートメソッド/変数は通常、サブクラスから隠されます。それは良いことです。

プライベートメソッドは、パラメータに関する仮定を行い、呼び出し元に健全性チェックを任せることができます。

保護されたメソッドは、入力健全性チェックする必要があります。


-1

「プライベート」とは、クラス自体以外の人が変更またはアクセスすることを意図したものではありません。サブクラスによって変更またはアクセスされることを意図していません。サブクラス?どのサブクラスですか?これをサブクラス化することはできません!

「保護」とは、クラスまたはサブクラスによる変更またはアクセスのみを目的としています。あなたはサブクラスになっているはずだと推測されますが、そうでなければ「プライベート」ではなく「保護」されます。

ここには明確な違いがあります。私が何かをプライベートにすると、あなたは汚れた指をそれから離しておくことになっています。あなたがサブクラスであっても。


-1

クラスをサブクラス化するときに最初に行うことの1つは、プライベートメソッドの束をprotectedに変更することです。

privateprotected メソッドに関するいくつかの推論:

privateメソッドはコードの再利用を防ぎます。サブクラスは、プライベートメソッドのコードを使用できないため、再度実装する必要があります-または、もともとプライベートメソッド&cに依存していたメソッドを再実装する必要があります。

一方、他の誰かが彼の答えで示唆したように、サードパーティのサブクラスも「外界」と見なされるという意味で、クラスによって「外界」に提供されるAPIとは見なされない メソッドprivate既に。

それは悪いことですか?-そうは思いません。

もちろん、(擬似)パブリックAPIは元のプログラマをロックし、それらのインターフェイスのリファクタリングを妨げます。しかし、逆の見方をすると、なぜプログラマーはパブリックAPIと同じくらいクリーンで安定した方法で、独自の「実装の詳細」を設計しないのでしょうか?private彼は自分の「プライベート」コードを構造化するのにだらしないように使うべきでしょうか?おそらく誰も気付かないので、後でそれをきれいにすることができると思いますか?- 番号。

プログラマーは、「プライベート」コードにも少し考えを入れて、そもそも可能な限り多くのコードの再利用を許可または促進するような方法で構造化する必要があります。そうすれば、非プライベートな部分は、将来不安になるほどの負担にはならないかもしれません。

私が見る多くの(フレームワーク)コードは、一貫性のないprivate:の使用を採用していますprotected。プライベートメソッドに委任する以上のことをほとんど行わない非最終メソッドは一般的に見られます。protected、プライベートフィールドへの直接アクセスによってのみ契約を履行できる非最終メソッド。

これらのメソッドを論理的にオーバーライド/強化することはできませんが、技術的には(コンパイラー)を明白にするものはありません。

拡張性と継承が必要ですか?メソッドを作成しないでくださいprivate

クラスの特定の動作を変更したくないですか?メソッドを作成しますfinal

特定の明確に定義されたコンテキストの外部でメソッドを呼び出すことは本当にできませんか?メソッドprivateを作成するか、必要な明確に定義されたコンテキストを別のprotectedラッパーメソッドで再利用できるようにする方法について考えてください。

だからこそ、private控えめに使用することをお勧めします。と混同privateしないようにfinal。-メソッドの実装がクラスの一般的な契約に不可欠であり、したがって置き換えたりオーバーライドしたりしてはならない場合は、それを作成してfinalください!

フィールドについてprivateは、それほど悪くはありません。フィールドが適切なメソッドを介して合理的に「使用」できる限り(そうでない getXX()setXX()!)。


2
-1これは対応していないprivateVS protected元の質問を、間違えアドバイスを与える(「使うprivate控えめに」?)とオブジェクト指向設計上の一般的なコンセンサスに反します。を使用privateすることは、ずさんなコードを隠すこととは関係ありません。
アンドレスF.

3
クラスにはAPIがあると言いますが、APIのユーザーが知りたいことのない詳細に煩わされることを望まない接続を行うようには思われません。クラスのユーザーにとって理想的な状況は、インターフェースに必要なメソッドのみが含まれ、他には何も含まれないことです。メソッドprivateを作成すると、APIをクリーンに保つのに役立ちます。
ベンコットレル

1
@HannoBinder剛性に苦しむクラスがたくさんあることに同意しますが、カプセル化や長期的な保守性よりも柔軟性とコードの再利用はそれほど重要ではありません。すべてのクラスが保護されたメンバーを持ち、派生クラスが希望する実装の詳細を台無しにできる場合を考えてください。まだ書かれていないコードのどの部分でも、そのコードがいつでも失敗する可能性があることを知って、これらのクラスを確実にユニットテストしますか?コードが泥の大きな塊に変質する前に、そのような「ハッキング」を何回行うことができますか?
ベンコットレル

2
ああ、あなたは「メンバー」と言った。私が言っているのはメソッドのみを指している。メンバー変数(フィールド)は、プライバシーがはるかに正当化される別の話です。
-JimmyB

2
議論の命名法は特定の言語に固有ではないため、あちこちにあります。C ++の「メンバー」には、データ、関数、型、またはテンプレートを指定できます。
JDługosz

-1

protectedではなくprivateが優れたツールである重要なユースケースについて知っていますか、またはOOP言語では「protected&public」の2つのオプションで十分ですか?

プライベート:サブクラスが呼び出したりオーバーライドしたりするのに決して有用ではないものがある場合。

保護:サブクラス固有の実装/定数を持つものがある場合。

例:

public abstract Class MercedesBenz() extends Car {
  //Might be useful for subclasses to know about their customers
  protected Customer customer; 

  /* Each specific model has its own horn. 
     Therefore: protected, so that each subclass might implement it as they wish
  */
  protected abstract void honk();

  /* Taken from the car class. */
  @Override
  public void getTechSupport(){
     showMercedesBenzHQContactDetails(customer);
     automaticallyNotifyLocalDealer(customer);
  }

  /* 
     This isn't specific for any subclass.
     It is also not useful to call this from inside a subclass,
     because local dealers only want to be notified when a 
     customer wants tech support. 
   */
  private void automaticallyNotifyLocalDealer(){
    ...
  }
}

2
サブクラスが呼び出したりオーバーライドしたりするのに決して役に立たないものがある場合 -これは、私の意見では、事前に知ることがないものです。
アダムリブシャ

まあ、CMOSのリセットボタンを押す必要があるかもしれません。しかし、デフォルトの仮定では、私はそれを本当に必要としないので、シャーシ内に置かれます。メソッドについても同じことが言えます。サブクラスが絶対に再実装/呼び出しが必要な場合は保護します(参照:ホーンキング)。他の関係者がそれを呼び出す必要がある場合は、公開します。
アーナブダッタ

-2

この問題を理解するのは困難だったので、私の経験の一部を共有したいと思います。

  • 保護フィールドとは何ですか?それはだんの何物でもすなわち、クラス外部からアクセスすることができない分野、より公にこのように:$classInstance->field。そして、これが「これだ」というトリック。それは彼らの正当な内部部分であるため、あなたのクラスの子供たちはそれに完全にアクセスできます。
  • プライベートフィールドとは何ですか?これは、独自のクラスおよびこのクラスの独自の実装に対する「真のプライベート」です。薬瓶のように、「子供の手の届かないところに保管してください」。呼び出されたときに- -あなたはそれがあなたのクラスの誘導体、あなたの方法でunoverridableだという保証はありますがあります正確なあなたが宣言したもの

更新:私が解決した実際のタスクによる実用的な例。ここにあります:USBやLPT(私の場合)のようなトークンがあり、ミドルウェアがあります。トークンはPINコードの入力を求め、それが正しい場合は開き、暗号化された部分といくつかのキーを解読に送信できます。キーはトークンに保存されます。キーを読み取ることはできず、使用するだけです。また、トークンのキーで署名されたセッション用の一時キーがありましたが、ミドルウェア自体に保存されていました。一時キーは、ドライバーレベルで存在するためだけに、外部のどこにでも漏れることは想定されていませんでした。そして、プライベートフィールドを使用して、この一時キーとハードウェア接続関連のデータを保存しました。したがって、パブリックインターフェイスだけでなく、保護されたインターフェイスも使用できるデリバティブはありませんでしたタスク用に作成した「便利な」サブルーチンですが、キーとHWインタラクションでストロングボックスを開くことができませんでした。理にかなっていますか?


ごめんなさい!それらを台無しにした-私の答えを更新=)ありがとう!私は急いでタイプミスしました=)
Alexey Vesnin

2
OPは2つの保護レベルの違いを認識していると思いますが、なぜ一方を他方よりも使用する必要があるのか​​興味があります。
サム

@サムは私の答えをより深く読んでください。それらはまったく異なる種類のフィールドです!唯一、彼らが共通している事は、彼らの両方が公に参照することができないということである
アレクセイVesnin

2
何を言っているのか分かりません。私はプライベートと保護の違いを知っています。おそらく、保護レベルの意味を誤解したのでしょうか?私は「アクセスレベル」に言及しています。あなたの答えは悪くないが、それは質問に直接対処しないことを指摘しようとした。OPは保護/プライベート/パブリックの両方の意味を知っているように見えますが、どのような状況でどちらを選択したいかはわかりません。これはあなたが(私によってではなく)投票された方法かもしれません。
サム

@Sam私はあなたのポイントを持っていると思う-私の実際の練習/経験から実用的なケースを追加しました。あなたのポイントに欠けているものはありますか?
アレクセイ・
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.