[Effective C++] Item 23: 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자
Item 23: 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class WebBrowser {
public:
void clearCache();
void clearHistory();
void removeCookies();
// ...
};
class WebBrowser {
public:
void clearEverything();
};
void clearBrowser(WebBrowser& wb) {
wb.clearCache();
wb.clearHistory();
wb.removeCookies();
}
이 코드에서 clearEverything
와 clearBrowser
의 함수 중 더 좋은(객체지향적인) 방법은 clearBrowser
이다. 물론 객체지향 법칙에서 데이터와 그 데이터를 기반으로 동작하는 함수는 한 데 묶여 있어야 하며, 멤버 함수가 더 낫다고 하지만 객체 지향에서 정말 중요한 원칙은 할 수 있는 만큼 캠슐화를 해야한다.
이외에도 비멤버 함수를 사용하면 관련 기능을 구성하는데 있어서 더 패키징 유연성이 높아지고 이로 인해 컴파일 의존도도 낮추며 확장성을 높일 수 있다. 그래서 비멤버 방법이 멤버 함수보다 여러모로 좋다는 것이다.
캡슐화의 관점에서 어떤 것을 캡슐화했다는 것은 외부에서 볼 수 없음을 의미하고 외부에서 볼 수 있는 것이 줄어들면 그것들을 바꿀 때 필요한 유연성이 커진다. 변경 자체가 영향을 줄 수 있는 범위가 ‘변경된 것을 볼 수 있는 것들’로 한정되기 때문이다. 즉, 이미 있는 코드를 바꾸더라도 제한된 사용자들밖에 영향을 주지 않는 융통성을 확보할 수 있다는 점이다.
C#에서는 비멤버 함수가 불가능하기 때문에 Facade패턴(물론 단일 클래스와 복합 클래스라는 차이점은 존재한다.) 비슷하게 만들어서 사용하거나 스태틱 함수로 대체해야 한다.
앞서 캡슐화 이야기를 한 이유는 비멤버, 비프렌드 함수는 어떤 클래스의 private 멤버 부분을 접근할 수 있는 함수의 개수를 늘리지 않으니 더 유연하다, 더 캡슐화할 수 있음을 의미한다.
여기서 비프렌드 함수를 좀 더 이야기 해보자면 결국 비프렌드 함수 조차도 해당 객체의 public만 접근할 수 있기 때문에 캡슐화에 대한 영향이 달라지지 않는다. (죽어라 노력해도) 따라서 비프렌드, 비멤버를 강조한 것이다.
주의해야 할 점은 캡슐화에 대한 이야기 때문에 “함수는 어떤 클래스의 비멤버가 되어야 한다”라는 주장이 “그 함수는 다른 클래스의 멤버가 될 수 없다”라는 의미가 아니라는 것이다.
추가로 namespace를 활용하면 위에서 말한 패키지 유연성이 더 좋고, 컴파일 의존성을 좀 더 낮출 수 있다. 네임스페이스는 클래스와 달리 여러 개이 소스 파일에 나뉘어 흩어질 수 있기 때문에 해당 기능을 하는 클래스와 기능을 묶거나 활용해야 하는 public함수를 같이 묶을 수 있다.
정리
- 멤버 함수보다는 비멤버 비프렌드 함수를 자주 쓰도록 하자. 캡슐화 정도가 높아지고, 패키징 유연성도 커지며, 기능적인 확장성도 늘어난다.
확실히 C#에서도 나는 기능을 묶기 위해서 public 멤버 함수로 사용하거나 Facade패턴을 사용했었는데, 해당 클래스 참조를 받아서 반환하는 정적 함수를 따로 만들면 더 캡슐화에 힘을 줄 수 있을 것 같다.
댓글남기기