개발 서적 기록/오브젝트_조영호

16일차 - 캡슐화가 적절지 않은 경우와 명령 쿼리 분리 원칙

밍 끄적 2023. 8. 19. 01:19
728x90

2023.08.18 FRI

199p ~ 213p

 

15일차 내용 ⬇️

2023.08.18 - [개발 서적 기록/오브젝트_조영호] - 15일차 - 퍼블릭 인터페이스 만들기

 

15일차 - 퍼블릭 인터페이스 만들기

2023.08.18 FRI 183p ~ 198p 14일차 내용 ⬇️ 2023.08.15 - [개발 서적 기록/오브젝트_조영호] - 14일차 - 협력, 메시지, 퍼블릭 인터페이스, 오퍼레이션 14일차 - 협력, 메시지, 퍼블릭 인터페이스, 오퍼레이션

magenta-ming.tistory.com


디미터 법칙은 어떤 객체와 결합되어 있는지를 고려하는 것이다.

협력을 제한하는 디미터 법칙에서, 한개의 dot(.)을 쓰는 것을 권장했다.

 

하지만 이 말은 어떤 객체와 결합되는지에 따라 다르다.

 

IntStream.of(1, 15, 20, 3, 9).filter( x -> x > 10 ).distinct().count(); 와 같은 코드는 계속 dot를 통해 다른 메서드를 호출하고 있지만 계속 IntStream의 인스턴스와 결합될 뿐이다. 따라서, 디미터 법칙을 위반하지 않는다.

 

항상 캡슐화 해야하는 것은 아니다

캡슐화를 엄격히 지키기 위해서, 협력을 제한하거나 다른 객체에 묻지 않고 시키다, 어긋난 책임을 할당할 수 있다.

 

예를 들어 아래와 같은 코드가 있다.

AppleStore에서 주어진 User에게 MacBook을 구매하는 buyMac 메서드는 user로부터 예약 객체를 가져와서, 그 예약이 유효한지 확인한다.

만약 유효하다면, 에약 ID를 통해서, 예약된 맥북을 가져와 유저에게 추가한뒤 반환한다.

유효하지 않은 예약이라면, 결제한 뒤에 새로운 맥북을 가져와 유저에게 추가한다.

public class AppleStore {
	
    public MacBook buyMac(User user){
    
    	if(user.getReservation().isValid()){
        	
            Long reservationId = user.getReservation().getId();
            MacBook m = MacBook.ofReserve(reservationId);
            return user.addNewMac(m);
        } else{
        	
            user.getWallet().getPay();
            MacBook m = MacBook.ofNew();
            return user.addNewMac(m);
        }
    }
}

디미터 법칙에 의하면, AppleStore 객체는 User 뿐만 아니라 Reservation 객체에도 의존하고 있으며, 외부 객체의 상태에 따라 판단하고 있기에 좋은 코드가 아니다.

그래서 이를 개선하기 위해서 User가 예약이 유효한지 판단하게 한뒤 맥북을 가져오게해서 스스로 추가하고 스스로 결제하도록 캡슐화를 수행할 수 있다.

 

하지만, 그건 User의 책임에 맞을까? User는 카드만 건네주고 맥북만 받으면 될일이다. 예약이 유효한지 판단하고 어떤 맥북을 가져올지는 AppleStore가 해야할 일이다. 즉, User에게 적절하지 않은 책임이 할당되어 User 객체의 응집도가 낮아진다.

또, 지금은 예약과 현장구매만 있지만, 홈쇼핑이나 온라인 구매와 같은 다른 상황이 추가된다면 User가 영향을 받는다.

 

따라서, AppleStore의 캡슐화를 높이는 것보다, AppleStore와 User의 응집도를 높이는 것이 전체적인 관점에서 적합하다.

 

이처럼 항상 캡슐화를 지향하는 것이, 전체적인 관점에서는 객체지향적이지 못하는, 어떤 부작용을 낳을 수 있다.

 

명령 쿼리 분리 원칙을 통한 퍼블릭 인터페이스

루틴

어떤 절차를 묶어 호출 가능하도록 이름을 부여한 기능

프로시저 / 명령

루틴 내에서, 부수 효과를 발생시킬 수 있지만 값을 반환할 수 없다.

객체의 상태를 수정하는 오퍼레이션이다.

함수 / 쿼리

루틴 내에서, 값을 반환할 수 있지만 부수효과를 발생시킬 수 없다.

객체와 관련된 정보를 반환하는 오퍼레이션이다.

명령 쿼리 분리 원칙

오퍼레이션은 명령 혹은 쿼리 둘 중 하나여야한다.

따라서, 객체의 상태를 변경하는 명령은 반환값을 가질 수 없고, 객체의 정보를 반환하는 쿼리는 상태를 변경할 수 없다.

 

728x90