리펙토링은 결국 프로그램의 요소를 조작한느 일이다. 함수는 데이터보다 다루기가 수월하다. 함수를 사용한다는 건 대체로 호출한다는 뜻아고, 함수의 이름을 바꾸거나 다른 모듈로 옮기기는 어렵지 않다. 여차하면 기존 함수를 그대로 둔 채 전달 함수로 활용할 수도 있기 때문이다.(즉, 예전 코드들은 변함없이 기존 함수를 호출하고, 이 기존 함수가 새로 만든 함수를 호출하는 식이다.) 이런 전달 함수를 오래 남겨둘 일은 별로 없지만 리펙터링 작업을 간소화하는 데 큰 역할을 한다.
반대로 데이터는 함수보다 다루기가 까다로운데, 그 이유는 이런 식으로 처리할 수 없기 때문이다. 데이터는 참조하는 모든 부분을 한 번에 바꿔야 코드가 제대로 작동한다. 짧은 함수 안의 임시 변수처럼 유효범위가 아주 좁은 데이터는 어려울 게 없지만, 유효범위가 넓어질수록 다루기가 어려워진다. 전역 데이터가 골칫거리인 이유도 바로 여기에 있다.
그래서 접근할 수 있는 범위가 넓은 데이터를 옮길 때는 먼저 그 데이터로의 접근을 독점하는 함수를 만드는 식으로 캡슐화하는 것이 가장 좋은 방법일 때가 많다. 데이터 재구성이라는 어려운 작업을 함수 재구성이라는 더 단순한 작업으로 변환하는 것이다.
데이터 캡슐화는 다른 경우에도 도움을 준다. 데이터를 변경하고 사용하는 코드를 감시할 수 있는 확실한 통로가 되어주기 때문에 데이터 변경 전 검중이나 변경 후 추라 로직을 쉽게 끼워 넣을 수 있다. 데이터의 유효범위가 넓을수록 캡술화해야 한다. 레거시 코드를 다룰 때는 이런 변수를 참조하는 코드를 추가하거나 변경할 때마다 최대한 캡슐화한다. 그래야 자주 사용하는 데이터에 대한 결합도가 높아지는 일을 막을 수 있다. 객체 지향에서 객체의 데이터를 항상 private으로 유지해야 한다고 그토록 강조하는 이유가 바로 여기에 있다.
class Owner {
public String name;
public int age;
}
Class Main {
Owner owner = new Owner();
owner.name = "Alex"
owner.age = 24;
System.out.println(owner.name);
System.out.println(owner.age);
}
class Owner {
private String name;
private int age;
Owner(){}
Owner(String name, int age){
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
Class Main {
Owner owner1 = new Owner();
Owner owner2 = new Owner("Mike", 22);
owner1.setName("Alex");
owner1.setAge(24);
System.out.println(owner1.getName());
System.out.println(owner2.getAge());
}
마틴 파울러 저 리팩터링 2판