私は現在Qtで働いているので、C++です。私はプライベートデータメンバーとパブリックメンバー関数を持つクラスを持っています。クラスで利用可能なデータメンバーのパブリックゲッターとセッターがあります。
今、私の質問は、クラスのデータメンバーのゲッターとセッターがある場合、それらのデータメンバーをプライベートにすることのポイントは何ですか?基本クラスのプライベートデータメンバーは論理的に聞こえます。しかし、それ以外に、プライベートメンバーとそのゲッターとセッターを持つことは、私にとって論理的なものではないようです。
または、代わりにすべての変数をpublicにして、ゲッターとセッターがまったく必要ないようにできますか? プライベートメンバーにデータの抽象化を保証することは知っていますが、ゲッターとセッターを使用すると、これらの変数に簡単にアクセスできます。これに関するポインタは大歓迎です。
どちらでもない。何かをするメソッドが必要です。それらのいずれかが特定の内部変数に対応している場合、それは素晴らしいことですが、クラスのユーザーにこれを電信するものは何もないはずです。
プライベートデータはプライベートであるため、いつでも実装を置き換えることができます(完全な再構築も可能ですが、それは別の問題です)。瓶から魔神を取り出したら、それを押し戻すことは不可能です。
編集:私は別の答えにしたコメントに続いて。
ここでの私のポイントは、あなたが間違った質問をしているということです。ゲッター/セッターの使用またはパブリックメンバーの使用に関するベストプラクティスはありません。特定のオブジェクトに最適なものと、特定の現実世界のもの(またはゲームの場合は想像上のもの)をモデル化する方法だけがあります。
個人的にゲッター/セッターは、2つの悪の少ない方です。ゲッター/セッターの作成を開始すると、人々は、どのデータを表示し、どのデータを表示しないかを重視するオブジェクトの設計を停止するからです。公のメンバーでは、すべてが公開される傾向があるため、さらに悪化します。
代わりに、オブジェクトが何をするか、そして何かがそのオブジェクトであるということの意味を調べてください。次に、そのオブジェクトへの自然なインターフェイスを提供するメソッドを作成します。その自然なインターフェースは、ゲッターとセッターを使用していくつかの内部プロパティを公開することを含むため、そうです。しかし、重要な部分は、事前に考えて、設計上正当な理由でゲッター/セッターを作成したことです。
いいえ、リモートでも同じものではありません。
クラスインターフェイスへのさまざまなアプローチによって達成できるさまざまなレベルの保護/実装非表示があります。
1。パブリックデータメンバー:
2。データへの参照(おそらくプライベートデータメンバーへ)を返すメソッド:
3。ゲッターメソッドやセッターメソッド(プライベートデータメンバーにアクセスする可能性があります):
ゲッター/セッターアプローチは、プロパティが物理オブジェクトによって実装されているという事実すら公開しません。つまりゲッター/セッターペアの背後には物理データメンバーが存在しない可能性があります。
上記のことを考慮すると、ゲッターとセッターのペアがパブリックデータメンバーと同じであると誰かが主張するのを見るのは奇妙です。実際、それらには共通点はありません。
もちろん、各アプローチにはバリエーションがあります。たとえば、ゲッターメソッドは、データへのconst参照を返し、(2)と(3)の間にデータを配置します。
データ項目ごとにゲッターとセッターがある場合、データをプライベートにすることは意味がありません。そのため、データ項目ごとにゲッターとセッターを用意するのは悪い考えです。 std :: stringクラスを考えてください-(おそらく)1つのgetterとsize()関数があり、setterはまったくありません。
またはBankAccount
オブジェクトを検討してください-現在のバランスを変更するためにSetBalance()
setterが必要ですか?いいえ、ほとんどの銀行はそのようなことを実装してくれたことに感謝しません。代わりに、ApplyTransaction( Transaction & tx )
のようなものが必要です。
データを公開します。いつか「ゲッター」または「セッター」のロジックが必要な(どちらかというとありそうもない)イベントで、データ型をoperator=
および/またはoperator T
をオーバーロードするプロキシクラスに変更できます。 T =必要なロジックを実装するために現在使用しているタイプ)。
編集:データへのアクセスを制御することはカプセル化を構成するという考え方は基本的に偽です。カプセル化とは、実装の詳細を隠すことです(一般的に!)notデータへのアクセスを制御します。
カプセル化は抽象化を補完します。抽象化はオブジェクトの外部から見える動作を扱い、カプセル化はその動作の実装方法の詳細を隠すことを扱います。
実際にゲッターまたはセッターを使用すると抽象化レベルが低下し実装が公開されます-この特定のクラスが論理的に実装していることをクライアントコードが認識する必要があります一対の関数(ゲッターとセッター)としての「データ」。上記で提案したようにプロキシを使用すると、realカプセル化が提供されます-1つの不明瞭なコーナーケースを除き、完全に hides論理的にデータであるものが実際に一対の関数を介して実装されるという事実。
もちろん、これはコンテキストに保持する必要があります。一部のクラスでは、「データ」はまったく抽象化されていません。一般的に言えば、データの代わりに、より高いレベルの操作を提供できる場合、それは望ましいことです。それにもかかわらず、最も有用な抽象化がデータの読み取りと書き込みであるクラスがあります。その場合、(抽象化された)データは他のデータと同じように見えるようにする必要があります。値の取得または設定には、ビットの単純なコピー以上のものが含まれる可能性があるという事実は、実装の詳細であり、ユーザーには非表示にする必要があります。
ゲッターとセッターを使用すると、プライベートメンバーからの入出力にロジックを適用できるため、データへのアクセスを制御できます(OO用語を知っているユーザーへのカプセル化)。
パブリック変数は、制御されていない検証されていない操作のためにクラスのデータを公開しますが、これはほとんど常に望ましくありません。
これらのことについても長期的に考えなければなりません。現在、検証が行われていない可能性があります(これが、パブリック変数が良い考えの理由です)が、今後追加される可能性があります。それらを事前に追加すると、フレームワークから離れるため、検証がこのように依存コードを壊さないことは言うまでもなく、raodをリファクタリングすることは少なくなります。
ただし、各プライベート変数に独自のゲッター/セッターが必要であることを意味するわけではありません。ニールは銀行の例で、ゲッター/セッターが意味をなさないことがあるという良い点を挙げています。
ロジックが単純であり、変数の読み取り/書き込み時に他のことをする必要がないと確信している場合は、データを公開することをお勧めします。 C++の場合、クラスではなくstructを使用して、データがパブリックであることを強調します。
ただし、データメンバにアクセスするときに他の処理を行う必要がある場合や、後でこのロジックを自由に追加したい場合があります。この場合、ゲッターとセッターは良い考えです。変更は、コードのクライアントに対して透過的になります。
追加機能の簡単な例-変数にアクセスするたびにデバッグ文字列を記録することができます。
カプセル化の問題(理由は十分です)を別にすれば、ゲッター/セッターがあるときに変数が設定/アクセスされるたびにブレークポイントを設定するのは非常に簡単です。
ゲッターとセッターではなくパブリックフィールドを使用する理由は次のとおりです。
使用しているソフトウェアの種類によっては、これらはすべて非常に例外的なケースである可能性があり(また、遭遇したと思われる場合はおそらく間違っている)、または常に発生する可能性があります。それは本当に依存しています。
( 値ベースのプログラミングに関する10の質問 から。)
厳密に言えば、すべてのデータメンバーをプライベートにし、[〜#〜] and [〜#〜]ゲッターとセッターをプライベートにすることから始めることをお勧めします。他の世界(つまり、「(l)userコミュニティ」)が実際に必要とするものを見つけたら、適切なゲッターやセッターを公開したり、適切に制御されたパブリックアクセサーを記述したりできます。
また、(Neilの利益のために)デバッグ時に、特定のデータメンバーの読み取りまたは書き込みが行われたときに、デバッグプリントや他のアクションを掛けるのに便利な場所があると便利な場合があります。ゲッターとセッターを使用すると、これは簡単です。パブリックデータメンバーの場合、それは後部の大きな苦痛です。
値の取得と設定のためだけにゲッターとセッターを使用することは無意味だと思います。このようなメソッドを使用するパブリックメンバーとプライベートメンバーの間に違いはありません。ゲッターとセッターを使用するのは、何らかの方法で値を制御する必要がある場合、または将来役立つ可能性があると思われる場合のみです(ロジックを追加しても、残りのコードは編集できません)。
ゲッターとセッターはほとんどのプログラミング言語で意図的に冗長であり、特にそれらを使用することについてもう一度考えさせると考えてきました。 。
パブリックデータメンバー(POD構造体を除く)を持たないことをお勧めします。また、すべてのデータメンバーにゲッターとセッターを用意することはお勧めしません。むしろ、クラスのクリーンなパブリックインターフェイスを定義します。これには、プロパティ値を取得および/または設定するメソッドが含まれる場合があり、それらのプロパティはメンバー変数として実装される場合があります。ただし、すべてのメンバーのゲッターとセッターを作成しないでください。
考え方は、インターフェイスを実装から分離し、クラスのユーザーがコードを変更しなくても実装を変更できるようにすることです。 getterおよびsetterを介してすべてを公開する場合、公開データの使用に関して何も改善していません。
ゲッターとセッターを使用すると、ユーザーに値を与える方法を変更できます。
以下を考慮してください。
_double premium;
double tax;
_
次に、このpremium
値を使用して場所全体にコードを記述し、プレミアムを取得します。
_double myPremium = class.premium;
_
仕様が変更されたばかりで、ユーザーの観点から見たプレミアムは_premium + tax
_である必要があります
コードでpremium
値が使用されているすべての場所を変更し、tax
を追加する必要があります。
代わりにそのように実装した場合:
_double premium;
double tax;
double GetPremium(){return premium;};
_
すべてのコードはGetPremium()
を使用し、tax
の変更は1行になります。
_double premium;
double tax;
double GetPremium(){return premium + tax;};
_
戻り値は、ゲッターとセッターの使用にも影響します。変数の値を取得するか、プライベートデータメンバー変数にアクセスするかは違います。値による整合性、参照による参照、またはポインタによる保持はそれほど多くありません。
ゲッターとセッターは主に存在するため、メンバーの取得方法と設定方法を制御できます。ゲッターとセッターは特定のメンバーにアクセスする方法としてのみ存在しませんが、メンバーを設定しようとする前に、特定の条件を満たしていることを確認するため、または取得する場合、そのコピーを返すように制御できます非プリミティブ型の場合のメンバー。全体的に、データメンバーとの対話方法をパイプライン化する場合は、g/s'ersを試して使用する必要があります。