👉 이 게시글은 inflearn의 코딩으로 학습하는 리팩토링 강의 내용을 바탕으로 작성되었습니다.
메소드를 호출하는 것을 메소드를 가지고 있는 객체에 메세지를 전달한다고 표현하기도 합니다. 즉, 하나의 메소드를 호출하는 것이 아니라 레퍼런스를 따라 계속해서 메소드 호출이 이어지는 구조를 메세지 체인이라고 합니다.
ex) this.member.getCredit().getLevel().getDiscription()
이러한 체인이 길어지게 된다면 코드가 이해하기 어려운 형태가 될 뿐만 아니라, 이 과정에 호출되는 메소드 중 하나가 변경이 된다면 체인을 이루고 있는 메소드의 코드도 변경이 필요하기 때문에 작업량이 많아집니다.
이 글에서는 메시지 체인을 캡슐화하여 클라이언트가 최소한의 정보만 알고도 코드를 사용할 수 있게끔 하는 리팩토링 기술에 대해 알아보겠습니다.
캡슐화 (Encapsulation)는 특정 모듈이 시스템의 다른 모듈을 최소한으로 알 수 있도록 하여 클래스 간의 결합도를 낮추는 역할을 합니다.
따라서 어떤 모듈을 변경할 때, 최소한의 모듈만 영향을 받게 하여 변경하기 용이하게 하는 것이 리팩토링의 목적입니다.
public class Person {
private String name;
private Department department;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
public class Department {
private String chargeCode;
private Person manager;
public Department(String chargeCode, Person manager) {
this.chargeCode = chargeCode;
this.manager = manager;
}
public String getChargeCode() {
return chargeCode;
}
public Person getManager() {
return manager;
}
}
class PersonTest {
@Test
void manager() {
Person joonkyo = new Person("joonkyo");
Person nick = new Person("nick");
joonkyo.setDepartment(new Department("deploy", nick));
Person manager = joonkyo.getDepartment().getManager();
assertEquals(nick, manager);
}
}
클라이언트 코드 (test code)에서 manager를 받아오는 코드가 메세지 체인 형태로 이루어져 있습니다.
기존 코드에서는 Department 클래스를 통해 manager에 접근할 수 있다는 정보를 알아야 하는 단점이 있습니다.
public class Person {
private String name;
private Department department;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
Person getManager() {
return getDepartment().getManager();
}
}
Department의 getManager() 메소드를 Person 클래스로 이동시켜 클라이언트의 메시지 체인 형태의 코드를 다음과 같이 간결하게 만들었습니다.
class PersonTest {
@Test
void manager() {
Person joonkyo = new Person("joonkyo");
Person nick = new Person("nick");
joonkyo.setDepartment(new Department("deploy", nick));
Person manager = joonkyo.getManager();
assertEquals(nick, manager);
}
}
이렇게 되면, 나중에 getManager() 메소드의 내부 로직이 변경되더라도 getManager()를 사용한 코드는 그대로 유지할 수 있게 되고, 클라이언트에서는 Person 클래스의 getManager()만 파악해도 해당 코드의 동작 방식을 쉽게 이해할 수 있기 때문에 유지 보수 측면에서 상당한 이점을 갖게 됩니다.