Objective-C Protocol(프로토콜) 심화
과니(tiny2n) 1:1 | 2013.02.14 09:58 | 조회 1,149
가가
Objective-C Protocol(프로토콜) 심화

통신상에서 Protocol이라 하면 통신규약이라 합니다. (이쯤되면 누구 나 다 알고있죠.)
Objective-C에서 Protocol은 Delegate라 합니다. (이쯤되면 누구나 알고 있죠.) 정말 ??!!? 하지만 이말은 100% 정답은 아닙니다. Protocol를 이용해 Delegate (Pattern)를 구현할 뿐, Protocol이 Delegate라 할 수는 없습니다. 그럼 프로토콜이 무엇이냐. 프로토콜은 다음과 같습니다.

Protocol = Interface

Objective-C상에서는 Interface(이하 인터페이스라)는 용어가 없고, Protocol (이하 프로토콜) 용어만 있어서 Objective-C (이하 오브젝티브 C)만 하셨던 분들은 위에 대한 정의가 없어 프로토콜을 델리게이트와 같은 것으로 생각하고 있는 경향이 큰 것 같습니다. 잘못된건 아니지만 100% 정답이라고 할 수 없습니다.

그럼 이제 인터페이스에 대해 알아야 겠죠. 인터페이스란 코드는 없고 메소드만 있는 것을 말합니다. 전에도 잠깐 설명한것 같은데 상속에는 크게 두가지 상속이 있습니다. 그 두가지란 클래스 상속과 인터페이스 상속입니다.
클래스 상속
is-a
인터페이스 상속
can-do

 코드 공유  코드 공유 안함
 다중 상속 지원 (몇 언어만 지원)  다중 상속 지원
* 다중 상속이 몇 언어만 지원하는 것은 다중상속은 복잡성과 결합도를 매우 증가하게 되어 유지보수를 어렵게 만들게 됩니다. 그래서 새로운 언어마다 다중상속을 지원하지 않는 추세 입니다.

설계를 하다보면 복수개의 다양한 성질이 유사성을 지닌다면, 상속(다향성)으로 이를 통일하는 것이 효율적입니다. 그렇지 않다면 객체에 따라 조건문을 통해서 분기할 수 밖에 없습니다. 이러한 조건문들은 변화에 민감하기 때문에 유지보수가 어려워집니다.
(객체지향 언어는 조건문을 최소화 하는 것이 핵심)

인터페이스 상속은 진정한 의미에 다중 상속은 아닙니다. 다중 상속이란 부모가 갖고 있는 상태 및 행위를 모두 갖는 것인데, 인터페이스에는 상태는 없고 행위만 있으므로 다중 상속이 아닌 인터페이스 위임(기능 부여)라 할 수 있습니다.

OOP에 핵심중에 다음 말이 있습니다.
"구현보다는 인터페이스에 맞춰서 코딩 하라"

전 시간에도 예기했지만, 클래스 상속은 클래스간에 결합도를 높여 유연한 설계를 하기 어렵게 만듭니다. 하지만 인터페이스 상속은 구현이 결합되어 있지않아 느슨한 커플링으로 유연한 설계를 가능하게 합니다.

하지만 가장 어려운 것은 어떤 상황에서 클래스 상속을 사용하고 어느 상황에서 인터페이스 상속을 해야 하는 가 입니다.
(설계시 가장 어려운 난제 입니다. 1. 베이스 클래스에서 추상 메소드를 만들어 파생 클래스에서 재정의 해야 할지, 2. 인터페이스에 선언하여 상속하여 구현해야 할지)

아래 예제로 어느 상황에서 클래스 상속과 인터페이스 상속이 쓰여야 하는지 설명하겠습니다.
(올바른 설계는 아니지만, 항상 예제를 만드는 것이 가장 어려운 관계로...)




한국인, 일본인, 외국인 모두 인간이므로 인간을 베이스 클래스로 각각 파생 합니다.


여기서 한국사람이지만 일본어를 하는 재일교포, 한국사람이지만 영어를 하는 재미교포를 넣어달라는 요구사항이 생겼다고 합시다.

  잉??
정말 누가봐도 올바른 설계가 아니죠. 깨지기 쉬운 설계입니다.

지금부터 클래스 상속과 인터페이스 상속이 어떻게 다른가 설명하고 위 예제를 어떻게 변경해야 하는지 알아보겠습니다.


클래스 상속은 "선천성 성질"을 나타내고,
인터페이스 상속은 "후천성 성질"을 타나냅니다.

선천성 성질 : 태어났을 때부터 갖고 있는 개체의 고유한 특성입니다. 인간은 모두 "먹기"와 "자기"는 태어났을 때 부여 받는 고유한 특징입니다.
후천성 성질 : 자라면서 환경에 따라 부여받을 수 있는 기능을 추가로 부여 받는 것입니다.

위에 제시된 선천성 성질과 후천성 성질을 구분하여 클래스 상속과 인터페이스 상속을 이용하여 클래스를 설계하면 다음과 같습니다.





인터페이스 in 오브젝티브 C

그럼 이번에는 오브젝티브C 안에서의 인터페이스가 어떻게 쓰여졌나 알아보겠습니다.

서두에도 얘기했지만 오브젝티브 C에서는 인터페이스라는 말이 프로토콜이라는 말로 쓰입니다. 클래스간에 규약이라고도 하지만 사실 위와 같이 기능 부여 라는 의미가 맞습니다. (맞다 틀리다 이분화 하는 것은 아닙니다.)

예제 1.
@interface AViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

:  "선천적 성질"은 UIViewController를 따르며, "후천적 성질"은 UITableViewDelegate, UITableViewDataSource를 따릅니다.
다시말해 고유한 특성은 UIViewController 이지만, UITableViewDelegate, UITableViewDataSource의 기능을 부여합니다.

예제 2.
@interface AView : UIView <NSCopying>

: "선천적 성질"은 UIView를 따르며, "후천적 성질"은 NSCopying를 따릅니다.
다시 말해 고유한 특성은 UIView 이지만, NSCopying 기능인 깊은 복사 기능을 부여합니다. 


꼭 선언만이 아닌 구현코드에서도 인터페이스 중심으로 코딩할 수 있습니다. 다음은 제가 지금 제작하고 있는 프로젝트의 일부분 입니다.
/**
 패킷을 설정하는 메소드
 해당 패킷을 파싱하여 갯수 및 총금액을 계산
 @param SSIPacket SSIPacketPossessList
 */
- (void)setPacket:(id <SSIPacketList>)packet
{
    id <SSIPacketList> list = packet;

    // 갯수 출력
    [_lblCertificateCount setText:[@([list count]) description]];

    // 총액 계산
    NSUInteger totalBalance = 0;
    for (id <SSIPacketPossess> possess in list)
        totalBalance += [possess balance];
    
    // 총액 출력
    [_lblCertificateTotalBalance setText:[@(totalBalance) description]];
    
    [self setNeedsDisplay];
}

packet은 SSIPacketList라는 기능이 부여된 개체 입니다. count와 List<SSIPacketPossess>를 반환하는 기능이 부여되어 있습니다.
List에서도 SSIPacketPossess 인터페이스로 반환합니다. SSIPacketPossess는 총액을 반환하는 기능이 부여 되어 있습니다.



이와 같이 프로토콜(인터페이스)를 델리게이트로 생각하는 것도 틀린 바는 아니나 객체지향에서의 인터페이스는 좀더 근본적으로 시사하는게 다릅니다. 많은 공부와 연구를 통해 근본적으로 시사하는 것을 탐구하고 적용해 보길 바라겠습니다.

'개발지식창고 > iOS' 카테고리의 다른 글

IBOutlet과 IB(Interface Builder)  (0) 2013.12.19
Apple iOS Deverloper Library Site  (0) 2013.12.19
String과 Int 변환  (0) 2013.12.19
Entry point ~ View 전까지의 Process  (0) 2013.08.20
Object C 정리  (0) 2013.08.19
Posted by 모과이IT
,