ゲッターとセッターを持つこと自体はカプセル化を壊しません。カプセル化を解除するのは、データメンバー(java lingoのすべてのフィールド)にゲッターとセッターを自動的に追加することです。これは、すべてのデータメンバーをパブリックにするよりも優れていますが、ほんの少しの距離です。
カプセル化のポイントは、オブジェクトの外部からオブジェクトの状態を知ることも変更することもできないことではなく、それを行うための合理的なポリシーを持っていることです。
一部のデータメンバーは、オブジェクトの内部に完全に存在する場合があり、ゲッターもセッターも持たない必要があります。
一部のデータメンバーは読み取り専用である必要があるため、ゲッターは必要ですがセッターは必要ない場合があります。
一部のデータメンバーは、互いに一貫性を保つ必要がある場合があります。そのような場合は、それぞれにセッターを提供するのではなく、値を一貫してチェックできるように、それらを同時に設定する単一の方法を提供します。
一部のデータメンバーは、一定の量だけ増分または減分するなど、特定の方法でのみ変更する必要がある場合があります。この場合、セッターではなくincrement()
and / or decrement()
メソッドを提供します。
しかし、実際には読み取り/書き込みが必要な場合があり、ゲッターとセッターの両方を持っています。
の例を考えてみましょうclass Person
。人に名前、社会保障番号、年齢があるとします。人々が名前や社会保障番号を変更することを許可しないとしましょう。ただし、その人の年齢は毎年1ずつ増やす必要があります。この場合、名前とSSNを指定された値に初期化し、年齢を0に初期化するコンストラクターを提供incrementAge()
します。また、年齢を1増やすメソッドを提供します。 3つすべてのゲッター。この場合、セッターは必要ありません。
この設計では、オブジェクトの状態をクラスの外部から検査できるようにし、クラスの外部から変更できるようにします。ただし、状態を任意に変更することはできません。ポリシーがあります。これは、名前とSSNをまったく変更できないこと、および年齢を一度に1年ずつ増やすことができることを効果的に示しています。
今、人も給料を持っているとしましょう。そして、人々は自由に仕事を変えることができます。つまり、給与も変わります。この状況をモデル化するには、setSalary()
方法を提供する以外に方法はありません!この場合、給与を自由に変更できるようにすることは、完全に合理的なポリシーです。
ところで、あなたの例では、私はクラス与えるだろうと代わりの方法を、と。その後、カプセル化がまだあります。Fridge
putCheese()
takeCheese()
get_cheese()
set_cheese()
public class Fridge {
private List objects;
private Date warranty;
/** How the warranty is stored internally is a detail. */
public Fridge( Date warranty ) {
// The Fridge can set its internal warranty, but it is not re-exposed.
setWarranty( warranty );
}
/** Doesn't expose how the fridge knows it is empty. */
public boolean isEmpty() {
return getObjects().isEmpty();
}
/** When the fridge has no more room... */
public boolean isFull() {
}
/** Answers whether the given object will fit. */
public boolean canStore( Object o ) {
boolean result = false;
// Clients may not ask how much room remains in the fridge.
if( o instanceof PhysicalObject ) {
PhysicalObject po = (PhysicalObject)o;
// How the fridge determines its remaining usable volume is a detail.
// How a physical object determines whether it fits within a specified
// volume is also a detail.
result = po.isEnclosedBy( getUsableVolume() );
}
return result;
}
/** Doesn't expose how the fridge knows its warranty has expired. */
public boolean isPastWarranty() {
return getWarranty().before( new Date() );
}
/** Doesn't expose how objects are stored in the fridge. */
public synchronized void store( Object o ) {
validateExpiration( o );
// Can the object fit?
if( canStore( o ) ) {
getObjects().add( o );
}
else {
throw FridgeFullException( o );
}
}
/** Doesn't expose how objects are removed from the fridge. */
public synchronized void remove( Object o ) {
if( !getObjects().contains( o ) ) {
throw new ObjectNotFoundException( o );
}
getObjects().remove( o );
validateExpiration( o );
}
/** Lazily initialized list, an implementation detail. */
private synchronized List getObjects() {
if( this.list == null ) { this.list = new List(); }
return this.list;
}
/** How object expiration is determined is also a detail. */
private void validateExpiration( Object o ) {
// Objects can answer whether they have gone past a given
// expiration date. How each object "knows" it has expired
// is a detail. The Fridge might use a scanner and
// items might have embedded RFID chips. It's a detail hidden
// by proper encapsulation.
if( o implements Expires && ((Expires)o).expiresBefore( today ) ) {
throw new ExpiredObjectException( o );
}
}
/** This creates a copy of the warranty for immutability purposes. */
private void setWarranty( Date warranty ) {
assert warranty != null;
this.warranty = new Date( warranty.getTime() )
}
}
Getters and setters are often criticized as being not proper OO
-引用してください。