[Refactoring] 2. 인터페이스

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;

};

하면 한 눈에 인터페이스라는 것도 알아볼 수 있어 좋습ㄴㅔ다.


이렇게 해서 추상클래스와 인터페이스를 마무리합니다.

감사합니다!cool

반응형
그리드형

'컴퓨터공학과 > 그외' 카테고리의 다른 글

[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

댓글

❤️김세인트가 사랑으로 키웁니다❤️