[Refactoring] 2. 인터페이스
- 컴퓨터공학과/그외
- 2015. 10. 29.
2. 인터페이스
이번에는 핸드폰 예제를 이용합니다!
쌈쏭의 자랑 애니콜(Anycall) 핸드폰의 통화(call)기능을 구현합니다.
사람(Person)은 use_phone()을 통해 이 기능을 사용합니다.
싸이언(Cyon) 핸드폰을 하나 더 구매했다고 합시다.
싸이언은 통화 기능이 애니콜과 달리 send 함수를 사용하네요.
역시 통화하기 위해 Person 클래스에 싸이언용 use_phone()을 구현합니다.
애니콜과 싸이언은 다른 타입으로, 다른 타입의 포인터끼리는 호환이 되지 않기 때문에
void use_phone(Cyon *p, const char* n) { p -> send(n); }
을 하나 더 만들어주어야 하는 것이죠.
메인함수에는
int main()
{
Person p;
Anycall a;
p.use_phone(&a, "000-0000-0000");
Cyon c;
p.use_phone(&c, "000-1111-1111");
}
가 추가되겠지요.
그러나 이렇게 구현하게 되면 OCP(Open Close Principle, 개방폐쇄원칙)에 위배됩니다.
♥ 개방-폐쇄 원칙은 시스템의 구조를 올바르게 재조직(리팩토링)하여 나중에 이와 같은 유형의 변경이 더 이상의 수정을 유발하지 않도록 하는 것이다. 개방-폐쇄 원칙이 잘 적용되면, 기능을 추가하거나 변경해야 할 때 이미 제대로 동작하고 있던 원래 코드를 변경하지 않아도, 기존의 코드에 새로운 코드를 추가함으로써 기능의 추가나 변경이 가능하다. [출처-위키피디아]
이는 tightly coupling 되어 있기 때문입니다.
다른 핸드폰을 사용한다면,
핸드폰 클래스를 추가해주고, Person 클래스에는 타입에 맞게 use_phone을 구현해주어야하는 번거로움이 생깁니다.
OCP원칙에 위배되지 않고, 핸드폰 하나가 더 추가되더라도 내부 코드는 변화 없이 구현할 수 있을까요?
>>> loosely coupling을 만들면 됩니다!
모든 핸드폰은 같은 이름을 쓰는 통화 기능(call)을 반드시 구현하도록 강제화합니다.
-> 앞에서 배웠듯이 추상 클래스를 도입하면 되겠지요?
우선, 애니콜과 사이언 모두 Phone 클래스를 상속받아 call 기능을 무조건적으로 구현하도록 합니다.
class Phone
{
public :
// 순수 가상 함수는 자식에게 특정 기능을 강제화하기 위해 사용
virtual void call(const char *n) = 0;
};
여기서 인터페이스 개념이 등장합니다. 읭??????
인터페이스는 서로 다른 클래스를 연결하는 연결장치라고 볼 수 있습니다.
여기서는 Anycall, Cyon 클래스를 Person 클래스와 연결하는 Phone 클래스를 인터페이스라고 할 수 있겠죠.
그러나 97번째 줄의 Person클래스에서 보면
use_phone의 첫 번째 파라미터를 다르게하여(Anycall, Cyon 포인터 타입이 다르기 때문에)
2개의 함수를 재정의 해주는데요.
♥ 상속을 받았으니
부모타입 * = &자식객체; 가 가능하게 됩니다.
내부적으로 부모의 코드를 가지고 있기 때문에 Upcasting이 가능합니다.
따라서
애니콜과 사이언의 부모 클래스인 Phone 클래스를 이용하여
void use_phone(Phone* p, const char* n) { p -> call(n); }
라고 구현할 수 있게 됩니다.
내부의 코드는 변화 없이
스카이 (Sky) 핸드폰도 추가 할 수 있습니다.
172~176줄 SKY 클래스가 추가 되어도 다른 코드는 변함이 없이 사용될 수 있습니다.
이렇게, 인터페이스를 사용하면
코드 수정을 국지화할 수 있고
폰클래스와 사람클래스 모두 인터페이스에만 맞춰서 개발하면 되므로
개발 향상성이 2배 빨라진다고 할 수 있습니다!!
인터페이스는 서로 다른 클래스를 연결하는 연결장치라고 볼 수 있습니다.
인터페이스를 사용하면 코드 수정을 국지화할 수 있고, 개발 향상성을 높일 수 있습니다.
*
참고로
자바에서는 인터페이스를 알아보기 위해 interface 키워드를 사용하는데,
interface 키워드가 없는 C++에서는 관례적으로 심볼 I를 클래스 이름 앞에 붙여줍니다.
class IPhone
{
public :
virtual void call(const char *n) = 0;
};
IPhone이 되었네요?!ㅋㅋㅋㅋㅋㅋ
그렇지만 I를 쓰는 것은 너무 없어보이쟈냐!
define을 사용하여
#define interface class
로 정의해주고, interface 클래스에는 다음과 같이
interface Phone
{
public :
virtual void call(const char *n) = 0;
};
하면 한 눈에 인터페이스라는 것도 알아볼 수 있어 좋습ㄴㅔ다.
이렇게 해서 추상클래스와 인터페이스를 마무리합니다.
감사합니다!
'컴퓨터공학과 > 그외' 카테고리의 다른 글
[Refactoring] 4. 상속 (0) | 2015.11.18 |
---|---|
[Refactoring] 3. 캐스팅 (0) | 2015.11.18 |
[Refactoring] 1. 순수 가상함수와 추상 클래스 (0) | 2015.10.29 |
Top 10 IT Trends for 2015 (0) | 2015.06.29 |
[ML] Linear Classification (0) | 2015.06.12 |