객체지향 OO 설계 원칙은 캡슐화/상속/다형성을 지원해야한다.
데이터와 함수가 응집력 있게 구성된 집단을 서로 구분 짓는 선을 그을 수 있다.
OO언어에서는, 각각 클래스의 private 멤버 데이터와 public 멤버 함수로 표현된다.
그렇지만 OO언어에서만, 캡슐화가 되는건 아니다.
위의 c언어의 경우, pointer.h를 사용하는 측에서는 point struct 멤버에 접근할 방법이 전혀없다. 또한, 이 point struct가 어떻게 구현되어 있는지 조금도 알지 못한다 → 이게 캡슐화다.
이에 비해, c++에서의 point struct는 어떻게 구성되어있는지 너무 잘보인다. → 캡슐화가 깨진것이다.
이것을 보아 OO언어는 생각보다 캡슐화를 강제하지 않는다는 것을 알 수 있다.
OO언어가 상속은 확실히 제공한다.
그러나 c언어에서도 없었던 것은 아니다. 다만, c++로 넘어오면서, 단일 상속을 구현했다.
다형성이란 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미한다.
OO언어 이전에도 다형적인 언어는 존재했다.
void copy() {
int c;
while ((c=getchar()) != EOF)
putchar(c);
}
getchar가 문자를 읽는 STDIN
, putchar가 문자를 쓰는 STDOUT
장치는 다형적이다.
유닉스 운영체제의 경우 모든 입출력 장치 드라이버는 open, close, read, write, seek 이 다섯가지 표준 함수를 제공해야 한다. FILE 데이터 구조는 이 다섯 함수를 가리키는 포인터를 포함한다.
struct FILE {
void (*open)(char* name, int mode);
void (*close)()
int (*read)();
void (*write)(char c);
void (*seek)(long index, int mode);
}
각 입출력 드라이버는 이들 함수를 토대로 구현체를 만든다.
void open(char* name, int mode) {/*...*/};
void close() {/*...*/};
int read() {/*...*/};
void write(char c) {/*...*/};
void seek(long index, int mode) {/*...*/};
struct FILE console = {open, close, read, write, seek};
이제 STDIN을 FILE*로 선언하고 getchar를 구현할 수 있다.
extern struct FILE* STDIN;
int getchar() {
return STDIN->read();
}
OO 언어는 다형성을 새롭게 제공한 것은 아니지만 좀 더 안전하고 편리하게 사용할 수 있게 해준다. 함수에 대한 포인터를 직접 사용하면 버그가 발생하기 쉽다.
그러나 OO 언어는 이러한 관례를 없애주며 실수할 위험이 없다.
필기체 인식, 음성 장치와 같은 새로운 입 출력 장치가 추가되어 프로그램을 동작하고 싶을 때도 아무 수정이 필요하지 않다.
복사 프로그램을 다시 컴파일할 필요 조차 없다. 복사 프로그램의 코드는 입출력 드라이버의 코드에 의존하지 않기 때문이다. 새로운 입출력 장치가 FILE에 정의된 다섯 가지 표준 함수를 구현한다면 복사 프로그램에서는 이 장치를 얼마든지 사용할 수 있다.
입출력 드라이버가 복사 프로그램의 plugin이 된 것이다. OO의 등장으로 어디서든 이 플러그인(plugin) 아키텍처를 적용할 수 있게 되었다.
다형성 이전의 소프트웨어는 main 함수에서 고주순, 중간 수준 함수를 거쳐 저수준 함수를 호출하는 방향으로 설계되었다. 이러한 방식에서 소스 코드 의존성의 방향은 반드시 제어흐름을 따르게 된다.
main 함수가 고수준 함수를 호출하려면 고수준 함수가 포함된 모듈의 이름을 지정해야 한다. C의 #include
, JAVA의 import
구문 등이다.
HL1 모듈은 ML1 모듈의 F() 함수를 호출한다.
소스 코드 상에서는 HL1 모듈은 인터페이스를 통해 F() 함수를 호출하지만 런타임에서 이 인터페이스는 존재하지 않는다.
ML1과 I 인터페이스 사이의 소스코드 의존성(상속 관계)는 제어 흐름과는 반대인 점을 주목하자. 이는 의존성 역전 이라고 불린다.
의존성 역전이 가능해지면 개별적인 컴포넌트를 만들 수 있다.
컴포넌트의 소스코드가 변경되면 해당 코드가 포함된 컴포넌트만 다시 배포하면 된다. 이를 배포독립성이라 부른다.
시스템 모듈을 독립적으로 배포할 수 있게 되면, 서로 다른 팀에서 각 모듈을 독립적으로 개발할 수 있고, 이것을 개발 독립성이라 부른다.
OO란 다형성을 이용하여 시스템의 모든 소스 코드 의존성에 대한 절대적인 제어 권한을 획득할 수 있는 능력이다.
플러그인 아키텍처를 구성할 수 있고, 이를 통해 고수준의 정책을 포함하는 모듈은 저수준의 세부사항을 포함하는 모듈에 대해 독립성을 보장할 수 있다.
저수준의 세부사항은 중요도가 낮은 플러그인 모듈로 만들 수 있고, 고수준의 정책을 포함하는 모듈과는 독립적으로 개발하고 배포할 수 있다.