Search

Chapter07 - 객체 간의 기능 이동

객체 설계에서 가장 중요한 일 중 하나가 ‘기능을 어디에 넣을지 판단'하는 것.
기능을 넣을 적절한 위치를 찾는 문제는 메서드 이동과 필드 이동을 실시해서 기능을 옮기자
다만 필드이동 → 메서드 이동 순서
기능이 방대해질 때는 클래스 추출을 실시해서 기능을 일부 분리해야함.
기능이 너무 적어지면 클래스 내용 직접 삽입을 실시
다른 클래스가 사용 중일 때는 대리 객체 은폐를 실시해서 대리 클래스가 사용 중이라는 사실을 감추자.
대리 클래스를 은폐하면 소유한 클래스의 인터페이스가 계속 변경될 때도 있는데, 과잉 중개 메서드 제거를 실시
외래 클래스에 메서드 추가 & 국소적 상속 확장 클래스 이용은 특수 케이스

메서드 이동

동기

메서드가 자신이 속한 클래스보다 다른 클래스의 기능을 더 많이 이용할 땐, 메서드가 제일 많이 이용하는 클래스 안에서 비슷한 내용의 새 메서드를 작성하자. 기존 메서드는 간단한 대리 메서드로 전환하든지 아예 삭제하자.
다른 클래스에 대해 의존성이 지나칠 때는 메서드를 옮기는 것이 좋다.
옮길만한 메서드를 발견하면, 메서드에 대한 Callee, Caller, 재정의 여부를 판단.

필드 이동

동기

어떤 필드가 자신이 속한 클래스보다 다른 클래스에서 더 많이 사용될 때는 대상 클래스 안에 새 필드를 선언하고 전부 새 필드 참조로 수정하자.

방법

필드가 public이면 필드 캡슐화 기법
대상 클래스 안에 읽기/쓰기 메서드와 함께 필드를 작성
원본 객체에서 대상 객체를 참조할 방법을 정하자
원본 클래스에서 필드를 삭제
원본 필드를 참조하는 모든 부분을 대상 클래스에 있는 적절한 메서드를 참조하게 수정
컴파일과 테스트를 실시

클래스 추출

동기

두 클래스가 처리해야할 기능이 하나의 클래스에 들어 있을 땐 새 클래스를 만들고 기존 클래스의 관련 필드와 메서드를 새 클래스로 옮기자.

방법

옮길 필드마다 필드 이동을 적용하자.
메서드 이동을 실시해서 원본 클래스의 메서드를 새 클래스 옮기자.
인터페이스를 줄이자.
양방향을 단방향으로 바꿀 수 있는지 보자.
여러 곳에서 클래스에 접근할 수 있게 할지 결정하자.
새 클래스를 참조 객체나 변경 불가 값 객체로서 공개할지 여부를 결정

클래스 내용 직접 삽입

동기

클래스에 기능이 너무 적을 땐, 그 클래스의 모든 기능을 다른 클래스로 합쳐넣고 원래의 클래스는 삭제하자.
클래스 추출과 반대이다.

대리 객체 은폐

동기

클라이언트가 객체의 대리 클래스를 호출할 땐 대리 클래스를 감추는 메서드를 서버에 작성하자.
캡슐화가 중요하다. 무언가를 변경할 때, 그 변화를 전달해야할 객체가 줄어든다.
Persone, Department 두 클래스 모두를 클라이언트에서 수정하도록 놔두지 말고, Person에서만 Department를 수정할 수 있도록 고치자.
기본적으로 .을 여러번 사용해서, 객체 탐색을 이어나가지 말자. 랑 똑같은 거임.

과잉 중개 메서드 제거

동기

클래스에 자잘한 위임이 너무 많을 땐 대리 객체를 클라이언트가 직접 호출하게 하자.
기본적으로 대리 객체 은폐의 반대임.
객체 사용을 캡슐화하면 얻는 장점도 있지만, 단점도 있음.
클라이언트가 대리 객체의 새 기능을 사용해야할 때마다, 중간에 위임 메서드를 추가해야한다.
이런 경우가 너무 많아지면 객체를 숨길 필요가 없다는 뜻.
시스템이 변경되면서 은폐 정도의 기준이 달라질 수 있다

외래 클래스에 메서드 추가

동기

서버 클래스에 메서드를 추가해야하는데, 그 클래스를 수정할 수 없을 땐 클라이언트 클래스 안에 서버 클래스의 인스턴스를 첫 번째 인자로 받는 메서드를 작성하자.
Date newStart = new Date(previousEnd.getYear(), previousEnd,getMonth(), previouseEnd.getDate() + 1); ----------------------- Date newStart = nextDay(previousEnd); private static Date nextDay(Date arg){ return new Date(arg.getYear(), arg.getMonth(), arg.getDate()+1); }
Java
복사
외래 메서드는 임시방편에 불과하다. 가능하면 외래 메서드를 원래 있어야할 위치로 옮겨야한다.

국소적 상속확장 클래스 사용

동기

사용 중인 서버 클래스에 여러 개의 메서드를 추가해야하는데, 수정할 수 없을 땐, 새 클래스를 작성하고 그 안에 필요한 여러 개의 메서드를 작성하자.
필요한 메서드가 한 두개 일 때는 클라이언트에 추가하면 된다. 근데 여러 개면 차라리 상속해서 기능을 화장하는게 좋다.
하위 클래스를 쓰던가 래퍼 클래스를 쓰던가 두 개가 있다.
래퍼 클래스를 쓰면 모든 메서드를 위임해야한다.
래퍼 클래스를 쓸 때는, 원본 객체를 인자로 받는 메서드가 문제가 된다.
public boolean after (Date arg); aWrapper.after(aDate); aWrapper.after(anotherWrapper); aDate.after(aWrapper); // 불가능하다.
Java
복사
그럼에도 래퍼 클래스를 쓰는 이유는 클라이언트가 래퍼를 쓰고 있는지를 모르게 하기 위함임.