22

オブジェクト指向プログラミングの最大の利点の 1 つはカプセル化であり、私たちが (または少なくとも私が) 教えられてきた "真実" の 1 つは、メンバーは常に非公開にし、アクセサーとミューテーターを介して利用できるようにする必要があるということです。これにより、変更を検証および検証する機能が保証されます。

しかし、これが実際にどれほど重要なのか、私は興味があります。特に、より複雑なメンバー (コレクションなど) がある場合、コレクションのキーを取得したり、コレクションから項目を追加/削除したり、等

一般的にルールを守っていますか?自分用に書かれたコードか、他の人が使用するコードかによって、答えは変わりますか? この難読化のために私が見逃しているもっと微妙な理由はありますか?

4

22 に答える 22

16

過去に多くの人が取り組んできた数年前のコードを維持しなければならない人として、メンバー属性が公開されると、最終的には悪用されることは明らかです。アクセサやミューテータのアイデアに反対する人もいます。それは、「クラスの内部の仕組みを隠す」というカプセル化の目的をまだ実際に果たしていないからです。これは明らかに物議を醸すトピックですが、私の意見は、「すべてのメンバー変数をプライベートにし、内部変数を変更させる方法ではなく、クラスが何をしなければならないか(メソッド)を主に考えてください」です。

于 2008-09-19T04:49:57.367 に答える
16

場合によります。これは、実際的に決定しなければならない問題の1つです。

ポイントを表すクラスがあったとします。X座標とY座標のゲッターとセッターを使用することも、両方を公開してデータへの無料の読み取り/書き込みアクセスを許可することもできます。私の意見では、クラスは栄光の構造体のように機能しているため、これは問題ありません。データ収集には、いくつかの便利な関数が添付されている可能性があります。

ただし、内部データへのフルアクセスを提供したくない場合や、オブジェクトと対話するためにクラスによって提供されるメソッドに依存する場合は、多くの状況があります。例として、HTTPリクエストとレスポンスがあります。この場合、誰でもネットワーク経由で何かを送信できるようにすることはお勧めできません。クラスメソッドで処理およびフォーマットする必要があります。この場合、クラスは単純なデータストアではなく、実際のオブジェクトとして考えられています。

動詞(メソッド)が構造を駆動するかどうか、またはデータが駆動するかどうかにかかっています。

于 2008-09-19T04:52:13.147 に答える
8

はい、カプセル化は重要です。基礎となる実装を公開すると、(少なくとも) 2 つの問題が発生します。

  1. 責任を混同します。呼び出し元は、基礎となる実装を理解する必要はなく、理解する必要もありません。彼らは、クラスにその仕事をしてもらいたいだけです。基礎となる実装を公開することにより、クラスはその仕事をしていません。代わりに、呼び出し元に責任を押し付けているだけです。
  2. 基礎となる実装に結び付けます。基礎となる実装を公開すると、それに縛られます。たとえば、その下にコレクションがあることを呼び出し元に伝えた場合、そのコレクションを新しい実装に簡単に交換することはできません。

これら (およびその他) の問題は、基礎となる実装への直接アクセスを許可するか、基礎となるすべてのメソッドを単に複製するかに関係なく適用されます。必要な実装のみを公開する必要があります。実装を非公開にすることで、システム全体がより保守しやすくなります。

于 2008-09-19T05:10:33.493 に答える
3

私は、メンバーをできるだけプライベートに保ち、まったく同じクラス内からでも、ゲッターを介してのみemにアクセスすることを好みます。また、可能な限りバリュースタイルのオブジェクトを宣伝するための最初のドラフトとしてセッターを避けるようにしています。クライアントはオブジェクトを構成できるはずですが、(他の人は)これが実装の詳細であるため、実際に何が構成されているかを知ることができないため、依存性注入を頻繁に使用すると、セッターはありますがゲッターはありません。

よろしく、Ollie

于 2008-09-19T04:55:40.427 に答える
2

自分のコードであっても、ルールを厳密に守る傾向があります。そのため、C#のプロパティが本当に好きです。与えられた値を制御するのは本当に簡単ですが、それでも変数として使用できます。または、セットをプライベートにして公開するなど。

于 2008-09-19T04:51:26.410 に答える
2

基本的に、情報隠蔽はコードの明確さに関するものです。他の誰かがあなたのコードを拡張しやすくし、クラスの内部データを操作するときに誤ってバグを作成するのを防ぐように設計されています。これは、コメント、特に指示が含まれているコメントを誰も読まないという原則に基づいています。

例:変数を更新するコードを書いていますが、Gui がその変更を反映するように確実に変更する必要があります。最も簡単な方法は、アクセサ メソッド (別名「セッター」) を追加することです。更新データが更新されます。

そのデータを公開し、Setter メソッドを介さずに何かが変数を変更した場合 (そして、これは悪口のたびに発生します)、更新が表示されない理由を見つけるために誰かが 1 時間のデバッグを費やす必要があります。データの「取得」にも同じことが当てはまりますが、それほどではありません。ヘッダー ファイルにコメントを入れることもできますが、何かがひどく、ひどくおかしくなるまで、誰もそれを読まない可能性があります。private で強制すると、実行時のバグではなく、簡単に見つけられるコンパイル時のバグとして表示されるため、間違いを犯すことができなくなります。

経験上、メンバー変数を public にして、Getter メソッドと Setter メソッドを省略したいのは、それを変更しても副作用がないことを明確にしたい場合だけです。特に、単純に 2 つの変数をペアとして保持するクラスのように、データ構造が単純な場合。

通常は副作用が必要なため、これはかなりまれに発生するはずです。また、作成しているデータ構造が非常に単純であり、作成しない場合 (ペアリングなど) は、より効率的に記述されたものが既に利用可能です。標準ライブラリで。

そうは言っても、大学で取得するような、1回限りの拡張機能のないほとんどの小さなプログラムの場合、それは何よりも「良い習慣」です。それらを手渡し、二度とコードに触れることはありません。また、リリース コードとしてではなく、データの格納方法を調べる方法としてデータ構造を記述している場合、Getter と Setter は役に立たず、学習体験の邪魔になるという良い議論があります。 .

職場や大規模なプロジェクトに着手したときだけ、さまざまな人によって書かれたオブジェクトや構造によってコードが呼び出される可能性が高くなり、これらの「リマインダー」を強化することが不可欠になります。それが一人のプロジェクトであるかどうかは、驚くほど無関係です。「今から 6 週間後のあなた」は、同僚と同じように別人であるという単純な理由からです。そして、「6 週間前の私」は怠け者であることがよくあります。

最後のポイントは、一部の人々は情報の隠蔽にかなり熱心であり、データが不必要に公開されるとイライラすることです。それらをユーモアにするのが最善です。

于 2008-09-19T07:46:07.927 に答える
1

C#プロパティは、パブリックフィールドを「シミュレート」します。見た目はかなりクールで、構文はこれらのget/setメソッドの作成を本当にスピードアップします

于 2008-09-19T04:55:43.263 に答える
0

私は、モジュール内のコードの深さに基づいて決定を下します。モジュールの内部にあり、外部とのインターフェースをとらないコードを書いている場合、プログラマーのパフォーマンス(コードの記述と書き換えの速度)に影響を与えるため、プライベートでカプセル化することはあまりありません。

ただし、モジュールのユーザーコードとのインターフェイスとして機能するオブジェクトについては、厳密なプライバシーパターンを順守します。

于 2008-09-19T04:49:15.620 に答える
0

これらの少なくとも1つが成立する場合、カプセル化は重要です。

  1. あなた以外の誰もがあなたのクラスを使うつもりです(または彼らはドキュメントを読まないのであなたの不変条件を壊します)。
  2. ドキュメントを読まない人は誰でもあなたのクラスを使用するでしょう(または彼らはあなたの注意深く文書化された不変条件を壊します)。このカテゴリには、現在から2年後のあなたが含まれることに注意してください。
  3. 将来のある時点で、誰かがあなたのクラスから継承する予定です(フィールドの値が変更されたときに追加のアクションを実行する必要があるため、セッターが必要になる可能性があります)。

それが私だけのものであり、いくつかの場所で使用されており、それを継承するつもりがなく、フィールドを変更してもクラスが想定する不変条件が無効にならない場合にのみ、フィールドを公開することがあります。

于 2008-09-19T04:53:44.500 に答える
0

私の傾向は、可能であればすべてを非公開にしようとすることです。これにより、オブジェクトの境界が可能な限り明確に定義され、オブジェクトが可能な限り分離された状態に保たれます。最初(2回目、5回目?)に失敗したオブジェクトを書き直さなければならないとき、それはより少ない数のオブジェクトに含まれるダメージを保持するので、私はこれが好きです。

オブジェクトを十分に緊密に結合する場合、それらを1つのオブジェクトに結合するだけの方が簡単な場合があります。結合の制約を十分に緩和すると、構造化プログラミングに戻ります。

オブジェクトの束が単なるアクセサ関数であることがわかった場合は、オブジェクトの分割を再考する必要があるかもしれません。そのデータに対してアクションを実行していない場合、そのデータは別のオブジェクトの一部として属している可能性があります。

もちろん、ライブラリのようなものを書いている場合は、他の人がそれに対してプログラムできるように、できるだけ明確でシャープなインターフェイスが必要です。

于 2008-09-19T04:55:25.403 に答える
0

ツールを仕事に合わせてください...最近、現在のコードベースに次のようなコードが表示されました。

private static class SomeSmallDataStructure {
    public int someField;
    public String someOtherField;
}

そして、このクラスは、複数のデータ値を簡単に渡すために内部的に使用されました。必ずしも意味があるとは限りませんが、メソッドがなく、DATAだけがあり、クライアントに公開していない場合は、非常に便利なパターンだと思います。

私がこれを最近使用したのは、JSPページで、データのテーブルが表示され、上部に宣言的に定義されていました。したがって、最初は複数の配列であり、データフィールドごとに1つの配列でした...これにより、コードを通過するのがかなり難しくなり、フィールドが定義で隣り合っていないため、一緒に表示されませんでした...そこで、単純なものを作成しました上記のようなクラスはそれをまとめます...結果は本当に読みやすいコードであり、以前よりもはるかに多くなりました。

道徳的...コードをより単純で読みやすくする可能性がある場合は、「受け入れられた悪い」代替案を検討する必要があります。それを熟考し、結果を検討する限り...聞いたすべてを盲目的に受け入れないでください。

そうは言っても...パブリックゲッターとセッターはパブリックフィールドとほとんど同じです...少なくとも本質的には(少し柔軟性がありますが、それでもすべてのフィールドに適用するのは悪いパターンです)。

Java標準ライブラリでさえ、パブリックフィールドのいくつかのケースがあります。

于 2008-09-19T04:57:49.780 に答える
0

オブジェクトを意味のあるものにすると、使いやすく維持しやすくなります。

例: Person.Hand.Grab(howquick, how much);

秘訣は、メンバーを単純な値ではなく、それ自体がオブジェクトであると考えることです。

于 2008-09-19T05:33:04.533 に答える
0

あなたが与えたもので人々が何をできるかをコントロールすることがすべてです。自分をコントロールすればするほど、より多くの仮定を立てることができます。

また、理論的には、基礎となる実装などを変更できますが、ほとんどの場合は次のとおりです。

private Foo foo;
public Foo getFoo() {}
public void setFoo(Foo foo) {}

正当化するのは少し難しいです。

于 2008-09-19T04:47:54.873 に答える
0

実際には、私は常に 1 つのルールだけに従います。

カプセル化とその重要性は、プロジェクトの成果です。どのオブジェクトがインターフェイスにアクセスするのか、どのように使用するのか、メンバーへの不要なアクセス権を持っているかどうかは問題になりますか? 各プロジェクトの実装に取り​​組む際に自問する必要がある質問など。

于 2008-09-19T04:48:39.083 に答える
0

この質問は、カプセル化の概念と「情報隠蔽」を混同していると主張します
(「カプセル化」の概念の一般的な解釈と一致しているように見えるため、これは批判ではありません)

ただし、私にとって、「カプセル化」は次のいずれかです。

  • 複数のアイテムをコンテナに再グループ化するプロセス
  • アイテムを再グループ化するコンテナー自体

納税者システムを設計しているとします。納税者ごとに、子供の概念を次のようにカプセル化できます。

  • 子を表す子のリスト
  • to のマップは、異なる親からの子を考慮に入れます
  • 必要な情報 (子の総数など) を提供するオブジェクト Children (Child ではない)

ここには 3 種類のカプセル化があり、2 つは低レベルのコンテナー (リストまたはマップ) で表され、1 つはオブジェクトで表されます。

それらの決定を下すことによって、あなたは

  • そのカプセル化を公開するか、保護するか、非公開にするか: 「情報隠蔽」の選択はまだ行われています
  • 完全な抽象化を行う (オブジェクト Children の属性を改良する必要があり、納税者システムの観点から関連情報のみを保持するオブジェクト Child を作成することを決定する場合があります)
    抽象化とは、どの属性を選択するプロセスです。のオブジェクトはシステムに関連しており、完全に無視する必要があります。

つまり、私の要点は次のとおりです。
その質問は次のように題されている可能性があります:
Private vs. Public members in practice (情報の隠蔽はどれほど重要ですか?)

しかし、私の2セントだけです。カプセル化を「情報隠蔽」の決定を含むプロセスと見なすことができることを完全に尊重します。

ただし、私は常に「抽象化」-「カプセル化」-「情報の隠蔽または可視性」を区別しようとしています。

于 2008-09-19T06:25:59.600 に答える
0

@VonC

International Organization for Standardization の「Reference Model of Open Distributed Processing」は興味深い読み物かもしれません。「カプセル化:オブジェクトに含まれる情報は、オブジェクトがサポートするインターフェースでの相互作用を通じてのみアクセスできるというプロパティ」と定義されています。

ここで、情報隠蔽がこの定義の重要な部分であることを主張しようとしました: http://www.edmundkirwan.com/encap/s2.html

よろしく、

エド。

于 2008-10-31T11:05:54.613 に答える
-1

確かに、内部コードを記述しているのか、他の誰かが使用するコード(または自分自身であるが、含まれているユニットとして)を記述しているのかによって違いが生じます。外部で使用されるコードには、明確に定義/文書化されたインターフェイスが必要です。できるだけ変更したくないでしょう。

内部コードの場合、難易度によっては、今は簡単な方法で物事を行う方が手間がかからず、後で少しペナルティを支払うことがあります。もちろん、マーフィーの法則は、カプセル化に失敗したクラスの内部を変更する必要がある場所で、後で広範囲の変更を行う必要があるため、短期間の利益が何度も消去されることを保証します。

于 2008-09-19T04:50:40.327 に答える
-1

特に、返すコレクションを使用する例では、そのようなコレクションの実装が変更され(より単純なメンバー変数とは異なり)、カプセル化の有用性が高くなる可能性があります。

そうは言っても、私はPythonの扱い方が好きです。メンバー変数はデフォルトでパブリックです。それらを非表示にしたり、検証を追加したりする場合は、提供されている手法がありますが、それらは特殊なケースと見なされます。

于 2008-09-19T04:56:38.753 に答える
-1

ここには、既存の回答のほとんどで対処されていない実際的な懸念があります。カプセル化と外部コードへのクリーンで安全なインターフェイスの公開は常に優れていますが、作成しているコードが空間的および/または時間的に大きな「ユーザー」ベースによって消費されることを意図している場合は、はるかに重要です。私が言いたいのは、誰か (あなたでさえも) が将来にわたってコードを保守することを計画している場合、または少数以上の他の開発者からのコードとインターフェイスするモジュールを作成している場合は、もっと多くのことを考える必要があるということです。 1 回限りのコードや完全に自分で作成したコードを作成する場合よりも慎重に検討してください。

正直なところ、私はこれが悲惨なソフトウェア エンジニアリングの実践であることを知っていますが、最初はすべてを公開することがよくあります。最近のほとんどの一般的な IDE でツールをリファクタリングすると、使用するアプローチ (カプセル化の追加とカプセル化の削除) の関連性が以前よりもはるかに低くなります。

于 2008-09-19T05:32:42.787 に答える
-1

私はほぼ常にこれに関するルールに従っています。私には 4 つのシナリオがあります - 基本的に、ルール自体といくつかの例外 (すべて Java の影響):

  1. ゲッター/セッターを介してアクセスされる、現在のクラスの外部で使用可能
  2. クラス内での使用は通常、メソッド パラメータではないことを明確にするために「this」が前に付けられます。
  3. トランスポート オブジェクトのように、非常に小さいままにすることを意図したもの - 基本的に属性のストレート ショット。すべて公開
  4. ある種の拡張のために非公開にする必要がある
于 2008-09-19T05:06:50.040 に答える