리팩토링 37. 위임 숨기기

    들어가기 전

    이 글은 인프런 백기선님의 강의를 복습하며 작성한 글입니다


    리팩토링 37. 위임 숨기기 (Hide Deligate)

    • 캡슐화란 어떤 모듈이 시스템의 다른 모듈을 최소한으로 알아야 한다는 것이다. 그래야 어떤 모듈을 변경할 때, 최소한의 모듈만 그 변경에 영향을 받는다. 그런 상태일 때만 코드의 확장 변경이 손쉽다. 
    • 객체 지향은 '필드를 메서드로 숨기기'도 있지만, '메서드를 메서드로 숨기기'도 가능하다.
      • person.department().manager(); → person.getManager() (메서드 체이닝을 메서드로 숨김 : 위임 숨기기)
      • 이전의 코드는 Department를 통해 Manager에 접근할 수 있다는 정보를 알아야 하지만, getManager()를 통해 위임을 숨긴다면 클라이언트는 person의 getManager()만 알아도 된다. 나중에 getManager() 내부 구현이 바뀌더라도 getManager()를 사용한 코드는 그대로 유지할 수 있다. 

     

    메서드 체인 호출도 메서드로 한번 감싸서(캡슐화) 최소한의 정보만 클라이언트에게 노출할 수 있다. 그렇다면 캡슐화는 왜 중요한 것일까? 캡슐화가 중요한 이유는 모듈이 알고 있는 정보를 최소한으로 관리할수록 나중에 무언가 변경 되었을 때, 변경에 뒤따라서 변경되어야 하는 부분들이 그만큼 줄어들기 때문이다. 만약 캡슐화를 신경쓰지 않고, 여기저기에 많이 공유된다면 하나의 변경점이 수많은 부분의 변경을 촉발할 수도 있다. 

    이 리팩토링의 목적은 '클라이언트가 최소한의 정보만 알고 코드를 사용'하도록 '위임'을 캡슐화 하는 것이다. 하지만 이 부분에 너무 집착할 필요는 없다. 메서드 체이닝의 캡슐화 정도는 상황마다 달라지고 정답이 없다. 따라서 '중재자 제거' / '메서드 체인' 사이의 캡슐화는 그 때마다 잘 정해서 사용하는 정도면 충분하다. 


    코드 보기

    아래 Person 클래스의 테스트 코드를 살펴보자. 현재 테스트 코드에서는 Manager라는 변수를 가져올 때, keesun.getDepartment().getManager() 메서드를 이용해서 가져온다. 그런데 이렇게 Manager 변수를 찾아오는 상황이 '클라이언트가 너무 많이 알고 있는' 상황으로 생각할 수 있다. 이럴 때, '위임 숨기기'를 통해서 캡슐화 할 수 있다. 

    class PersonTest {
    
        @Test
        void manager() {
            Person keesun = new Person("keesun");
            Person nick = new Person("nick");
            keesun.setDepartment(new Department("m365deploy", nick));
    
            Person manager = keesun.getDepartment().getManager();
            assertEquals(nick, manager);
        }
    
    }

    현재 Person 클래스의 코드는 아래와 같다. 그리고 이 코드에 다음 순서대로 리팩토링을 진행하면 된다.

    1. getManager() 메서드를 Person 클래스에 추가한다. 
    2. 테스트 코드에서 getManager()를 사용하도록 고친다.

    이 때, department를 노출할 것인지는 선택사항이다. 왜냐하면 현재 맥락에서는 더 이상 department를 노출할 필요는 없기 때문이다. 외부 클라이언트에게는 최소한만을 공개하는 것이 좋다.

    public class Person {
    
        private String name;
        private Department department;
    
        public Person(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        // 삭제 필요. + getManager()를 추가해서 위임 숨기기
        public Department getDepartment() {
            return department;
        }
    
        public void setDepartment(Department department) {
            this.department = department;
        }
    }

    위 방식대로 리팩토링을 진행하면 다음과 같이 바뀐다.

    public class Person {
    
        private String name;
        private Department department;
    
        public Person(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setDepartment(Department department) {
            this.department = department;
        }
    
    	// 위임 숨기기용 메서드 추가.
        public Person getManager() {
            return this.department.getManager();
        }
    
    }
    
    
    class PersonTest {
    
        @Test
        void manager() {
            Person keesun = new Person("keesun");
            Person nick = new Person("nick");
            keesun.setDepartment(new Department("m365deploy", nick));
    
            // 테스트 코드 수정
            // Person manager = keesun.getDepartment().getManager();
            Person manager = keesun.getManager();
            assertEquals(nick, manager);
        }
    
    }

     

     

     

    'etc > 리팩토링' 카테고리의 다른 글

    리팩토링 38. 중재자 제거하기  (0) 2023.05.10
    냄새 18. 중재자  (0) 2023.05.10
    냄새 17. 메세지 체인  (0) 2023.05.10
    냄새 16. 임시 필드  (0) 2023.05.10
    리팩토링 36. 특이 케이스 추가하기  (1) 2023.05.10

    댓글

    Designed by JB FACTORY