22

private単に変数を定義し、それらの変数にアクセスするためのゲッターセッターを定義すると、データはカプセル化されると常に言っています。私の質問は、ゲッターとセッターを介して変数(データ)にアクセスできるかどうかですが、データが非表示または安全になるのはなぜですか?

説明のためにたくさんググったが、何も見つからなかった。誰もがブログや投稿で、これはデータを隠す手法であると言っていますが、説明/詳細は示されていません。

4

9 に答える 9

60

カプセル化は、クラスのアクセサーメソッドとミューテーターメソッドを定義するだけではありません。これは、クラス間の相互依存性を最小限に抑えることからなるオブジェクト指向プログラミングのより広い概念であり、通常、情報隠蔽によって実装されます。

カプセル化の美しさは、ユーザーに影響を与えることなく物事を変える力です

Javaのようなオブジェクト指向プログラミング言語では、アクセシビリティ修飾子(public、protected、private、およびpackage-privateを意味する修飾子なし)を使用して詳細を非表示にすることにより、カプセル化を実現します。これらのアクセシビリティのレベルを使用すると、カプセル化のレベルを制御できます。レベルの制限が緩和されるほど、変更が発生したときのコストが高くなり、クラスが他の依存クラス(つまり、ユーザークラスやサブクラス)と結合します。

したがって、目標はデータ自体を非表示にすることではなく、このデータの操作方法に関する実装の詳細です。

アイデアは、このデータにアクセスするためのパブリックインターフェイスを提供することです。クラスのパブリックインターフェイスを損なうことなく、後でデータの内部表現を変更できます。それどころか、データ自体を公開することにより、カプセル化が損なわれるため、ユーザーに影響を与えることなくデータの操作方法を変更する能力が損なわれます。クラスのパブリックインターフェイスではなく、データ自体に依存関係を作成します。「変化」がついにあなたを見つけたとき、あなたはトラブルのための完璧なカクテルを作るでしょう。

フィールドへのアクセスをカプセル化する理由はいくつかあります。Joshua Blochは、彼の著書「Effective Java」の項目14:クラスとメンバーのアクセス可能性を最小限に抑えることで、いくつかの説得力のある理由について言及しています。

  • フィールドに保存できる値を制限できます(つまり、性別はFまたはMである必要があります)。
  • フィールドが変更されたときにアクションを実行できます(イベントのトリガー、検証など)。
  • メソッドを同期することにより、スレッドセーフを提供できます。
  • 新しいデータ表現(つまり、計算フィールド、さまざまなデータ型)に切り替えることができます

ただし、カプセル化はフィールドを隠すだけではありません。Javaでは、クラス全体を非表示にすることができます。これにより、API全体の実装の詳細を非表示にできます。たとえば、メソッドで考えてみてくださいArrays.asList()。実装を返しますが、インターフェースをList満たす限り、どの実装でも構いませんよね?Listメソッドのユーザーに影響を与えることなく、実装を将来変更することができます。

カプセル化の美しさ

さて、私の意見では、カプセル化を理解するには、まず抽象化を理解する必要があります。

たとえば、車の概念の抽象化のレベルで考えてみてください。車の内部実装は複雑です。それらには、トランスミッションシステム、ブレーキシステム、燃料システムなどのいくつかのサブシステムがあります。

ただし、抽象化を簡素化し、抽象化のパブリックインターフェイスを介して世界中のすべての車とやり取りします。すべての車には、方向を制御するハンドルがあり、押すと車を加速して速度を制御するペダルがあり、押すと停止するペダルがあり、ギアがあります。前進するか後退するかを制御できるスティック。これらの機能は、車の抽象化のパブリックインターフェイスを構成します。午前中はセダンを運転し、午後は同じようにセダンから降りてSUVを運転することができます。

ただし、これらすべての機能が内部でどのように実装されているかについての詳細を知っている人はほとんどいません。車に油圧方向システムがなかった時代を考えてみてください。ある日、自動車メーカーが発明し、それ以降は自動車に搭載することにしました。それでも、これはユーザーがユーザーと対話する方法を変更しませんでした。せいぜい、ユーザーは指向性システムの使用の改善を経験しました。車の内部実装がカプセル化されているため、このような変更が可能でした。パブリックインターフェイスに影響を与えることなく、変更を安全に行うことができます。

さて、自動車メーカーが燃料キャップを車の片側ではなく、車の下に置くことに決めたと考えてください。あなたはこれらの新しい車の1台を買いに行きます、そしてあなたがガスを使い果たしたときあなたはガソリンスタンドに行きます、そしてあなたは燃料キャップを見つけません。突然、車の下にあることに気づきましたが、ガソリンポンプのホースでは届きません。今、私たちはパブリックインターフェース契約を破ったので、世界全体が崩壊し、物事が期待どおりに機能していないために崩壊します。このような変更には数百万の費用がかかります。世界のすべてのガソリンポンプを交換する必要があります。カプセル化を破るとき、私たちは代償を払わなければなりません。

したがって、ご覧のとおり、カプセル化の目標は、相互依存を最小限に抑え、変更を容易にすることです。実装の詳細の公開を最小限に抑えることで、カプセル化を最大化します。クラスの状態には、パブリックインターフェイスを介してのみアクセスする必要があります。

オブジェクト指向プログラミング言語でのカプセル化と継承というAlanSnyderの論文を読むことを強くお勧めします。このリンクはACMの元の論文を指していますが、GoogleからPDFコピーを見つけることができると確信しています。

于 2012-08-15T13:48:21.993 に答える
16

私があなたの質問を理解する方法は、変数をとして宣言しますがprivate、それらの変数はゲッターとセッターを使用してアクセスできるため、プライベートではありません。したがって、それを行うことの意味は何ですか?

ゲッターとセッターを使用する場合、private変数へのアクセスを制限できます。

つまり、

private int x;

public int getInt(String password){
 if(password.equals("RealPassword")){
   return x;
  }
}

そして、セッターについても同じです。

于 2012-08-15T09:25:42.933 に答える
13

ゲッター/セッターで追加のロジックを実行でき、変数の値を変更できないため、データは安全です。コードがnull変数で機能しなかったと想像してください。そのため、セッターでnull値をチェックし、デフォルト値である!=nullを割り当てることができます。したがって、誰かが変数をnullに設定しようとしているかどうかに関係なく、コードは引き続き機能します。

于 2012-08-15T09:20:16.870 に答える
5

私の質問は、ゲッターとセッターを介して変数(データ)にアクセスできるかどうかですが、データが非表示または安全になるのはなぜですか?

ロジックはgetter/setterの下にカプセル化できます。例えば、

public void setAge(int age) {
    if (age < 0) {
        this.age = 0;
    }
    else {
        this.age = age;
    }
}
于 2012-08-15T09:17:52.893 に答える
4

ジガーの答えを続ける:カプセル化されるものがいくつかあります。

  1. 契約管理:あなたがそれpublicを成し遂げるなら、あなたは文字通り誰にでもそれを彼らが望むものに変えるようにさせています。制約を追加して保護することはできません。セッターは、データが適切な方法で変更されていることを確認できます。

  2. 可変性:必ずしもセッターが必要なわけではありません。オブジェクトの存続期間中不変に保ちたいプロパティがある場合。あなたはそれをプライベートにするだけで、セッターはありません。おそらくコンストラクターを介して設定されます。次に、ゲッターは属性(不変の場合)または属性のコピー(属性が可変の場合)を返すだけです。

于 2012-08-15T09:24:59.547 に答える
3

一般に、ゲッターとセッターによるフィールドのカプセル化により、変更に対する柔軟性が高まります。

フィールドに直接アクセスすると、「ばかげたフィールド」で立ち往生します。フィールドは、書き込みと読み取りのみが可能です。フィールドにアクセスしている間は、他に何もできません。

メソッドを使用する場合、値を設定/読み取りしながら、好きなことを行うことができます。markusとJigarが述べたように、検証は可能です。さらに、ある日、値が別の値から派生するか、値が変更された場合にいくつかのアクションを実行する必要があるかを決定できます。

どうしてデータが隠されているか安全なのか

ゲッターとセッターを使用しても、データは隠されておらず、安全でもありません。それはあなたにそれを安全にする可能性を与えるだけです。隠されているのは実装であり、データではありません。

于 2012-08-15T09:47:39.747 に答える
2

データ検証は、アクセサやミューテータが使用されている場合にカプセル化が安全性をどのように提供するかに関する質問に対する主な回答です。他の人は、ミューテーターにデフォルト値を設定するためのフェイルセーフの例を使用してこれに言及しています。代わりに例外をスローすることを好むと回答しましたが、これはすばらしいことですが、使用するときにデータが不良であることを識別しても、データが不良であるという事実は変わりませんしたがって、データが変更される前に例外をキャッチするのは最善ではないでしょうか。つまり、ミューテーターでそれを実行するのでしょうか。このように、ミューテーターが有効であると検証しない限り、実際のデータが変更されることはありません。したがって、データが不良の場合でも元のデータが保持されます。

私自身はまだ学生ですが、カプセル化に最初に遭遇したときとまったく同じでしたので、それを理解するのに少し時間を費やしました。

于 2013-06-06T06:11:04.693 に答える
1

スレッドを考慮した説明が好きです。フィールドを公開した場合、インスタンスは、特定のスレッドがそのフィールドの1つを変更したことをどのように知るのでしょうか。

それを行う唯一の方法は、カプセル化を使用するか、より簡単にそのフィールドにゲッターとセッターを与えることです。したがって、たとえば、フィールドの更新を常に知っており、チェック/反応することができます。

于 2012-08-15T09:22:04.433 に答える
0

カプセル化により、他の人がコードを再利用しやすくなります。カプセル化を使用するもう1つの重要な理由は、インターフェイスはフィールドを宣言できませんが、フィールドを参照できるメソッドを宣言できることです。

メソッドには、最初に動詞が付いた適切な名前が付けられています。例:getName()、setName()、isDying()。これはコードを読むのに役立ちます!

于 2015-07-25T07:05:57.233 に答える