オブジェクト指向プログラミングでは、私はこの質問を持っていましたが、今でもそうしています:
public getterとpublic setterを作成する場合、クラスメンバーをプライベートとして宣言する利点は何ですか?
上記の場合と、クラス メンバーを public として宣言する場合のセキュリティ レベルに違いはありません。
ありがとう!
カプセル化により、データの隠蔽とメンバー変数のより詳細な制御が提供されます。属性が公開されている場合、誰でもアクセスでき、任意の値を割り当てることができます。ただし、メンバー変数がプライベートで、そのセッターを提供している場合。次に、非論理的な値の設定を避けるために、setter メソッドにいくつかの制約チェックを入れるオプションが常にあります。
たとえば、 public メンバーのみを持つクラス:
class MyClass {
public int age;
}
public MyClassUser {
public static void main(String args[]) {
MyClass obj = new MyClass();
obj.age = -5 // not a logical value for age
}
}
プライベート メンバーとセッターを持つ同じクラス:
class MyClass {
private int age;
public void setAge(int age) {
if(age < 0) {
// do not use input value and use default
} else {
this.age = age;
}
}
}
クラスに維持する不変条件がない場合、プライベート データ メンバーのパブリック ゲッターとセッターを作成しても意味がありません。パブリック データ メンバーを使用する必要があります。
一方、維持する不変条件がある場合は、セッターを使用すると、データ メンバーに割り当てることができる値を制限できます。
データ メンバーがあるからといって、そのためのゲッターまたはセッターを作成する必要があるわけではないことに注意してください。
Pet peeve:「でも、内部が変わったらどうするの?」それは問題ではありません。をgetName
返す関数がありましたstd::string const&
。ゲッターは、後で実装を変更するときに選択を制限するため、カプセル化を減らします。
簡単な (そして少しばかげた) 例:
class Foo {
private int age = -1; // unset value
public setAge(int a) {
if (a < 0) {
throw new IllegalArgumentException("Invalid age "+a);
}
age = a;
}
public getAge() {
if (age < 0) {
throw new InvalidStateException("Age was not previously set.")
}
return age;
}
}
要するに、コントロールを獲得し、値が正しいことを保証できます。カプセル化といいます。
http://en.wikipedia.org/wiki/Encapsulation_%28オブジェクト指向プログラミング%29
後でクラス メンバーの内部表現を変更し、getter と setter に機能 (Observer への通知など) を追加することができますが、すべてインターフェイス (パブリック getter と setter) を変更する必要はありません。
あなたの質問は確かにフィールドとプロパティの違いです。通常、フィールドはプライベートであり、プロパティはそれらを公開します。以下は、SOに関する素晴らしい回答の引用です。
プロパティはフィールドを公開します。フィールドは (ほとんどの場合) クラスに対してプライベートに保ち、get および set プロパティを介してアクセスする必要があります。プロパティは、クラスを使用するものによってアクセスされる外部の方法に影響を与えずに、フィールドを変更できるようにする抽象化のレベルを提供します。
C# では、手動で宣言しなくても、自動プロパティによってフィールドが作成されます。
public Prop { get; set; }
public Prop { public get; private set; }
public Prop { private get; public set; }
// etc, you can specify access modifier as per your need
範囲が限定されたデータ転送オブジェクトがあり、設計上ロジックが関連付けられていない場合、getter と setter に値が表示されません。
ただし、何らかのロジックが関連付けられているかどうか、または広く使用されているコンポーネントがある場合、データの保存方法の詳細を非表示にすることは理にかなっています。最初はすべての getter と setter が些細なことでクラスを埋め尽くしているように見えるかもしれませんが、時間の経過とともに、setter に検証を追加したり、getter を変更したりすることさえあるかもしれません。たとえば、フィールドを削除したり (そして将来的に定数を返したり)、委任されたオブジェクトにデータを格納したり、他のフィールドから値を計算したりできます。
上記の場合と、クラス メンバーを public として宣言する場合のセキュリティ レベルに違いはありません。
差し迫った質問は次のとおりです。
1)値を設定する際に条件を確認したい場合は?
2)サブクラスがそのメソッドを検証することによって、何か他のものを返したり設定したりしたい場合はどうなりますか?
カプセル化のほかに、セッターが値を設定するだけではない状況を考えてみましょう。
多くのクラスで使用している場合はどうなりますか? そして今、あなたはそれの機能を変更したいことに気づきましたか? 手動で設定した場所全体で変更する必要があります。セッターがいれば、人生はもっと楽だったでしょう。
カプセル化と同様に、実装の詳細を隠します。これにより、アクセスを制御し、内部が変更されても安定したインターフェイスを提供できます。
class Person //version 1.0
{
std::string name;
public:
std::string getName() const { return name; }
void setName(const std::string &newName)
{
if (!newName.empty()) //disallow empty names
name = newName;
}
};
class Person //version 1.1
{
std::string firstName;
std::string lastName;
public:
std::string getFirstName() const { return firstName; }
void setFirstName(const std::string &newFirstName)
{
firstName = newFirstName;
}
std::string getLastName() const { return lastName; }
void setLastName(const std::string &newLastName)
{
if (!newLastName.empty()) //disallow empty last names
firstName = newFirstName;
}
std::string getName() const
{
std::ostringstream s;
if (!firstName.empty())
s << fistName << ' ';
s << lastName;
return s.str();
}
void setName(const std::string &newName)
{
setFirstName(splitUntilLastSpace(newName));
setLastName(splitFromLastSpace(newName));
}
};
変数を as として宣言することを asprivate
と呼びます Encapsulation in Java
。
Java または任意のオブジェクト指向プログラミング言語でコードを作成する際にカプセル化を使用する利点は次のとおりです。
- カプセル化されたコードはより柔軟で、新しい要件に合わせて簡単に変更できます。
- Java でのカプセル化により、単体テストが容易になります。
- Java のカプセル化により、誰が何にアクセスできるかを制御できます。
- カプセル化は、マルチスレッド環境で適切な選択である Java で不変クラスを記述するのにも役立ちます。
- カプセル化は、モジュールの結合を減らし、モジュール内の結束を高めます。これは、1 つのもののすべてが 1 つの場所にカプセル化されるためです。
- カプセル化により、コードの他の部分に影響を与えることなく、コードの一部を変更できます。
もう1つの利点は
Java で変数を非公開にし、それらに getter と setter を提供すると、クラスに互換性のある Java Bean 命名規則が作成されます
アクセサー メソッドは、特定のフィールドの単一更新ポイントを提供します。コードベース全体でフィールドに直接アクセスするのではなく、フィールドに対する検証ロジックまたはその他の変更を単一のメソッドで制御できるため、これは有益です。
詳細については、次の IBM ドキュメントを参照してください: http://www.ibm.com/developerworks/java/library/ws-tip-why.html
パブリック ゲッターとパブリック セッターがプライベート プロパティの値を返し、その値を変更するだけであれば、違いはわかりません。
ただし、カプセル化を実装しているため、後でセッターや書き込み専用/読み取り専用プロパティの引数チェックなど、別の動作を実装できます。
オブジェクト指向プログラミングの最も重要な概念の 1 つは、カプセル化です。データと、そのデータに作用するメソッドを一緒にカプセル化します。理想的には、関連するメソッドを介してのみデータにアクセスする必要があります。また、データの状態は、これらのメソッドを介して他のオブジェクトによって「照会」される必要があります。変数をパブリックにすると、その変数はカプセル化を破る他のすべてのオブジェクトで直接使用できるようになります。
実際、小規模なプロジェクトで 1 人で開発していて、コードを再利用しない場合、それはちょっと役に立たないかもしれませんが、ほとんどは良い習慣です。
ただし、チーム開発では、変更をある程度制御する必要がある場合があり、ゲッターとセッターを使用してそれを行うことができます。
さらに、一部のクラスでは、セッターはコンストラクターまたは他の関数を介して実行されるため、ゲッターしかありません。