CHAPTER 2 사례연구: 아이폰 앱 설계
앱의 설계를 하는데 중요한 세 가지 일
1. 아이디어의 개념화
2. 룩앤필(look-and-feel) 설계
3. 앱 아키텍처 설계
여러가지 디자인 패턴(아이폰에서 주로 사용되는 것들)
미디에이터
컴포지트
비지터
프록시
메멘토
커맨드
옵저버
CHAPTER 3 프로토타입
'복제(clone)' 오퍼레이션에 적용하는 패턴을 프로토타입(prototype)아라고 한다. 같은 주조 틀을 사용해서 제품을 생산하는 것이 복제인데, 이때 주조 틀의 근간이 되는 것이 프로토타입이다.
정의
프로토타입 인스턴스를 사용해서 생성할 여러 종류의 객체를 기술하고 해당 프로토타입을 복제하여 새로운 객체를 생성한다.
사용하는 상황
1) 객체의 타입이나 구체적인 생성 방법을 클라이언트 코드와는 독립적으로 유지하면서 객체를 생성할 필요가 있을 때
2) 인스턴스가 생성될 클래스가 런타임 시에 결정될 때
3) 서로 다른 클래스의 인스턴스들이 속성의 일부만 다를 뿐 거의 유사할 때, 이런 경우 각 클래스들의 객체를 일일이 생성하지 않고 그 클래스들과 대응되는 프로토타입 클래스들의 객체를 복제하는 것이 더 좋다.
4) 객체의 일부분으로 다른 객체를 포함하는 복합 객체와 같은 경우는 객체 생성이 쉽지 않다. 따라서 기존에 있는 복합 객체를 복제한 후 변경해서 사용하면 더 쉬울 것이다.
Mark 복합 객체의 복사 메서드 구현하기
서브 클래스에서 copy메서드를 성넣나고 있지 않아도 NSObject 클래스에는 선언되어 있다. 따라서 copy메서드가 호출되면 NSObject에서 그 호출을 자신의 서브 클래스에게 전달된다. 그러므로 각 서브 클래스에서는 자신의 복제 객체를 반환하기 위해 NSCopying 프로토콜에 정의된 copyWithZone:zone 메서드를 구현해야한다. 만약 구현하지 않으면 NSInvalidArgumentException 예외가 발생한다.
tip) [[self class] allocWithZone:zone]에서 [self class]를 사용한 이유는 Vertex의 서브 클래스들도 이 copy 메서드를 재사용할 수 있께 하기 위함이다. 그렇지 않고 [Vertex alloc]을 사용하면 Vertex의 서브 클래스들은 자신들의 실제 타입이 아닌 Vertex 타입의 복사 객체를 반환하게 될 것이다.
복제된 Mark 객체를 패턴 템플릿으로 사용하기
사견
copy메서드를 잘 정의해놔야지 서브 클래스들도 정리하기 편하다.
CHAPTER 4 팩토리 메서드
이 팩토리 메서드 패턴은 추상 팩토리(Abstract Factory) 패턴의 필수 요소가 된다.
팩토리 매서드 패턴이란?
객체를 생성하는 인터페이스를 정의하되, 실제 객체 생성은 해당 객체가 속하는 서브 클래스에서 하도록 한다.
팩토리 메서드는 언제 사용하면 좋을까?
1) 런타임 시에 정확히 어떤 클래스의 객체가 생성될지 예상할 수 없을 때
2) 생성되는 객체의 클래스들을 특정 클래스의 서브 클래스들로 두고자 할 때
3) 어떤 클래스에서 도우미(helper) 클래스들을 서브 클래스로 갖고 있으면서 그 서브 클래스 중 하나의 객체를 생성하여 반환하고자 할 때
예를 들면 NSNumber인데 [NSNumber numberWithBool:YES]는 NSNumber의 서브 클래스인 NSCFBoolean의 객체를 생성한다.
팩토리 메서드가 안전한 객체 생성 방법인 이유는?
공통적인 인터페이스를 갖는 팩토리 메서드만 알면 된다. 추후에 새로운 클래스가 추가되더라도 클라이언트 코드를 수정할 필요가 없다.
사견
책의 예제에서 팩토리 매서드 패턴의 예를 들어준 코드를 살펴보면 controller는 도화지의 controller라서 실제 메세지(메서드 콜)을 해주는 코드는 별도로 존재한다. 예를 들면 loadCanvaseViewWithGenerator:[[ClothCanvaseViewGenerator alloc] init] 을 해야지 해당 함수에서 좌변항이나 우변항이나 모두 상속 구조이기 때문에 만족하는 것이다. 여기서 CanvasViewController는 본인이 어떤 canvasView로 생성받았는지 알 수 없다.(알고자 하면 class로 비교해봐야할듯)
CHAPTER 5 추상 팩토리
정의
생성할 객체의 실체 클래스를 명시하지 않고도 같은 종류에 속하는 객체들을 생성할 수 있는 인터페이스를 제공한다.
이 패턴은 다른 패턴에서도 많이 활용된다. 프로토타입 패턴, 싱글톤 패턴, 플라이웨이트 패턴 등이 있다.
추상팩토리와 팩토리 메서드의 비교
추상 팩토리 |
팩토리 매서드 |
객체 합성(composition)을 사용한 객체 생성의 추상화 동일한 종류의 여러 객체들을 생성한다. 새로 추가된 타입의 객체 생성을 지원하려면 부모타입(클래스)의 인터페이스를 수정할 필요가 있다. |
클래스 상속(inheritance)을 사용한 객체 생성의 추상화 한 가지 타입의 객체를 생성한다. 새로 추가된 타입의 객체 생성을 지원하려면 그 객체의 클래스를 기존 부모 클래스의 서브 클래스로 추가하고 부모 클래스의 팩토리 메서드를 오버라이딩한다. |
참고
기존의 추상 팩토리에서 모든 상표에 대해 새로운 UI요소가 지원할 필요가 있을 때는 그것에 대응되는 팩토리 메서드를 부모 클래스에 새로 추가할 필요가 있다. 이 경우 새로 추가된 팩토리 메서드를 지원하기 위해 모든 서브 클래스의 코드도 변경되어야 할 것이다.
기타
이 구조는 인스턴스를 생성하기 위해서 클래스 팩토리 메서드를 사용하는데 장점으로는 런타임 시에 사용할 BrandingFactory 인스턴스를 결정하기 위해서 복잡한 메커니즘을 설계할 필요가 없다는 것이다. (전처리기 정의를 통해서 컴파일 시점에 결정되니깐)
...
이와 같이 Foundation 프레임워크에 구현된 추상 팩토리를 '클래스 클러스터'라고 한다.
사견
팩토리 메서드를 오버라이딩하여 구현한다.
CHAPTER 6 빌더
: 하나의 생성 공정을 각각의 관계로 세분화하여 더욱 조정이 쉽고 재사용이 가능하게 만드는것. 이런 종류의 관계를 설계하는 데 필요한 디자인 패턴을 빌더(Builder)라고 한다.
정의
복잡한 객체의 생성을 그 객체의 표현(representation)과 분리하여 동일한 생성 방법으로 그 객체의 다른 표현을 만들 수 있게 한다.
빌더 패턴은 언제 사용하면 좋을까?
1) 서로 다른 여러 요소를 갖는 복잡한 객체를 생성할 필요가 있을 때. 이때 그 객체를 생성하는 알고리즘은 각 요소들을 결합하는 방법과 독립적이어야 한다. 흔한 예가 복합 객체(트리 구조와 같은)의 생성이다.
2) 어떤 객체를 여러 가지 방법으로 생성할 필요가 있을 때.(예를 들어 그 객체의 요소들을 여러 가지로 조합해서 만들 때)
빌더 |
추상 팩토리 |
복잡한 객체를 생성한다. 여러 단계로 객체를 생성한다. 여러 가지 방법으로 객체를 생성한다. 마지막 생성 단계에서 객체를 반환한다. 한 가지 타입의 특정 객체 생성에 초점을 둔다. |
간단한 또는 복잡한 객체를 생성한다. 한 단계로 객체를 생성한다. 한 가지 방법으로 객체를 생성한다. 생성된 객체를 곧바로 반환한다. 같은 종류의 여러 가지 객체들을 생성하는 데 중점을 둔다. |
사견
builder 클래스에서 newCharacter라는 식의 콜이 들어오면 기존에 갖고있던 character를 제거하고 새로 만들어 놓고, builder에게 여러 속성 값들의 변경을 메세지로 던진 다음에 객체를 받아오면 끝난다.
CHAPTER 7 싱글톤
정의
클래스에서 단 하나의 인스턴스만 갖도록 하여 그 인스턴스가 전역적인 액세스 포인트가 되도록 한다.
Objective-C에서 싱글톤 객체를 생성할 때 주의할 점이 2가지가 있다.
1) 호출 객체에서는 다른 방법을 통해 싱글톤 객체를 생성할 수 없어야 한다. 그렇지 않으면 싱글톤 클래스의 인스턴스가 여러 개 생성될 수 있기 때문이다.
2) 싱글톤 객체 생성 시의 제약 사항들은 참조 카운팅 메모리 모델에도 동일하게 해당된다.
싱글톤이라고 별도로 정의된건 없고, 자원이 할당되었는지 확인하고 추후에 자원이 해제되지 않게 관리하면 된다.
싱글톤의 서브 클래스 만들기
+ (Singleton *) sharedInstance {
if (sharedSingleton_ == nil) {
sharedSingleton_ = [NSAllocateObject([self class], 0, NULL) init];
}
return sharedSingleton_;
}
위 코드처럼 NSAllocateObject에 대한 싱글톤은 재정의하면 된다.
CHAPTER 8 어댑터
어댑터 패턴은 혹은 래퍼(Wrapper)라고도 한다. 그 개념은 클라이언트가 기대하는 인터페이스를 구현하는 어댑터를 제공하는 것이다.
어댑터 패턴은 2가지가 존재한다.
첫 번째는 클래스 어댑터라고 해서 상속을 사용해서 하나의 인터페이스를 다른 것에 맞추는 것입니다.
정의
어떤 클래스의 인터페이스를 클라이언트가 원하는 다른 인터페이스로 변환한다. 인터페이스가 호환되지 않아서 함께 사용할 수 없는 클래스들을 어댑터가 사용할 수 있게 해준다.
클래스 어댑터 VS 객체 어댑터
클래스 어댑터 |
객체 어댑터 |
하나의 실체 어댑티(Adaptee) 클래스만을 목표(target) 인터페이스에 맞춘다. 어댑티의 서브 클래스에서 하는 것처럼 어댑터 에서는 어댑티의 행동을 쉽게 오버라이딩할 수 있다. 어댑터 객체 하나만 필요하다. 어댑티 객체를 액세스하기 위해 별도의 포인터(참조)가 필요없다. |
어댑티 클래스와 그것의 여러 서브 클래스들을 목표 인터페이스에 맞출 수 있다. 어댑터에서는 어댑티의 객체 참조를 필요로 한다. 어댑티 객체를 액세스하기 위해 별도의 포인터(참조)가 필요하다. |
어댑터 패턴을 언제 사용하면 좋을까?
1) 기존 클래스의 인터페이스가 우리가 필요한 것과 일치하지 않을 때
2) 인터페이스가 호환되지 않는 다른 클래스들과 함께 사용할 수 있는 재사용 가능한 클래스를 원할 때
3) 어떤 클래스의 여러 서브 클래스들을 다른 클래스의 인터페이스와 맞추어 재사용하고 싶을 때. 이때 각 서브 클래스에서 어댑터 클래스를 따로 인터페이스하는 것은 비효율적이다. 그러므로 부모 클래스와 인터페이스하는 객체 어댑터를 사용한다.
위임 이해하기
어댑터 패턴은 위임 패턴(Delegation)의 하위 패턴이다. 또, 위임이라는 메커니즘은 데코레이터(Decorator) 패턴과 같은 또 다른 디자인 패턴의 목적도 달성할 수 있다.
Objective-C 프로토콜로 어댑터 패턴 구현하기
팁) 뭔가를 재사용하기 윈할 때는 그것을 객체로 만들어야 한다. 색상 변경 처리를 객체로 만든다면 커맨드 객체로 만드는 것이 좋은 방법이다. 커맨드 객체는 대기열 처리와 재사용이 가능하고 명령의 취소와 재실행이 가능하다.
사견
이 패턴은 책이 너무 복잡하게 설명되어 있어서 별도로 objective-C에선 어떻게 사용하는지 알아봐야겠다.
CHAPTER 9 브리지
하나의 구현을 운영체제 별로 각각 구현한다면 클래스 상속 구조의 크기가 말도 안 되게 비대해질 것이다. 이런 문제의 해결책은 서로 다른 윈도우 타입의 추상화를 서로 다른 운영체제의 각 윈도우 구현과 분리시키는 것이다. 이런 설계의 문제를 해결하는데 도움을 주는 디자인 패턴을 브리지(Bridge) 패턴이라고 한다.
브리지 패턴의 목적은 추상화 계층을 그것의 구현 계층과 분리시키는 것이다.
정의
추상체를 그건의 구현과 분리시킴으로써 그 두 가지가 독립적으로 변경될 수 있게 한다.
브리지 패턴은 언제 사용하면 좋을까?
1) 추상체와 그것의 구현을 영구적으로 결합하고 싶지 않을 때
2) 추상체와 그것의 구현 모두 나름의 서브 클래스로 확장될 수 있어야 할 때
3) 추상체의 구현을 변경해도 클라이언트 코드에 영향을 주지 않아야 한다.
4) 추상체를 개선하기 위해 그것의 구현체에 서브 클래스가 추가될 필요가 있다면, 그것은 곧 그것들을 두 가지 부분으로 분리할 필요가 있다는 것을 의미한다.
5) 서로 다른 추상 인터페이스를 사용하는 여러 객체들 간에 구현 부분을 공유하고 싶을 때
CHAPTER 10 퍼사드
서브 시스템의 서로 다른 인터페이스들에 대해 통합된 인터페이스를 제공하는 방법이 퍼사드(facade) 패턴이다.
(복잡도를 줄이고 서브 시스템 간의 정보 전달과 의존도를 감춤으로써 서브 시스템을 사용하기 쉽게 해주는 고수준의 인터페이스)
퍼사드 패턴은 언제 사용하면 좋을까?
CHAPTER 11 미디에이터
각 UI 요소가 더 많이 개입되면 혼란이 더욱 가중될 수 있으며, 각 UI 요소 간의 모든 트래픽을 관리하는 소통 제어가 필요하게 된다. 같은 컨텍스트에 있는 서로 다른 UI 요소 간의 상호 작용을 체계화하는 역활을 미디에이터(Mediator, 중재자)라고 한다.
미디에이터 패턴은 객체들 간의 상호 접속이 하나의 미디에이터 객체에서 처리될 수 있는 집중된 장소를 정의하기 위해 사용된다. 이 경우 다른 객체들은 서로 직접 접속할 필요가 없으므로 객체들 간의 의존도를 줄여준다.
Colleague 인스턴스는 Mediator 인스턴스의 참조를 갖는다. 반면에 Mediator 인스턴스는 이 체계에 포함된 모든 객체를 안다. 중요한 것은 모든 객체가 서로는 모르고 Mediator만 안다는 것이다.
미디에이터 패턴은 언제 사용하면 좋을까?
뷰 전환의 교통 순경과 같은 역활을 하는 컨트롤러 : CoordinatingController
UI 컴포넌트와 뷰 컨트롤러 간의 UI 처리 흐름 로직을 수행한다.
(사용자가 버튼을 터치하면 뷰 저난 요청이 촉발되어 CoordinatingController가 그 요청을 수행한다.)
요약
객체 상호간에 의존적인 경우에는 미디에이터 패턴이 매우 유용하다. 그러나 미디에이터 클래스 자체가 너무 비대해져서 유지보수가 어렵게 되는 것을 막을 수 있는 예방책이 반드시 고려되어야 한다. 예방책은 다른 디자인패턴을 도입하는 것이다.
사견
이건 UI뿐만 아니라 다른 곳에서도 사용 가능할듯. 요약하면 중재자, 사용자로 나눠서 생각하면 쉽다.
CHAPTER 12 옵저버
객체지향 소프트웨어 설계에서도 다른 행동을 갖는 객체들을 분리(또는 특정 객체의 행동을 다른 객체로 확장)하는 데 적용하고 있다. 그리고 그렇게 하면 서로 다른 객체들이 함께 동작할 수 있고, 동시에 다른 곳에서 재사용될 수도 있다.
옵저버 패턴은 Publish-Subscribe(발행-구독)패턴이라도고 한다.
옵저버 패턴은 언제 사용하면 좋을까?
실 사용 예제
1) 모델-뷰-컨트롤러에 옵저버 패턴 사용하기
2) 코코아 터치 프레임워크에서 옵버저 패턴 사용하기
2-1) 통보, NSNotificationCenter, NSNotification 객체를 사용한 일대다(one-to-many)의 Publish-Subscribe 모델
메세지 보내기 NSNotification *notification = [NSNotification notificationWithName:@"data changes" object:self]; NSNotificationCEnter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter postNotification:notification]; |
본인 등록하기 [notificationCenter addObserver:self selector:@selector(update:) name:@"data changes" object:subject]; |
2-2) 키-값 관찰(key-value observing)
통보 |
키-값 관찰 |
중심이 되는 객체가 모든 옵저버 객체들에게 변경 통보를 제공 주로 프로그램 이벤트들과 관련된다 |
관찰되는 객체가 옵저버 객체들에게 직접 통보를 보낸다. 특정 객체의 속성 값과 결부된다. |
2-3) CanvasView의 스트로크 변경하기
MVC 모델이다. 너무 디테일한 내용이라 스킵했다.
CHAPTER 13 컴포지트
컴포지트(composite)는 같은 종류의 다른 객체를 포함하는 객체이다.
사견
스스로를 계속 추가하는 구조이다.
마지막 노드도 add, remove의 함수를 갖고 있는건 어쩔 수 없다.
타입 검사를 안해도 되서 편리하다.
그리고 이걸 구현하는데 objective-C에선 프로토콜을 이용한다.
컴포지트 패턴은 언제 사용하면 좋을까?
1) 객체의 추상화 트리 구조(부분-전체 계층으로 된)가 필요할 때
2) 클라이언트가 복합 구조의 모든 객체와 개별 객체를 일관되게 처리하도록 하고 싶을 때
요약
트리 구조의 각 노드가 동일한 추상 인터페이스를 공유한다는 것이 취지이다
복합 구조에 적용되는 새로운 오퍼레이션은 비지터(Visitor) 패턴과 함께 사용 가능
컴포지트 패턴은 항상 이터레이터(Iterator) 패턴과 함께 사용된다.
CHAPTER 14 이터레이터
이터레이터(iterator)는 컬렉션 내부 구조를 노출시키지 않고 그것에 저장된 요소(객체)들을 순차적으로 액세스하는 방법을 제공한다.
외부 이터레이터 VS 내부 이터레이터
외부 이터레이터 |
내부 이터레이터 |
클라이언트는 외부 이터레이터를 사용하는 방법을 알아야 하지만, 더 많은 제어 방법을 클라이언트에게 제공한다. 클라이언트가 외부 이터레이터 객체를 생성하고 유지 및 관리한다. 클라이언트는 서로 다른 외부 이터레이터를 사용하여 여러 가지 유형의 순환 처리를 할 수 있다. |
클라이언트는 어떤 외부 이터레이터도 알 필요 없다. 대신에 해당 컬렉션의 특정 인터페이스(한 번에 하나의 요소를 읽거나 각 요소에 메시지를 보낼 수 있는)를 사용할 수 있다. 컬렉션 객체 스스로 자신의 외부 이터레이터 객체를 생성하고 유지 및 관리한다. 클라이언트 코드의 수정없이 컬렉션 객체가 서로 다른 외부 이터레이터를 선택할 수 있다. |
(외부 이터레이터는 for문 돌듯이 하는거고 내부 이터레이터는 file pointer처럼 next같은 함수로 제공되는 것인듯 하다)
이터레이터 패턴은 언제 사용하면 좋을까?
1) 복합 객체의 내부 구조를 노출시키지 않고 그것의 내용을 액세스할 필요가 있을 때.
2) 복합 객체의 내용을 여러 가지 방법으로 순환 처리하고 싶을 때
3) 서로 다른 타입의 복합 객체들의 내용을 순환 처리하기 위해 일관된 인터페이스를 제공할 필요가 있을 때
코코아 터치 프레임워크의 이터레이터 사용하기
애플에서는 'enumerator/enumerate'라는 이름 규칙을 사용하여 이터레이터 패턴을 적용하고 있다.
NSDirectoryEnumerator는 일반적인 컬렉션과는 거리감이 있으며, 이 클래스의 인스턴스는 파일 시스템의 디렉터리 내용을 재귀적으로 순환 처리한다.
컬렉션 클래스들은 해당 컬렉션 타입에 적합한 NSEnumerator의 서브 클래스 인스턴스를 반환하는 메서드들을 정의한다. 모두 nextObject메서드를 호출하여 열거자로부터 객체를 갖고 올 수 있다.
NSEnumerator
iOS 2.0 이후로 NSArray, NSDictionary, NSSet의 열거자로 NSEnumerator을 사용하고 있다.
(열거자 객체를 생성하고 반환하기 위해서 objectEnumerator, keyEnumerator같은 팩토리 메서드를 사용한다.)
NSArray *anArray = ... ;
NSEnumerator *itemEnumerator = [anArray objectEnumerator];
NSString *item;
while (item = [itemEnumerator nextObject]) {
// do. 마지막엔 nil 반환
}
iOS 4.0부터는 블록 기반 열거(Block-Based Enumeration)이라고 추가되었다.
블록 기반 열거
예제
NSArray *anArray = [NSArray arrayWithObject:@"This", @"is", @"a", @"test", nil];
NSString *string = @"test";
[anArray enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {
*stop = YES;
}
}
];
빠른 열거 처리
NSArray * anArray = ...;
for (NSString *item in anArray) {
// doing item
}
CHAPTER 15 비지터
비지터 패턴은 객체 구조의 요소들에 대해 수행되는 오퍼레이션을 나타낸다. 비지터는 자신이 동작하는 요소들의 클래스들을 변경하지 않고 우리가 새로운 오퍼레이션을 정의할 수 있게 해준다.
비지터 패턴은 두 개의 핵심 역활(컴포넌트)가 있다. 하나는 비지터(Visitor)와 그것이 방문하는 요소(Element)이다. 요소는 어떤 객체도 될 수 있지만, 일반적으로는 부분-전체구조(컴포지트 패턴)의 노드가 된다.
비지터 패턴은 언제 사용하면 좋을까?
1) 복잡한 객체 구조에서 서로 다른 인터페이스를 사용하는 서로 다른 많은 객체를 포함하고 있으면서(복합체처럼) 그 객체들의 실체 타입을 기준으로 어떤 오퍼레이션을 수행하고자 할 때
2) 복합 구조에 포함된 객체들에 대해 서로 관련이 없는 여러 오퍼레이션들을 수행할 필요가 있을 때(그 객체들의 클래스에서 그런 오퍼레이션을 넣지 않고) 이 경우 그런 오퍼레이션들을 하나의 비지터 클래스에 함께 유지하면서 그 오퍼레이션들이 필요할 때 사용할 수 있다.
3) 거의 변경이 없는 구조를 정의하는 복합 구조나 클래스에 새로운 오퍼레이션들을 추가할 필요가 있을 때
비지터 패턴의 단점은 비지터가 방문하는 대상 클래스와 강하게 결합되는 것이다. 새로운 기능을 반영하기 위해선 다른 서브 클래스들은 물론 부모 비지터 클래스도 변경될 필요가 있다.
비지터 대신 카테고리를 사용할 수 없을까?
카테고리를 사용할 수 있지만 수정을 하고 확장을 하게 되면 카테고리의 비용이 더 높게 나오기 때문에 비지터 패턴을 사용하는게 낫다.
CHAPTER 16 데코레이터
추가적인 책임(responsibility)을 동적으로 객체에게 첨가한다. 데코레이터는 서브 클래스를 통한 기능 확장에 유연성 있는 대안을 제공한다.
사진과 액자로 예를 들면 사진을 여러 액자에 장식(decorate)하더라도 사진의 내용은 변하지 않는다. 이처럼 객체의 원래 특성을 바꾸지 않고 그 객체에 "뭔가(행동)"을 추가하는 것이다.
비지터 패턴은 언제 사용하면 좋을까?
1) 다른 객체들에게 영향을 주지 않고 개별적인 객체들에게 동적으로 책임을 추가하고자 할 때
2) 클래스의 정의가 감춰져 있거나 그 클래스의 서브 클래스를 만들 수 없는 경우가 있다. 또한 그 클래스의 행동을 확장하려면 많은 수의 서브 클래스가 필요한 경우도 있다. 이처럼 행동 확장이 현실적으로 불가능한 클래스의 행동을 확장하고 싶을 때
3) 클래스의 확장된 책임들이 선택적(생략 가능)이 될 수 있을 때
객체의 "껍데기(외부적)" 변경 vs "알맹이(내부적)" 변경
껍데기 변경 = 데코레이터 |
알맹이 변경 = 스트래티지 |
외부에서 변경한다. 각 노드는 변경을 알지 못한다. |
내부에서 변경한다. 각 노드는 사전 정의된 변경 방법들을 안다. |
ex) UIImage의 이미지 필터 만들기
'소프트웨어 > Objective-C' 카테고리의 다른 글
effective objective-c 2.0 (0) | 2018.01.10 |
---|---|
Objective-C 기초 (outdate된 자료 일부 포함) (0) | 2018.01.02 |