web-dev-qa-db-ja.com

変数にゲッターとセッターがある場合、パブリックにする必要がありますか?

プライベートな変数を持つクラスがあり、そのクラスにはその変数のゲッターとセッターがあります。その変数を公開してみませんか?

ゲッターとセッターを使用しなければならない唯一のケースは、セットまたはゲット以外の操作を行う必要がある場合です。例:

void my_class::set_variable(int x){
   /* Some operation like updating a log */
   this->variable = x;
}
23
Oni

プロパティについて聞いたことがありますか?

プロパティは、「組み込み」のアクセサー(ゲッターとセッター)を持つフィールドです。たとえば、Javaにはプロパティがありませんが、ゲッターとセッターをプライベートフィールドに書き込むことをお勧めします。 C#にはプロパティがあります。

では、なぜゲッターとセッターが必要なのでしょうか。基本的にprotect/shieldフィールドに必要です。たとえば、メモリ参照のフィールドにアクセスするのではなく、フィールド(参照)を変更するメソッドにアクセスします。このメソッドは、例のように、ユーザーが気にしないいくつかの操作(カプセル化動作)を実行できます。たとえば、10個のクラスがパブリックフィールドを使用していて、その使用方法を変更する必要があると想像してください。フィールドの使用方法を変更するには、これらのクラスのそれぞれを調べる必要があります...だから「OOlysh」。

しかし、たとえば、deadというブール型フィールドがあるとします。 setDeadとisDeadを宣言する前に、よく考える必要があります。 人間が読めるのアクセサを作成する必要があります。たとえば、setDeadの代わりにkill()を使用します。

ただし、JavaBeanの命名規則(Javaについて)に準拠している)を前提としているフレームワークが多数あるため、そのような場合は、次のすべてのゲッターとセッターを宣言する必要があります命名法。

21
wleao

これは最も人気のある意見ではありませんが、私は大きな違いはないと思います。

セッターとゲッターはかなり悪い考えです。私はそれについて考えました、そして正直に言って、実際にはプロパティとパブリック変数のセッター/ゲッターの違いを思い付くことができません。

理論では、セッターとゲッターまたはプロパティは、変数が設定/取得されたときにいくつかの特別なアクションを実行する場所を追加し、理論的には変更からコードを分離します。

実際には、アクションを追加するためにセッターとゲッターが使用されることはめったにありません。アクションを追加したい場合は、それをクラスのすべてのセッターまたはゲッター(ロギングなど)に追加する必要があります。より良い解決策です。

設計の決定を分離することに関しては、intをlongに変更した場合でも、セッターを変更し、少なくとも手動でアクセスするすべての行を確認する必要があります。

いずれにせよ、可変クラスはデフォルトで回避する必要があるため、セッターの追加は最後の手段となるはずです。これは、オブジェクトが望ましい状態になるまで値を設定できるビルダーパターンで軽減され、その後、クラスが不変になり、セッターが例外をスローします。

ゲッターについては、ゲッターとパブリックの最終的な変数の違いをまだ思いつきません。ここでの問題は、それが悪いことですOOどちらの場合も。オブジェクトから値を要求してそれを操作するのではなく、オブジェクトに対して操作を実行するように要求する必要があります君は。

ちなみに、私は決してパブリック変数を推奨しているわけではありません。セッターとゲッター(さらにはプロパティ)は、すでにパブリック変数であることに非常に近いと言っています。

大きな問題は、OOプログラマーでない人は、セッターとゲッターを使用してオブジェクトをプロパティボール(構造)にして、受け渡し、操作することはほとんどできないということです。オブジェクト指向コードの動作の逆。

26
Bill K

ゲッターとセッターのユーザーは カプセル化 の原則に入ります。これにより、クラス内での動作方法を変更し、すべての機能を維持できます。

たとえば、他の3つのオブジェクトがfoo.barを呼び出してbarの値を取得し、barの名前をfarに変更した場合、問題が発生します。オブジェクトがfoo.barと呼ばれる場合、これを持つすべてのクラスを変更する必要があります。セッター/ゲッターを使用する場合は、何も変更する必要はありません。もう1つの可能性は、変数のタイプを変更することです。その場合、変換コードをゲッター/セッターに追加するだけで問題ありません。

8
user7007

ゲッターとセッターを使用すると、特定の変数に格納するコンテンツを制御することもできます。コンテンツを特定のタイプまたは値にする必要がある場合、セッターコードの一部は、新しい値がこれらの要件を確実に満たすようにすることができます。変数がパブリックの場合、これらの要件が満たされていることを確認することはできません。

このアプローチにより、コードの適応性と管理性も向上します。他のすべてのクラスまたはそのクラスを利用する関数からそのアーキテクチャを非表示に保つ関数がある場合は、クラスのアーキテクチャを変更する方がはるかに簡単です。すでに述べた変数名の変更は、ゲッターやセッターなどの関数がある場合に、はるかに簡単に行える多くの変更の1つにすぎません。全体的な考え方は、特にクラス変数をできるだけプライベートにすることです。

5
Kenneth

「ゲッターとセッターを使用しなければならないと思う唯一のケースは、セットまたはゲット以外の操作を行う必要がある場合です。」.

将来のある時点でmightがsetとget以外の操作を行う必要があり、それが発生したときに何千行ものソースコードを変更したくない場合は、ゲッターとセッターを使用する必要があります。

誰かに変数のアドレスを渡して渡してほしくない場合は、ゲッターとセッターを使用する必要があります。ソースコードに言及せずに変数を変更できる場合、またはオブジェクトが存在しなくなった後でも、悲惨な結果になります。 。

2
gnasher729

最初に、パラダイムを明確にします。

  • データ構造->適切に知識のある関数によって横断および操作できるメモリのレイアウト。
  • オブジェクト->実装を隠し、通信可能なインターフェースを提供する自己完結型モジュール。

ゲッター/セッターはどこで役に立ちますか?

ゲッター/セッターはデータ構造で役立ちますか? いいえ

データ構造は、関数のファミリに共通して操作されるメモリレイアウト仕様です。

一般に、古い新しい関数が一緒になってデータ構造を操作する可能性があります。他の関数がそれを理解できるようにそうする場合、関数はファミリに加わります。それ以外の場合は、その不正な機能とバグの原因です。

誤解しないでください。あちこちでスニッチ、ターンコート、およびダブルエージェントを使用したデータ構造を警告する関数のファミリがいくつか存在する可能性があります。それぞれに独自のデータ構造がある場合は問題ありませんが、データ構造を共有する場合は、政治に反対する複数の犯罪家族がいると想像してみてください。

混乱した拡張関数ファミリーが達成できる場合、不正な関数がすべてを台無しにしないようにデータ構造をエンコードする方法はありますか? はい、オブジェクトと呼ばれます。

ゲッター/セッターはオブジェクトで役立ちますか? いいえ

データ構造をオブジェクトにラップする目的は、不正な関数が存在しないようにすることです。関数がファミリーに参加したい場合は、最初に徹底的に吟味してからオブジェクトの一部にする必要がありました。

ゲッターとセッターのポイント/目的は、オブジェクトの外部の関数がオブジェクトのメモリレイアウトを直接変更できるようにすることです。 それは悪党で許可するために開かれた扉のように聞こえます...

エッジケース

パブリックゲッター/セッターが理にかなっている2つの状況があります。

  • オブジェクト内のデータ構造の一部はオブジェクトによって管理されますが、オブジェクトによって制御されません。
  • 一部の要素が実装オブジェクトの制御下にないと予想されるデータ構造の高レベルの抽象化を記述するインターフェース。

コンテナーとコンテナーインターフェイスは、これら2つの状況の両方の完璧な例です。コンテナーはデータ構造(リンクリスト、マップ、ツリー)を内部で管理しますが、特定の要素の制御はすべてと雑貨に委ねます。インターフェースはこれを抽象化し、実装を完全に無視し、期待のみを記述します。

残念ながら、多くの実装ではこれが間違っており、これらの種類のオブジェクトのインターフェースを定義して、実際のオブジェクトに直接アクセスできます。何かのようなもの:

interface Container<T>
{
    typedef ...T... TRef; //<somehow make TRef to be a reference or pointer to the memory location of T
    TRef item(int index); 
}

これは壊れています。 Containerの実装は、内部の制御を、使用する人に明示的に渡す必要があります。これが適切である可変値言語はまだ見たことがありません(不変値のセマンティクスを持つ言語は、データ破損の観点からは定義上問題ありませんが、必ずしもデータスパイの観点からはそうではありません)。

コピーセマンティクスのみを使用するか、プロキシを使用することで、getter/setterを改善/修正できます。

interface Proxy<T>
{
     operator T(); //<returns a copy
     ... operator ->(); //<permits a function call to be forwarded to an element
     Proxy<T> operator=(T); //< permits the specific element to be replaced/assigned by another T.
}

interface Container<T>
{
     Proxy<T> item(int index);
     T item(int index); //<When T is a copy of the original value.
     void item(int index, T new_value); //<where new_value is used to replace the old value
}

間違いなく、悪意のある関数がまだ騒乱を起こす可能性があります(十分な努力でほとんどのことが可能です)が、コピーセマンティクスやプロキシは、多数のエラーの可能性を減らします。

  • オーバーフロー
  • アンダーフロー
  • サブ要素との相互作用は、型チェック/型チェック可能です(型を失う言語では、これは恩恵です)
  • 実際の要素は、メモリに常駐する場合とそうでない場合があります。

プライベートゲッター/セッター

これは、ゲッターとセッターが型を直接操作する最後の要塞です。実際、これらのゲッターやセッターではなく、アクセサーやマニピュレーターと呼ぶこともできます。

このコンテキストでは、データ構造の特定の部分を操作する場合、常に/ほぼ常に/一般に、特定のブックキーピングを実行する必要があります。ツリーのルートを更新するとき、ルックアサイドキャッシュを削除する必要がある、または外部データ要素にアクセスするときに、ロックを取得/解放する必要があるとしましょう。これらの場合、DRYプリンシパルを適用し、それらのアクションを一緒に分割することは理にかなっています。

プライベートコンテキスト内では、ファミリー内の他の関数がこれらの「ゲッターとセッター」を回避してデー​​タ構造を操作することが可能です。したがって、なぜアクセサとマニピュレータとしてそれらを考えるのか。データに直接アクセスするか、別の家族に頼ってその部分を正しく行うことができます。

保護されたゲッター/セッター

保護されたコンテキストでは、パブリックコンテキストとひどく違いはありません。不正な可能性のある外部関数は、データ構造へのアクセスを求めています。したがって、存在しない場合、パブリックゲッター/セッターのように動作します。

1
Kain0_0

C++の経験から、setter/getterは2つのシナリオに役立ちます。

  1. 文字列や配列などのメンバーに値を割り当てる前に、健全性チェックを実行する必要がある場合。
  2. これは、-1(または負の値)がfalseの場合にブール値の割り当てにブール値を割り当てるなど、関数のオーバーロードが必要な場合に役立ちます。ゲッターの場合はその逆です。

それとは別に、セキュリティは有効なポイントですが、その重要性は、ログインやdbアクセス関連モジュールなどの非常に少数の開発アプリケーションに制限されています。あなたのモジュールを使用する人が少ないのに、なぜ余分なコーディングをするのですか?

0
Ajay nandoriya