게터와 세터가 있다고해서 캡슐화가 깨지는 것은 아닙니다. 캡슐화를 깨뜨리는 것은 모든 데이터 멤버 ( Java lingo의 모든 필드 )에 대해 아무런 생각없이 자동으로 getter 및 setter를 추가하는 것입니다. 이것은 모든 데이터 멤버를 공개하는 것보다 낫지 만 조금만 걸 으면됩니다.
캡슐화의 요점은 당신이 알고 또는 객체 외부에서 개체의 상태를 변경할 수 없게하는 것,하지만 당신은 합리적인있는 것이 아니다 정책 을 수행하기위한합니다.
일부 데이터 멤버는 객체 내부에있을 수 있으며 게터 나 세터가 없어야합니다.
일부 데이터 멤버는 읽기 전용이어야하므로 게터가 필요하지만 세터는 필요하지 않을 수 있습니다.
일부 데이터 멤버는 서로 일관성을 유지해야 할 수도 있습니다. 이 경우 각 설정기에 대해 세터를 제공하지 않고 동시에 설정하는 단일 방법을 제공하므로 값의 일관성을 확인할 수 있습니다.
일부 데이터 멤버는 일정량 씩 증가 또는 감소와 같은 특정 방식으로 만 변경하면됩니다. 이 경우 세터 대신 increment()
및 / 또는 decrement()
메소드를 제공해야합니다 .
그러나 다른 사람들은 실제로 읽기 / 쓰기가 필요할 수 있으며 게터와 세터가 모두 있어야합니다.
의 예를 고려하십시오 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
-인용 부탁드립니다.