반응형
Main Point : 캡슐화는 구현의 유연성을 높인다.
- 캡슐화
- 캡슐화란 데이터와 데이터와 관련된 기능을 묶는 것이다.
- 캡슐화는 객체가 기능을 어떻게 구현했는지를 외부에 감추는 것이다.
- 즉, 구현에 사용된 데이터의 상세 내용을 외부에 감춘다.
- 캡슐화에는 정보 은닉의 의미가 포함되어 있다.
- 캡슐화를 하는 가장 큰 이유는 외부에 영향을 주지 않고 객체 내부의 구현 변경을 가능하게 하기 위함이다.
- 캡슐화하지 않으면
- 요구 사항이 바뛰면 데이터의 구조와 사용 방법이 바뀌게 된다. 이 때 캡슐화가 되어있지 않으면 데이터를 사용하는 많은 코드의 수정이 발생한다. 즉, 절차 지향적 프로그래밍이 지닌 단점이 나타나게 된다.
//정회원 기능
if (acc.getMemberShip() == REGULAR && acc.getExpDate().isAfter(now()) {
정회원 기능과 관련한 코드 작성
}
더보기
위의 코드에서는 acc라는 객체에서 memberShip 데이터, expDate 데이터를 가져와 정회원인지를 확인하고 있다. 그런데, 서비스가 지속됨에 따라 5년 이상의 사용자나 일부 정회원 기능을 1개월 무상 제공하는 혜택의 요구 사항이 추가된다고 하면 코드는 아래와 같이 바뀔 것이다.
if (acc.getMemberShip() == REGULAR &&
(
(acc.getServiceDate().isAfter(fiveYearAgo) && acc.getExpDate().isAfter(now())) ||
(acc.getServiceDate().isBefore(fiveYearAgo) && addMonth(acc.getExpDate()).isAfter(now()))
)
) {
정회원 기능 구현
}
더보기
보기만 해도 어지러운 코드의 변경이다. 그래서 조건이 뭔데?
요구 사항이 바뀌어서 serviceDate 데이터를 가져오고, 해당 날짜가 5년이 됐는지를 확인하고, expDate는 지났는지를 각각 확인해야한다.
물론 해당 조건문을 사용하는 함수 하나에만 해당 내용이 필요하면 크게 문제될 점은 없다. 문제는 5년 이상 된 서비스면, 해당 조건이 필요한 함수가 얼마나 많겠냐는 점이다.
- 캡슐화하면
- 기능을 제공하고 해당 기능의 상세 구현 내용을 감춘다.
- 특정 객체 안에 메소드(기능)을 감춰서 구현한다. 다른 객체에서는 해당 기능을 이용할 뿐 내부적으로 어떻게 기능이 작동하는지는 알 수 없다.
- 이렇게 캡슐화가 진행된 상태에서 요구 사항이 바뀌면, 해당 요구 사항이 반영된 메소드 하나만 바꾸면 된다.
- 위의 예시를 캡슐화 한 코드를 살펴보자.
public class Account {
private static final MemberShip memberShip;
private Date expDate;
public boolean hasRegularPermission() {
return memberShip == REGULAR && expDate.isAfter(now());
}
...
if (acc.hasRegularPermission()) {
정회원 기능
}
더보기
Account 객체 내에 '정회원인지 확인하는' 메소드 하나를 만들고 그에 해당하는 조건 값을 반환하는 코드로 캡슐화 할 수 있다. 이렇게 캡슐화를 진행하게 되면 이후 요구사항을 반영할 때 hasRegularPermission() 메소드만 바꿔주면 된다.
캡슐화하지 않았던 코드와 마찬가지의 요구사항이 추가된다고 하면 코드는 아래와 같이 바뀌게 될 것이다.
public class Account {
private static final MemberShip memberShip;
private Date expDate;
public boolean hasRegularPermission() {
return memberShip == REGULAR &&
(expDate.isAfter(now()) ||
(
serviceDate.isBefore(fiveYearAgo()) &&
addMonth(expDate).isAfter(now())
)
);
}
...
if (acc.hasRegularPermission()) {
정회원 기능
}
더보기
결국 반환값이 바뀌어야 하기 때문에 hasRegularPermission() 자체는 어지럽게 바뀔 수밖에 없다. 그러나 이 값을 이용하는 다른 어떤 코드도 바뀌지 않는다. 오직 hasRegularPermission() 하나만 바꾸면 된다.
- 캡슐화는 연쇄적인 변경 전파를 최소화한다
- 캡슐화는 연쇄적인 변경 전파를 최소화 한다. 즉, 캡슐화를 잘 하면 요구 사항의 변화에 따른 연쇄적인 코드의 변경을 최소화 할 수 있다.
- 캡슐화를 하는 가장 큰 이유는 캡슐화가 잘 된 기능을 사용하는 코드에 영향을 최소화 할 수 있다는 점이다.
- 캡슐화와 기능
- 캡슐화를 시도하면 기능에 대한 이해도를 높인다.
- 위의 예시에서 왜 REGULAR인지를 확인하는지 그 이유를 이해해야 명확한 코드 작성이 가능하다. 왜 REGULAR인지를 파악하다 보면 해당 조건이 '정회원의 권한을 가졌는지'를 물어보는 것임을 알 수 있다. 그리고 이를 캡슐화해서 기능을 제공하는 것이다.
- 캡슐화를 위한 규칙
- 자동으로 캡슐화가 되는 것은 아니다. 특정한 규칙을 따라 캡슐화를 진행해야 한다.
- Tell, Don't Ask (데이터를 달라고 하지 말고, '해달라고' 하자) : 데이터를 가져와서 확인하거나 가공하는 것이 아니라, 해당 데이터를 가진 객체에 데이터가 필요한 이유 자체에 수반되는 과정을 부탁한다.
- 예를 들어, 위의 예시의 경우 memberShip 데이터를 '달라고' 요청한 뒤 가져온 데이터를 확인하는 것이 아니라, Account 객체 자체에 memberShip이 REGULAR 인지를 확인'해달라고'하는 것이다.
- Demeter's Law
- 메소드에서 생성한 객체의 메소드만 호출한다.
- 파라미터로 받은 객체의 메소드만 호출한다.
- 필드로 참조하는 객체의 메소드만 호출한다.
- 예를 들어, Account에서 expDate를 호출하고 그 expDate의 날짜가 지났는지를 확인하는 것처럼 연속적으로 메소드를 사용하는 것이 아니라, 한 메소드로 호출하는 것이다. acc.getExpiredDate.isAfter(now())와 acc.isExpired(now())는 같은 값을 반환한다.
반응형
'Programming > 객체지향프로그래밍입문' 카테고리의 다른 글
# 기능과 책임 분리 (0) | 2023.01.28 |
---|---|
# 상속보다는 조립 (0) | 2023.01.27 |
# 다형성과 추상화 (0) | 2023.01.19 |
# 객체 (0) | 2023.01.16 |
# 들어가며 (0) | 2023.01.15 |
댓글