확장성 있는 설계를 하기 위해 이용할 수 있는 방법은 어떤 것이 있을지에 대한 이야기이다.
클래스의 멤버 함수로 제공하는 방식과 비멤버 비프렌드 함수로 제공하는 방식의 장단점을 살펴보고 인터페이스 설계를 할 때 참고하자.
namespace WebBrowserStuff{
class WebBrowser{
public:
void clearCache();
void clearHistory();
void removeCookie();
void clearEverything();
};
void clearBrowser(WebBrowser& wb)
{
wb.clearCache();
wb.clearHistory();
wb.removeCookie();
}
}
웹브라우저로 캐시, 방문한 url 기록, 쿠키들을 지울 수 있는 함수들이 있다고 하자.
사용자 중에서 3가지 동작을 같이 하고 싶을 때 멤버함수로 제공하는 것이 좋을까? 아니면 비멤버 함수로 제공해주는 것이 좋을까?
캡슐화
캡슐화 ↑
밖에서 볼 수 있는 것 ↓
유연성 ↑
캡슐화의 정도를 파악하는 기준은 클래스의 멤버 함수 또는 데이터 멤버에 접근할 수 있는 개수가 몇 개인지로 파악하면 된다.
private 데이터멤버의 경우 이에 대한 getter, setter에 해당하는 함수의 개수 + 프렌드 함수의 개수이다.
clearEverything() 으로 한다면 그 함수 내에서는 클래스의 private 데이터 멤버 뿐아니라 멤버 함수까지 사용할 수 있다.
clearBrowser() 의 경우는 private으로 된 데이터 멤버나 멤버함수를 이용할 수 없다.
즉, 캡슐화 측면에서 비멤버 비프렌드(non-friend) 함수가 더 좋다는 의미이다.
주의! 이 삼수가 다른 클래스의 멤버가 될 수 없다는 이야기는 아님.
웹브라우저가 가진 private 멤버의 캡슐화에 영향을 주지 않는 점이 중요한 것.
패키징 유연성(packaging flexibility)
컴파일의 의존도를 낮추고 웹브라우저의 확장성도 높일 수 있다.
편의 함수
clearBrowser() 함수는 편의상 준비한 함수이다. 이 말은 clearBrowser가 없더라도 사용자 측면에서 clearBrowser 와 똑같은 기능을 할 수 있다는 말이다. 사용자는 clearCache(), clearHistory(), removeCookies() 를 순서대로 불러주기만 하면 된다.
이러한 편의 함수들을 나누어 놓는 쉽고 깔끔한 방법은 동일한 namespace 에 속하게 하고 헤더를 따로따로 구성하는 방식이다.
//"webbrowser.h" 헤더 - WebBrowser의 핵심 기능들이 선언
namespace WebBrowserStuff{
class WebBrowser{...};
}
//"webbrowserbookmarks.h" 헤더
namespace WebBrowserStuff{
...
// 즐겨찾기 관련 편의 함수들
}
//"webbrowsercookies.h" 헤더
namespace WebBrowserStuff{
...
//쿠키 관련 편의 함수들
}
namespace는 여러 개의 소스 파일에 나누어 흩어질 수 있기 때문에 응용도가 높은 클래스들은 위와 같은 방식으로 편의 함수를 구성할 수 있다. 이렇게 헤더파일을 따로 구성하면 필요한 경우에만 헤더파일을 사용해 컴파일 의존성을 쉽게 파악할 수 있다.
표준 C++ 라이브러리도 위와 같은 구조로 되어 있다.
std namespace 가 여러 개의 헤더 파일(<vector>, <algorithm>, <memory>) 들로 흩어져 선언되어 있다.
이렇게 하면 확장성을 높일 수 있는데 해당 namespace 에 비멤버 비프렌드 함수로 원하는 만큼 편의 함수를 추가해주면 되기 때문이다.
클래스는 그 전체가 한번에 정의되어야 하고 여러 조각으로 나눌 수 없기 때문에 비멤버 비프렌드 함수로 편의 함수를 만드는 것이 확장성에서 유리하다.
댓글