การมี getters และ setters ไม่ได้ทำให้ encapsulation ขาดตัวเอง สิ่งที่ทำให้ encapsulation หยุดพักคือการเพิ่มตัวรับและตัวตั้งค่าให้กับสมาชิกข้อมูลทุกคน (ทุกฟิลด์ในภาษาจาวาลิง) โดยไม่คิดอะไรเลย แม้ว่าสิ่งนี้จะดีกว่าการทำให้ข้อมูลทั้งหมดเป็นข้อมูลสาธารณะ แต่เพียงไม่กี่ก้าว
จุดของการห่อหุ้มไม่ใช่ว่าคุณไม่ควรรู้หรือเปลี่ยนแปลงสถานะของวัตถุจากภายนอกวัตถุ แต่คุณควรมีนโยบายที่สมเหตุสมผลในการทำเช่นนั้น
สมาชิกข้อมูลบางคนอาจอยู่ภายในวัตถุทั้งหมดและไม่ควรมีผู้ได้รับหรือผู้ตั้งค่า
ข้อมูลสมาชิกบางคนควรเป็นแบบอ่านอย่างเดียวดังนั้นพวกเขาอาจต้องการ getters แต่ไม่ใช่ setters
ข้อมูลสมาชิกบางคนอาจต้องรักษาให้สอดคล้องกัน ในกรณีเช่นนี้คุณจะไม่ให้ผู้ตั้งค่าสำหรับแต่ละคน แต่เป็นวิธีการเดียวในการตั้งค่าในเวลาเดียวกันเพื่อให้คุณสามารถตรวจสอบค่าเพื่อความมั่นคง
ข้อมูลสมาชิกบางคนอาจจำเป็นต้องเปลี่ยนแปลงในวิธีที่แน่นอนเช่นเพิ่มหรือลดจำนวนคงที่ ในกรณีนี้คุณจะต้องให้increment()
และ / หรือdecrement()
วิธีการมากกว่า setter
แต่คนอื่นอาจจำเป็นต้องอ่าน - เขียนและมีทั้งผู้ทะเยอทะยานและผู้ตั้งตน
class Person
ลองพิจารณาจากตัวอย่างหนึ่ง สมมติว่าบุคคลนั้นมีชื่อหมายเลขประกันสังคมและอายุ สมมติว่าเราไม่อนุญาตให้ผู้คนเปลี่ยนชื่อหรือหมายเลขประกันสังคม อย่างไรก็ตามอายุของบุคคลนั้นควรเพิ่มขึ้น 1 ปีทุก ๆ ปี ในกรณีนี้คุณจะต้องสร้างนวตกรรมที่จะเริ่มต้นชื่อและ SSN ให้กับค่าที่กำหนดและซึ่งจะเริ่มต้นอายุ 0 คุณยังมีวิธีการincrementAge()
ซึ่งจะเพิ่มอายุโดย 1 คุณจะให้ ทะเยอทะยานสำหรับทั้งสาม ไม่จำเป็นต้องใช้ตัวตั้งค่าในกรณีนี้
ในการออกแบบนี้คุณอนุญาตให้ตรวจสอบสถานะของวัตถุจากนอกชั้นเรียนและคุณอนุญาตให้เปลี่ยนจากนอกชั้นเรียน อย่างไรก็ตามคุณไม่อนุญาตให้มีการเปลี่ยนแปลงสถานะโดยพลการ มีนโยบายซึ่งระบุว่าชื่อและ 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
- การอ้างอิงโปรด