본문 바로가기
프로그래밍 놀이터/iOS

[Effective Objective-C] #9 클래스 클러스터 패턴을 사용해 구현의 상세 내용을 숨기라

by 돼지왕 왕돼지 2017. 8. 11.
반응형

 [Effective Objective-C] #9 클래스 클러스터 패턴을 사용해 구현의 상세 내용을 숨기라


출처 : Effective Objective-C

abstract base class, buttonWithType, Class Cluster, class 비교, concrete implementation, Count, effective objective-c, facade, immutable array, iskindofclass, mutable array, NSArray, NSMutableArray, NS_ENUM, objectAtIndex, placeholder array, uibuttontype, [Effective Objective-C] #9 클래스 클러스터 패턴을 사용해 구현의 상세 내용을 숨기라, 가변 배열, 내성 메서드, 불변 배열, 사용 방법 문서화, 시스템 프레임워크, 재정의, 저장 공간 정의, 추상 기본 클래스, 컬렉션 클래스, 코코아 클래스 클러스터 하위 클래스 생성 규칙, 코코아의 클래스 클러스터, 클래스 클러스터, 클래스 클러스터 패턴, 퍼블릭 파사드, 플레이스홀더


-

클래스 클러스터(class cluster)는 추상 기본 클래스(abstract base class) 뒤편에 상세 구현을 숨길 수 있는 아주 훌륭한 방법이다.

이 패턴은 오브젝티브-C 시스템 프레임워크 전반에 걸쳐 사용된다.

아래 함수가 예이다.

+ (UIButton*)buttonWithType:(UIButtonType)type; 




클래스 클러스터 생성하기


-

typedef NS_ENUM(NSUInteger, EOCEmployeeType){

     EOCEmployeeTypeDeveloper,

     EOCEmployeeTypeDesigner,

     EOCEmployeeTypeFinance,

}


@interface EOCEmployee : NSObject


@property (copy) NSString *name;

@property NSUInteger salary;


+ (EOCEmployee*) employeeWithType:(EOCEmployeeType)type;


- (void)doADaysWork;


@end


@implementation EOCEmployee


+ (EOCEmployee*)employeeWithType:(EOCEmployeeType)type{

     switch(type){

          case EOCEmployeeTypeDeveloper;

               return [EOCEmployeeDeveloper new];

               break;

          case EOCEmployeeTypeDesigner:

               return [EOCEmployeeDesigner new];

               break;

          case EOCEmployeeTypeFinance:

               return [EOCEmployeeFinance new];

               break;

     }

}


- (void)doADaysWork{

     // 하위 메서드에서 이 메서드를 반드시 구현하라.

}


@end


@interface EOCEmployeeDeveloper : EOCEmployee

@end


@implementation EOCEmployeeDeveloper

- (void)doADaysdWork{

     [self writeCode];

}     

@end



-

불행히도 Objective-C 에는 기본 클래스를 추상으로 만드는 기능이 없다.

대신 클래스의 사용 방법을 문서로 만들어야 한다.

이 경우 인터페이스에 초기화 메서드들의 정의가 없는데 이는 우연히라도 기본 클래스의 인스턴스를 직접 생성할 수 없게 막아야 하기 때문이다.

기본 클래스의 인스턴스가 생성되지 않도록 보장하는 또 다른 방법은 기본 클래스의 doADaysWork 메서드에서 예외를 던지도록 하는 것이다.

그러나 이 방법은 너무 과하고 보통은 불필요하다.






코코아의 클래스 클러스터


-

시스템 프레임워크에는 많은 클래스 클러스터가 있다.

NSArray 와 NSMutableArray 같은 대부분의 컬렉션 클래스들은 클래스 클러스터다.


두 개의 추상 기본 클래스가 있다.

각각 불변 배열(immutable array)와 가변 배열(mutable array)를 위한 것이다.


이것들은 모두 클래스 클러스터이지만 두 개의 퍼블릭 인터페이스가 있다.

불변 클래스는 모든 배열에 대한 공통 메서드를 정의하고, 가변 클래스는 오직 가변 배열에 대한 메서드들만 정의한다.



-

NSArray 의 경우 NSArray 의 인스턴스를 할당하면 플레이스홀더 배열이라는 다른 클래스의 인스턴스가 할당된다. (alloc 메서드 호출 중 )

이 플레이스 홀더 배열은 결국엔 NSArray 의 구성 하위 클래스 중 하나로 변경된다.



-

NSArray(그리고 대부분의 다른 컬렉션 클래스들) 같은 클래스가 클래스 클러스터라는 사실을 꼭 알고 있어야 한다.

그 사실을 모르면 다음과 같은 코드를 작성할 수도 있다.


id maybeAnArray = /*…*/;

if ( [maybeAnArray class] == [NSArray class] ){

     // 절대 실행되지 않는다.

}



-

NSArray 초기화 메서드가 반환하는 인스턴스는 클래스 클러스터 퍼블릭 파사드(facade)에 있는 내부 타입의 인스턴스이다.

그래서 위의 코드 대신 내성 메서드를 사용해야 한다.

id maybeAnArray = /*…*/;

if ( [maybeAnArray isKindOfClass:[NSArray class] ] ) {

     // 실행될 수 있다.

}



-

클래스 클러스터에 구상 구현 ( concrete implementation )을 추가하는 것은 흔히 요구되는 것이지만

그렇게 했을 때 발생할 수 있는 경고를 처리해야 한다.

Employee 예제의 경우 새로운 직원 타입을 추가하는 것은 팩터리 메서드 소스코드에 추가하는 방법밖에 없다.

NSArray 같은 코코아의 클래스 클러스터의 경우, 할 수는 있지만 몇 가지 규칙을 따라야 한다.



-

코코아 클래스 클러스터 하위 클래스 생성 규칙


1. 하위 클래스는 클래스 클러스터의 추상 기본 클래스를 상속해야 한다.

     NSArray 의 경우 추상 기본 클래스는 가변 또는 불변 기본 클래스이다.



2. 하위 클래스는 자신의 저장 공간을 정의해야 한다.

     하위 클래스 내부에 배열이 포함하고 있는 객체들을 담는 인스턴스 변수가 꼭 있어야 한다.

     이는 기대했던 것과는 반대다.

     이 인스턴스 변수는 확실히 NSArray 에 있어야 할 것 같다.

     그러나 NSArray 자체는 배열에 대한 인터페이스만 정의한, 숨겨진 객체들을 연결하는 간단한 연결고리일 뿐이라는 사실을 기억해야 한다.



3. 하위 클래스는 상위클래스의 문서에 정의된 메서드들을 재정의해야 한다.

     각 추상 기본 클래스는 하위 클래스가 반드시 구현해야 할 메서드 집합을 가지고 있다.

     NSArray 의 경우 구현해야 하는 메서드들은 count 와 objectAtIndex: 이다.



-

클래스 클러스터의 하위 클래스를 만들 때 따라야 할 규칙은 클래스 문서에 정의되어야 하고 사용자가 항상 가장 먼저 읽어야 할 문서다.




기억할 점


클래스 클러스터 패턴은 간단한 퍼블릭 퍼사드 뒤편에 상세 구현을 숨길 때 사용할 수 있다.


클래스 클러스터는 시스템 프레임워크에서 널리 사용된다.


클래스 클러스터의 퍼블릭 추상 클래스의 하위 클래스를 만들 때는 항상 주의를 기울여야 한다.

그리고 문서가 있으면 반드시 먼저 읽어봐야 한다.




반응형

댓글