구글


Cocoa의 중요한 디자인 패턴 ▶SW_Coding

iphone App를 개발하기 위해 Cocoa를 스터디 하는 중이다....Cocoa를 사용하면 할수록 정말 객체지향적으로 만들어져 있구나라는 생각이 불쑥 불쑥 든다.. Cocoa에서 사용하는 언어가 Objective-C이고 MS의 MFC의 언어는 C++이다. 다시말하면 두 프레임워크 모두 객체지향적으로 디자인 되어 있지만 몸으로 느낄수 있는 Object Oriented Design에 대한 느낌은 Cocoa가 MFC에 비해 절대 비교 우위에 있다는 것이다.. 그 단적인 예가 바로 Cocoa에서 사용하는 여러 객체의 명칭과 구현 방법일것이다. 

아래 내용은 Cocoa에서 사용하고 있는 기본에 충실한 Object Oriented Design Pattern에 대해 잘 정리 해 놓은 내용을 발췌한것이다. 많은 도움이 되었으면 하는 바램이다.


출처 : http://wiki.osxdev.org/index.php/Cocoa_%EB%94%94%EC%9E%90%EC%9D%B8_%ED%8C%A8%ED%84%B4#Keys


Cocoa Design Patterns

Cocoa 환경의 많은 구조와 기법은 디자인 패턴을 효과적으로 사용하고 있습니다. 추상적인 디자인으로 특정 컨텍스트에서 되풀이하여 발생하는 문제를 해결합니다. 이 챕터는 Cocoa의 디자인 패턴의 주요 구현을 설명하며 모델-뷰-컨트롤러와 객체 모델링에 주로 집중합니다. 주요 목적은 여러분에게 Cocoa의 디자인 패턴을 더 잘 인식시키고, 여러분의 소프트웨어 프로젝트에 이들 패턴의 이점을 도입할 수 있도록 하는 것 입니다.



[편집] What Is a Design Pattern?

디자인 패턴은 특정 컨텍스트에서 반복해서 발생하는 일반적인 문제를 해결하기 위한 디자인의 템플릿입니다. 이것은 소프트웨어 뿐만 아니라 건축 및 공학과 같은 분야에서도 유용한 추상화 도구입니다. 다음 섹션에서는 디자인 패턴이 무엇인지, 왜 이들이 객체 지향 디자인에서 중요한지를 요약하며, 디자인 패턴의 예제를 살펴봅니다.

[편집] A Solution to a Problem in a Context

개발자로서 당신은 이미 객체 지향 프로그래밍의 디자인 패턴의 개념과 친숙할 수 있습니다. 이들은 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides(보통 "네명의 갱"이라고 불리는 이들)의 Design Patterns: Elements of Reusable Object-Oriented Software에서 처음으로 권위있게 설명되고 정리되었습니다. 원래 1994년에 출간되었던 이 책을 따라, 곧 다른 책들과 문서들이 객체지향 시스템에서의 디자인 패턴을 더 폭넓게 탐험하고 설명하게 되었습니다.

디자인 패턴의 간결한 정의는 "컨텍스트에 따른 문제의 해결책"입니다. 이 문장을 거꾸로 진행하며 살펴봅시다. 컨텍스트는 패턴이 적용되는 자주 발생하는 상황입니다. 문제는 이 컨텍스트와 컨텍스트에 해당하는 제약조건하에서 이루고자하는 목표입니다. 해결책은 우리가 찾고자 하는 것입니다. 바로 컨텍스트에서 목표를 달성하고 제약조건을 해결하는 일반적인 디자인입니다.

디자인 패턴은 오랫동안 효과적이라고 증명된 구체적인 디자인 구조의 핵심적인 측면을 추상화합니다. 이 패턴은 이름을 가지고 있으며, 패턴에 참여하는 클래스와 객체, 뿐만 아니라 그들의 책임과 협력도 지정합니다. 패턴이 적응 될 수 있는 상황과 패턴의 결과(비용과 효과)까지 설명합니다. 디자인 패턴은 특정 디자인의 템플릿 혹은 가이드와 같습니다. 어떻게 보면, 구체적인 디자인은 패턴의 인스턴스라고 볼 수 있습니다. 디자인 패턴은 절대적이지 않습니다. 그들을 적응할 수 있는 방식에 융통성이 있으며, 종종 프로그래밍 언어와 존재하고 있는 아키텍쳐가 패턴이 적용되는 방식을 결정합니다.

디자인의 테마나 원칙도 디자인 패턴에 영향을 미칩니다. 이런 디자인 원칙은 "변화하는 시스템 구조의 측면을 캡슐화합니다"와 "구현 대신 인터페이스에 프로그래밍하십시오"와 같이 객체지향 시스템의 구축에 있어 널리 알려진 방침입니다. 이들은 중요한 교훈을 가지고 있습니다. 예를 들어, 변화하는 시스템의 일부분을 분리시켜 캡슐화 시킨다면, 그들은 시스템의 다른 부분과 독립적으로 변화할 수 있습니다. 특히 특정 구현에 묶여있지 않은 인터페이스를 정의할때 유용합니다. 후에 이런 변화하는 부분을 변경하거나 확장하더라도 시스템의 다른 부분에 영향을 미치지 않습니다. 각 부분간의 의존성을 제거하고 커플링을 줄여서 결과적으로 시스템이 더 유연해지고 변화를 잘 다루게 됩니다.

이런 혜택은 디자인 패턴을 소프트웨어 제작시 고려해볼만한 중요한 사항으로 만들어 줍니다. 여러분의 프로그램에 디자인 패턴을 찾고 적용하고 사용한다면, 그 프로그램 및 프로그램을 구성하는 객체와 클래스는 더 높은 재사용성, 확장성을 갖게되며 미래에 요구되는 사항을 더 잘 반응할 수 있게 됩니다. 게다가, 디자인 패턴에 기반한 프로그램들은 동일한 목적을 달성하는데 더 적은 코드를 요구하게 되어 일반적으로 더 우아하고 효율적입니다.



[편집] An Example: The Command Pattern

네명의 갱이 쓴 그 책의 대부분은 디자인 패턴의 카탈로그로 이루어져 있습니다. 이 책은 범주(클래스 혹은 객체)와 목적(생성, 구조, 행동)으로 패턴을 카탈로그에 분류합니다. 카탈로그의 각 엔트리는 디자인 패턴의 의도, 동기, 적용가능성, 구조, 참여자, 협력, 결과, 구현을 다루고 있습니다. 이들 엔트리중의 하나는 커맨드 패턴(객체-행동 패턴)입니다.

커맨드 패턴의 의도는 "요청을 객체로 캡슐화하여 사용자가 각기 다른 요청, 큐, 로그 요청등을 가지고 잇는 클라이언트를 파라미터화 할수 있도록 하고 취소(undo) 처리를 지원한다"라고 언급되어 있습니다. 이 패턴은 메시지를 보내는 객체와 이 메시지를 받고 평가하는 객체를 구분합니다. 메시지의 발신자(클라이언트)는 특정 수신자에게 보내지는 하나 혹은 그 이상의 액션을 묶어서 요청을 캡슐화합니다. 캡슐화된 메시지는 객체 사이에서 건네져서 큐에 놓여지거나 후의 호출에 대비해 저장되어지고, 메시지 파라미터나 수신자를 바꾸기 위해 동적으로 수정됩니다. Figure 4-1은 이 패턴의 구조도 입니다.

Figure 4-1 커맨드 패턴의 구조도 


Cocoa에 친숙한 개발자라면 커맨드 패턴의 이 오버뷰 스케치가 무언가 떠오르게 할 것입니다. 이 패턴은 Foundation 프레임웍에서 메시지를 캡슐화하는 클래스인 NSInvocation을 완벽히 묘사하고 있습니다. 패턴의 의도에서 언급했듯이 목적 중의 하나는 작업을 취소(undo)할수 있도록 하는 것입니다. Cocoa 디자인에서 작업 취소(undo)관리를 위해 객체와 프로세스간 통신을 위한 아키텍쳐인 분산 객체의 호출이 사용됩니다. 커맨드 패턴은 또한 (완벽하지는 않지만) Cocoa에서 사용자가 컨트롤들을 활성화 시킬때 보내지는 메시지의 타겟과 액션을 캡슐화하는 타겟-액션 기법을 설명합니다.

Cocoa는 프레임웍 클래스와 언어, 런타임에서 이미 카탈로그로 정리된 디자인 패턴을 구현해놓고 있습니다. (이 구현은 “How Cocoa Adapts Design Patterns”에 설명되어 있습니다.) 많은 개발 요구사항을 디자인 패턴의 바로 쓸수 있는 적용을 사용하여 충족시킬 수 있습니다. 혹은 여러분의 문제와 컨텍스트가 새로운 패턴 기반의 디자인을 요구한다고 볼 수도 있습니다. 패턴에서 중요한 것은 소프트웨어를 개발할 때를 알고 적절한 때 디자인을 사용하는 것입니다.

[편집] How Cocoa Adapts Design Patterns

Cocoa 전반에 걸쳐 디자인 패턴의 적용을 찾을 수 있습니다. 패턴에 기반한 기법과 아키텍쳐는 Cocoa 프레임웍, Objective-C 런타임과 언어에서 쉽게 찾을 수 있습니다. Cocoa는 종종 패턴에 자신만의 특징을 패턴에 적용하는데, 그 디자인은 언어의 능력이나 존재하는 아키텍쳐와 같은 요소에 영향을 받습니다.

이 섹션에는 Design Patterns: Elements of Reusable Object-Oriented Software에 카탈로그화 되어있는 상당수의 디자인 패턴 엔트리를 포함하고 있습니다. 각 엔트리는 패턴을 요약하며 해당 패턴의 Cocoa 구현을 설명합니다. Cocoa가 구현하고 있는 패턴만이 목록에 나오며, 이후에 나오는 섹션의 각 패턴에 대한 이야기는 특정한 Cocoa 컨텍스트에 해당합니다. 이들 패턴과 친숙해져서 Cocoa 소프트웨어 개발에 유용하게 사용할 것을 추천합니다.

Cocoa의 디자인 패턴 구현은 다양한 형태로 되어있습니다. 다음 섹션에 설명되고 있는 프로토콜, 카테고리와 같은 디자인은 Objective-C 언어의 기능입니다. 다른 경우, "패턴의 인스턴스"는 하나의 클래스나 관련된 클래스 그룹 (예를 들어, 클래스 클러스터나 싱글톤 클래스)에 구현되어 있습니다. 또 다른 경우 패턴 적용은 리스폰더 체인과 같이 주 프레임웍 아키텍쳐에 되어 있습니다. 패턴 기반 기법의 일부는 거의 "공짜로" 얻을 수 있지만 다른 일부는 사용자가 약간의 작업을 해야 합니다. 비록 Cocoa가 패턴을 구현하고 있지 않은 경우라도 상황이 필요로 한다면 직접 구현하는 것이 좋습니다. 예를 들어, 종종 객체 컴포지션(데코레이터 패턴)은 서브클래스로 클래스 행동을 확장시키는 것보다 더 나은 기법입니다.

모델-뷰-컨트롤러(MVC)와 객체 모델링, 이 두개의 디자인 패턴은 아래에서 다루지 않습니다. MVC는 복합 혹은 집단 패턴으로 몇몇 카탈로그 패턴에 기반하고 있습니다. 객체 모델링은 네명의 갱의 카탈로그에 해당하는 내용이 없고 대신 관계 데이터베이스의 도메인에 그 기반을 두고 있습니다. 하지만 MVC와 객체 모델링은 아마 Cocoa에서 가장 중요하고 깊이 스며들어있는 디자인 패턴 혹은 메타포이며 상당부분 상호 연관된 패턴입니다. 이들은 바인딩, 작업 취소 관리, 스크립팅, 도큐먼트 아키텍쳐와 같은 몇몇 기술의 디자인에 핵심적인 역할을 합니다. 이들 패턴에 대해 더 알길 원한다면 “The Model-View-Controller Design Pattern”“Object Modeling”를 읽으십시오.

[편집] Abstract Factory

관련된 혹은 의존적인 객체의 집단을 그들의 구상 클래스를 지정하지 않고 생성하는 인터페이스를 제공합니다. 클라이언트는 이 팩토리로부터 얻어진 특정 구상 객체의 어느 것과도 분리되어 있습니다.

[편집] Class Cluster

클래스 클러스터는 다수의 프라이빗, 구상 서브클래스를 하나의 퍼블릭, 추상 슈퍼 클래스 아래로 그룹짓는 아키텍쳐입니다. 추상 슈퍼클래스는 자신의 서브클래스의 인스턴스를 만들 메소드를 선언합니다. 슈퍼클래스는 불려진 생성 메소드에 따라 적절한 구상 서브클래스의 객체를 반환합니다. 각 객체는 다른 프라이빗 구상 서브클래스에 속할 수 있습니다.

Cocoa는 클래스 클러스터를 상황에 따라 데이터의 저장이 변할 수 있는 객체의 생성에 제한합니다. Foundation 프레임웍은 NSString, NSData, NSDictionary, NSSet, NSArray 객체를 위한 클래스 클러스터를 가지고 있습니다. 퍼블릭 슈퍼클래스는 언급한 이들 수정 불가능한 클래스 뿐만 아니라 해당하는 수정가능한 클래스인 NSMutableString, NSMutableData, NSMutableDictionary, NSMutableSet, NSMutableArray를 포함합니다.

[편집] Uses and Limitations

클러스터로 대표되는 타입의 수정가능한 객체나 수정 불가능한 객체를 생성하고자 할때, 클래스 클러스터의 퍼블릭 클래스중 하나를 사용합니다. 클래스 클러스터를 사용하면 단순성과 확장성 사이에 트레이드오프가 있습니다. 클래스 클러스터는 인터페이스를 하나의 클래스로 단순화시켜 클래스의 학습과 사용을 쉽게 만들어줍니다. 그러나, 일반적으로 클래스 클러스터의 추상 클래스로부터 커스텀 서브클래스를 만들기는 더 어렵습니다.


더 읽을거리: “Class Clusters”에서 Cocoa의 클래스 클러스터에 대한 더 상세한 정보를 제공하고 있습니다.




[편집] Adapter

클래스의 인터페이스를 클라이언트가 기대하는 다른 인터페이스로 전환합니다. 어댑터는 다른 방식으로는 호환되지 않는 인터페이스를 함께 작업할 수 있도록 합니다. 클라이언트를 타겟 객체의 클래스로부터 분리시켜줍니다.

[편집] Protocols

프로토콜은 언어수준(Objective-C)의 기능으로 어댑터 패턴의 인스턴스인 인터페이스를 정의할 수 있도록 해줍니다. (자바에서 "interface"는 "protocol"과 동의어 입니다.) 만일 클라이언트 객체가 다른 객체와 통신하길 원하지만 그들의 인터페이스가 호환되지 않아 어렵다면 프로토콜을 정의할 수 있습니다. 프로토콜은 클래스에 연관되지 않은 메소드 선언의 시리즈입니다. 다른 객체의 클래스는 공식적으로 그 프로토콜을 도입하여 그 프로토콜의 모든 메소드를 구현하는 것으로 그 프로토콜을 준수하게 됩니다. 클라이언트 객체는 그 후에 그 다른 객체에 프로토콜 인터페이스를 통해 메시지를 보낼 수 있게 됩니다.

프로토콜은 메소드 선언의 모음을 클래스 계층에 독립적으로 되게 합니다. 클래스 상속 뿐만 아니라 프로토콜의 준수에 기반하여 객체를 그룹지을 수 있도록 합니다. NSObject 메소드인 conformsToProtocol:을 이용하면 객체가 프로토콜에 준수하는지를 확인할 수 있습니다.

공식적인 프로토콜 외에도 Cocoa는 비공식적인 프로토콜도 갖추고 있습니다. 이런 종류의 프로토콜은 NSObject 클래스에 있는 카테고리인데, 어느 객체든 그 카테고리안의 메소드의 잠재적인 구현자가 될 수 있게 합니다. ("Categories" 를 보십시오.) 비공식 프로토콜의 메소드는 선택적으로 구현될 수 있습니다. 비공식 프로토콜은 델리게이션 기법의 구현의 일부입니다. ("Delegation"을 보십시오.)

프로토콜의 디자인이 어댑터 패턴과 완벽히 들어맞지는 않습니다. 그러나 이를 이용해 다른 방식으로는 호환되지않는 인터페이스인 클래스들을 함께 사용할 수 있도록 합니다.

[편집] Uses and Limitations

프로토콜을 사용하여 주로 계층적으로 관련없는 클래스들 통신하길 원하는 경우에 준수하도록 인터페이스를 선언합니다. 그러나 프로토콜을 사용하여 객체의 클래스를 숨기며 객체의 인터페이스를 선언할 수도 있습니다. Cocoa 프레임웍은 많은 공식 프로토콜을 포함하고 있으며 이들 프로토콜들은 커스텀 클래스들이 특정 목적으로 그들과 통신하는 것을 가능하게 해줍니다. 예를 들어, Foundation 프레임웍에 포함된 NSObject, NSCopying, NSCoding 프로토콜은 모두 다 중요합니다. Application Kit 프로토콜은 NSDraggingInfo, NSTextInput, NSChangeSpelling을 포함합니다.

공식적인 프로토콜은 이를 도입한 클래스가 선언된 메소드를 모두 구현할 것을 요구합니다. 이들은 또한 연약해서, 프로토콜을 정의한 후 다른 클래스에 제공한 후에 변화를 가한다면, 이들 클래스를 망가뜨릴 수도 있습니다.


더 읽을거리 : 공식적인 프로토콜에 대한 더 많은 정보는 The Objective-C 2.0 Programming LanguageProtocols에서 찾을 수 있습니다.



[편집] Chain of Responsibility

하나 이상의 객체가 그 요청을 다룰 수 있는 기회를 주는 것으로 요청을 보낸 수신자와 그 송신자의 결합을 피하십시오. 수신 객체를 연결짓고 요청을 그 연결고리를 따라 그것을 처리할 수 있는 객체에 도달할 때까지 요청을 전달합니다. 각각의 객체는 요청을 처리하거나 연결고리의 다음 객체에 그 요청을 건네줍니다.

[편집] Responder Chain

Application Kit 프레임웍은 리스폰더 체인이라고 알려진 아키텍쳐를 포함하고 있습니다. 이 연결고리는 (NSResponder로부터 상속받은 객체인) 리스폰더 객체의 시리즈로 구성되어 있습니다. 이 리스폰더 객체들은 마우스클릭과 같은 이벤트나 액션 메시지를 넘겨받게 되고 (보통) 결국 처리합니다. 만일 주어진 리스폰더 객체가 특정 메시지를 처리하지 않는다면, 그 메시지를 연결 고리안의 다음 리스폰더로 넘깁니다. 연결고리안의 리스폰더 객체의 순서는 보통 뷰 계층에 의해 결정되어 저수준에서부터 고수준으로 점차 올라가게되어 최상에는 뷰 계층을 처리하는 윈도우 객체나 윈도우 객체, 혹은 글로벌 애플리케이션 객체의 딜리게이트에 이르게 됩니다. 이벤트와 액션 메시지가 리스폰더 체인을 올라가는 길은 다릅니다. 애플리케이션은 많은 윈도우(혹은 뷰의 지역 계층)을 가질 수 있기 때문에 많은 리스폰더 체인을 가질 수 있지만, 오직 현재의 활성화 윈도우와 관련된 하나의 리스폰더 체인만이 한번에 활성화 될 수 있습니다.

리스폰더의 비슷한 체인이 애플리케이션의 에러 처리를 위해서도 존재합니다.

뷰 계층의 디자인은 리스폰더 체인과 상당히 관련되어 있으며 컴포지트 패턴을 도입하고 있습니다. ("Composite") 컨트롤 객체로부터 발생되는 액션 메시지는 타겟-액션 기법에 기반하고 있으며 이는 커맨드 패턴의 인스턴스입니다. ("Command")

[편집] Uses and Limitations

인터페이스 빌더를 이용하거나 프로그래밍을 통해 유저 인터페이스를 구축하려 할 때, 하나 혹은 그 이상의 리스폰더 체인을 바로 얻게 됩니다. 리스폰더 체인은 뷰 계층과 협력하고 있으며, 윈도우의 컨텐트 뷰의 서브뷰인 뷰 객체를 만들면 자동으로 얻게 됩니다. 만일 뷰 계층에 커스텀 뷰를 추가했다면, 리스폰더 체인의 일부가 됩니다. 적절한 NSResponder 메소드를 구현했다면, 이벤트와 액션 메시지를 받고 처리할 수 있게 됩니다. 윈도우 객체, 글로벌 애플리케이션 객체인 NSApp의 델리게이트인 커스텀 객체 역시 이들 메시지를 받고 처리할 수 있습니다.

프로그래밍을 통해 커스텀 리스폰더를 리스폰더 체인에 끼워 넣을 수 있으며, 리스폰더의 순서를 프로그래밍으로 다룰 수 있습니다.

더 읽을거리: 이벤트와 액션 메시지를 위한 리스폰더 체인과 에러를 처리를 위한 리스폰더 체인은 Cocoa Event-Handling GuideError Handling Programming Guide For Cocoa에 설명되어 있습니다. 이 문서는 뷰계층에 대해 "Composite" 패턴 섹션에서 요약하고 있으며, "The Core Application Architecture"에서 더 상세히 설명하고 있습니다.



[편집] Command

요청을 객체로 캡슐화하여 다른 요청, 큐, 로그 요청과 함께 클라이언트를 파라미터화 할 수 있으며 작업 취소를 지원할 수 있습니다. 요청 객체는 특정 수신자의 하나 혹은 그 이상의 액션을 묶습니다. 커맨드 패턴은 요청하는 객체와 요청을 받는 객체, 요청을 수행하는 객체를 구분합니다.

[편집] Invocation Objects

NSInvocation 클래스의 인스턴스는 Objective-C 메시지를 캡슐화합니다. 호출 객체는 타겟 객체, 메소드 셀렉터, 메소드 인자를 포함하고 있습니다. 호출 객체에 의해 디스패치되는 메시지의 인자 뿐만 아니라 타겟도 동적으로 변경할 수 있습니다. 일단 호출이 수행되면, 객체로부터 반환되는 값을 얻을 수 있습니다. 하나의 호출 객체로 반복해서 메시지를 타겟과 인자를 변환시키며 호출할 수 있습니다.

NSInvocation 객체의 생성은 NSMethodSignature 객체를 요구합니다. NSMenthodSignature 객체는 메소드의 인자와 반환 값의 타입 정보를 캡슐화합니다. NSMethodSignature 객체는 결국 메소드 셀렉터로부터 만들어집니다. NSInvocation의 구현으로 Objective-C 런타임의 기능을 사용가능하게 합니다.

[편집] Uses and Limitations

NSInvocation 객체는 분산 객체, 작업 취소(undo) 관리, 메시지 포워딩, 타이머의 프로그래밍 인터페이스의 일부입니다. 또한 메시지를 받는 객체와 메시지를 보내는 객체를 분리시킬 필요가 있는 비슷한 컨텍스트에서도 호출 객체를 사용할 수 있습니다.

분산 객체는 프로세스간 커뮤니케이션을 위한 기술입니다. 분산 객체에 대한 더 많은 정보는 "Proxy"에서 찾을 수 있습니다.

더 읽을 거리: NSInvocation 클래스 레퍼런스 문서에 호출 객체에 대한 더 상세한 정보가 있습니다. 또한, 관련된 기술들에 대한 정보는 다음 문서에서 찾아보십시오. Distributed

Objects Programming Topics, Undo Architecture, Timers, The Objective-C

2.0 Programming Language 의 “The Runtime System“.


[편집] Target-Action

타겟-액션 기법은 (버튼, 슬라이더, 텍스트필드와 같은)컨트롤 객체가 메시지를 해석하고 애플리케이션에 특정한 명령으로 처리할 수 있는 다른 객체에 메시지를 보낼 수 있도록 합니다. 받는 객체, 즉 타겟은, 보통 커스텀 컨트롤러 객체입니다. 액션 메시지라 이름지어진 메시지는 메소드의 유니크 런타임 구분자인 셀렉터에 의해 결정되어집니다. 일반적으로 컨트롤이 소유하고 있는 셀 객체가 타겟과 액션을 캡슐화합니다. 컨트롤은 유저가 클릭하거나 해서 활성화시킬 때 메시지를 보냅니다. (메뉴 아이템도 타겟과 액션을 캡슐화하고 유저가 선택했을 때 액션 메시지를 보냅니다.) 타겟-액션 기법은 (메소드 시그네쳐가 아닌)셀렉터에 기반해 작업할 수 있으며 액션 메소드의 시그네쳐가 관례적으로 항상 동일합니다.

[편집] Uses and Limitations

Interface Builder 애플리케이션을 사용해 프로그램의 유저 인터페이스를 구축하려 할 때 컨트롤의 액션과 타겟을 지정할 수 있습니다. 이렇게하여 컨트롤 자체를 위한 코드를 작성할 필요없이 컨트롤이 커스텀 비헤이비어를 시작하도록 할 수 있습니다. 액션 셀렉터와 타겟 커넥션은 nib 파일에 저장되고 nib 파일이 불려들여질때 복원됩니다. 컨트롤이나 그 셀에 setTarget:, setAction: 메시지를 보내는 것으로 타겟과 액션을 동적으로 바꿀 수 있습니다.

타겟-액션은 종종 커스텀 컨트롤러 객체가 데이터를 유저 인터페이스에서 모델 객체로 전송하거나 모델 객체의 데이터를 표시하도록 하는데 사용되었습니다. Cocoa 바인딩 기술은 이런 용도로 타겟-액션 기술을 사용할 필요를 없애주었습니다. Cocoa Bindings Programming Topics에서 이 기술에 대해 더 알 수 있습니다.

Application Kit의 컨트롤과 셀은 그들의 타겟을 리테인하지 않습니다. "Ownership of Delegates, Observers, and Targets"에서 추가적인 정보를 찾을 수 있습니다.

더 읽을거리: "The Target-Action Mechanism"에서 추가적인 정보를 찾을 수 있습니다.


[편집] Composite

부분-전체 계층을 표현하기 위해 트리 구조에 관련된 객체들을 구성합니다. Composite는 클라이언트가 각각의 객체와 객체의 컴포지션을 유일하게 처리하도록 합니다.

Composite 패턴은 모델-뷰-컨트롤러 종합 패턴의 일부입니다.

[편집] View Hierarchy

윈도우의 뷰(NSView 객체)는 내부적으로 뷰 계층으로 구조되어 있습니다. 이 계층의 루트에는 윈도우(NSWindow 객체)와 윈도우의 컨텐트 사각을 채우는 투명한 컨텐트 뷰가 있습니다. 뷰는 컨텐트 뷰에 더해져 그 서브뷰가 되며 자신들에게 더해진 뷰들의 슈퍼뷰가 됩니다. 뷰는 단 하나의 슈퍼뷰만 가질 수 있으며 서브뷰는 전혀 없거나 다수를 가질 수 있습니다. 시각적으로 이 구조를 포함으로 이해할 수 있습니다. 슈퍼뷰가 서브뷰를 포함합니다. Figure 4-2 뷰 계층의 구조적, 계층적 측면을 보여줍니다.

Figure 4-2 구조적, 시각적 뷰 계층도 

 

뷰 계층은 구조적인 아키텍쳐로 드로잉과 이벤트 핸들링에서 일정한 역할을 합니다. 뷰는 프레임과 바운드, 이 두개의 바운딩 사각형을 가지고 있습니다. 이들은 뷰 안에서 그래픽 작업이 어떻게 일어나는지에 영향을 미칩니다. 프레임은 외부 바운더리 입니다. 프레임은 뷰가 그 슈퍼뷰의 좌표 시스템에서 어디에 위치하는지를 지정하며, 사이즈를 정의하고, 드로잉을 그 경계에 클리핑합니다. 바운드는 내부 바운딩 사각형으로 뷰가 자기 자신을 그리는 표면의 내부 좌표 시스템을 정의합니다.

윈도우 시스템이 윈도우에게 디스플레이를 준비하라고 요청하면, 슈퍼뷰는 서브뷰를 렌더하기 이전에 자기자신을 렌더하라고 요청받습니다. (뷰에게 자기자신을 다시 그리라고 하는 메시지와 같은)메시지를 뷰에 보내면 메시지는 서브뷰에게 전달됩니다. 따라서 뷰 계층의 가지를 하나의 통합된 뷰로 다룰 수 있습니다.

뷰 계층은 리스폰더 체인에서 이벤트와 액션 메시지를 처리하는데도 사용됩니다. 리스폰더 체인의 요약은 Chain of Responsibility 패턴에서 찾을 수 있습니다. ("Chain of Responsibility")

[편집] Uses and Limitations

프로그래밍을 통하거나 Interface Builder를 사용하거나 상관없이 뷰를 다른 뷰에 추가할 때는 언제나 뷰 계층을 생성하고 수정할 수 있습니다. Application Kit 프레임웍은 자동으로 뷰 계층에 관련된 모든 관계를 처리해줍니다.

더 읽을거리: 뷰 계층에 대해 더 알기 원한다면. 이 문서의 "The View Hierarchy"를 읽으십시오. Cocoa Drawing Guide 에서도 뷰 계층을 다루고 있습니다.


[편집] Decorator

객체에 동적으로 추가적인 책임을 더하십시오. 데코레이터는 서브클래스를 대신해 유연하게 기능을 확장하는데 사용됩니다. 서브클래싱처럼, 데코레이터 패턴을 적용하면 이미 존재하는 코드를 수정하지 않고 새로운 비헤이비어를 추가시킬 수 있습니다. 데코레이터는 비헤이비어를 확장시키려하는 클래스의 객체를 감쌉니다. 그들은 감싸는 객체와 동일한 인터페이스를 구현하고 작업을 딜리게이트 하기 전이나 후에 자신만의 비헤이비어를 그 객체에 추가합니다. 데코레이터 패턴은 클래스가 확장은 가능하지만 수정은 불가능해야한다는 디자인 원칙을 표현합니다.

[편집] General Comments

데코레이터는 여러분의 코드에 하도록 추천되는 객체 컴포지션을 위한 패턴입니다. ("When to Make a Subclass"를 보십시오) 그러나 Cocoa는 이 패턴에 기반한 그 자신의 클래스와 기법들을 제공합니다. (아래의 섹션에서 논의됩니다.) 이들 구현에서 인터페이스 공유를 위해 다른 기법을 사용하지만 확장하는 객체가 감싼 객체의 인터페이스를 완전히 복사하지는 않습니다.

Cocoa는 데코레이터 패턴을 NSAttributedString, NSScrollView, NSTableView를 포함한 몇몇 클래스의 구현에서 사용합니다. 뒤의 두 클래스들은 다른 객체 클래스의 단순한 객체를 그룹짓고 그들의 상호작용을 조정하는 복합 뷰의 예입니다.

[편집] Delegation

델리게이션은 호스트 객체가 "약한" 레퍼런스를 다른 객체(델리게이트)에 임베드시키고 정기적으로 작업을 위한 입력이 필요할 때 델리게이트에 메시지를 보내는 기법입니다.("약한"이라는 말은 리테인하지 않은 단순한 포인터 레퍼런스를 의미합니다) 호스트객체는 일반적으로 (NSWindow나 NSXMLParser 객체와 같이 무엇인가 달성하려 하지만 일반적인 방식으로 밖에 할 수 없는) "바로 꺼내 쓸수 있는" 프레임웍 객체입니다. 델리게이트는 거의 항상 커스텀 클래스의 인스턴스인데, 호스트 객체와 함께 작동하여 작업의 특정 지점에서 프로그램에 특정한 행동을 제공합니다. (Figure 4-3을 보십시오) 따라서 델리게이션은 서브클래싱할 필요없이 다른 객체의 행동을 수정하거나 호가장할 수 있게 합니다.

Figure 4-3 델리게이트에 메시지를 보내는 프레임웍 객체 

 

단순하게 보면, 한 객체가 다른 객체에 작업을 위임하는 델리게이션은 객체 지향 프로그래밍에서 흔한 기술입니다. 그러나 Cocoa는 델리게이션을 아주 독특한 방식으로 구현합니다. 호스트 클래스는 비공식 프로토콜(NSObject의 카테고리)을 사용하여 델리게이트 객체가 구현하기로 선택한 인터페이스를 정의합니다. 델리게이트는 공식프로토콜과 달리 프로토콜의 모든 메소드를 구현할 필요는 없습니다. 호스트 객체는 델리게이트에 메시지를 보내려 시도하기 전에 (respondsToSelector: 메시지를 이용해) 그 객체가 메소드를 구현해놓았는지 확인하여 런타임 익셉션을 피합니다. 공식, 비공식 프로토콜에 대한 더 많은 것은 "Protocols"에서 찾을 수 있습니다.

Cocoa 프레임웍의 몇몇 클래스 또한 그들의 데이터 소스에 메시지를 보냅니다. 데이터 소스는 그 목적이 호스트 객체에 데이터를 제공하여 브라우저, 테이블 뷰, 혹은 비슷한 유저-인터페이스 뷰를 채우는 것이 목적이라는 것을 제외하면 모든 측면에서 델리게이트와 똑같습니다. 또한 데이터 소스는 델리게이트와 달리 프로토콜의 몇몇 메소드를 구현해야할수도 있습니다.

델리게이션은 데코레이터 패턴의 엄격한 구현이 아닙니다. 호스트(위임을 하는) 객체는 확장을 원하는 클래스의 인스턴스를 감싸지(wrap) 않습니다. 사실, 델리게이트는 위임하는 프레임웍 클래스의 행동을 특화시킨다는 점에서 반대의 경우라 할수 있습니다. 프레임웍 클래스에 의해 선언된 델리게이션 메소드를 제외하고는 인터페이스의 공유도 없습니다.

Cocoa의 델리게이션은 템플릿 메소드 패턴의 일부입니다. ("Template Method")

[편집] Uses and Limitations

델리게이션은 Cocoa 프레임웍에 흔한 디자인입니다. NSAppilcation, NSWindow, NSView의 몇몇 서브클래스들을 포함한 Application Kit 프레임웍의 많은 클래스가 델리게이트에 메시지를 보냅니다. NSXMLParser, NSStream과 같은 몇몇 Foundation 프레임웍도 델리게이트를 유지합니다. 델리게이션 메소드가 원하는 목적을 달성하도록 하지 않더라도 클래스를 서브클래스하는 것 대신 항상 클래스의 델리게이션 기법을 사용해야만 합니다.

동적으로 델리게이트를 바꿀 수 있지만 한번에 단 하나의 객체만 델리게이트가 될 수 있습니다. 따라서 다수의 객체가 특정 프로그램의 이벤트를 동시에 통지받기를 원한다면 델리게이션을 사용해서는 안됩니다. 그러나 이런 목적으로 노티피케이션 기법을 사용할 수 있습니다. 델리게이션이 프레임웍 클래스에 의해 선언된 노티피케이션 메소드를 하나 혹은 그 이상을 구현하기만 하면 델리게이트는 자동으로 위임한 프레임웍으로부터 통지를 받게 됩니다. 노티피케이션에 대한 이야기는 옵저버 패턴에서 찾을 수 있습니다. ("Observer")

Application Kit에서 위임하는 객체는 그들의 델리게이트나 데이터 소스를 리테인하지 않습니다. 더 많은 정보는 "OwnerShip of Delegates, Observers, and Targets"에서 찾을 수 있습니다.


더 읽을거리: 델리게이션에 대한 추가적인 정보는 "Delegates and Data Sources"에서 찾을 수 있습니다.



[편집] Categories

Objective-C 언어의 기능인 카테고리는 서브클래스할 필요 없이 클래스에 메소드(인터페이스와 구현)를 추가하도록 해줍니다. 프로그램의 범위 내에서 클래스 원래의 메소드와 카테고리로 추가한 메소드간의 런타임 차이는 없습니다. 클래스 종류의 카테고리의 메소드는 클래스의 모든 서브클래스에 의해 상속됩니다.

델리게이션과 마찬가지로 카테고리는 데코레이터 패턴의 엄격한 적용이 아니기에 원래의 의도는 충족시키지만 그 의도와는 다른 방법으로 구현하고 있습니다. 카테고리로 추가된 행동은 컴파일-타임 아티팩트이며 동적으로 획득되는 것은 아닙니다. 게다가 카테고리는 확장되는 클래스의 인스턴스를 캡슐화하지 않습니다.

[편집] Uses and Limitations

Cocoa 프레임웍은 많은 카테코리를 정의합니다. 그들의 대부분은 비공식 프로토콜입니다. ("Protocols"에 요약되어 있습니다) 종종 그들은 카테고리를 사용해 관련된 메소드를 그룹짓습니다. 여러분은 카테고리를 이용해 서브클래싱 하지 않고 클래스를 확장하거나 관련된 메소드를 그룹지을 수 있습니다. 그러나 다음의 사항을 주의해야 합니다.

  • 클래스에 인스턴스 변수를 추가할 수 없습니다.
  • 클래스에 이미 존재하는 메소드를 오버라이드하면, 응용프로그램이 예측하지 못한 방식으로 행동할 수 있습니다.


더 읽을거리: The Objective-C 2.0 Programming Language의 "Defining a Class"에서 카테고리에 대한 더 많은 정보를 찾을 수 있습니다.



[편집] Facade

하부 시스템의 인터페이스 모음에 통일된 인터페이스를 제공합니다. 파사드는 고수준의 인터페이스를 정의하여 복잡성을 줄이고 하부 시스템간 통신과 의존성을 숨겨 하부 시스템을 더 쉽게 사용하도록 만들어줍니다.

[편집] NSImage

NSImage 클래스는 (JPEG, PNG, TIFF 포맷과 같은)비트맵 기반 혹은 (EPS나 PDF포맷과 같은) 벡터기반의 이미지를 로드하고 사용하는 통일된 인터페이스를 제공합니다. NSImage는 동일한 이미지를 하나 이상의 표현으로 가지고 있을 수 있습니다. 각각의 표현은 NSImageRep 객체입니다. NSImage는 주어진 디스플레이 장치와 데이터의 특정 타입에 적절한 표현의 선택을 자동화합니다. 또한 이미지 처리와 선택의 상세한 부분을 숨겨 클라이언트가 많은 다른 하부 표현을 호환하여 사용하도록 합니다.

[편집] Uses and Limitations

NSImage가 한 이미지의 여러 다른 표현을 지원하기 때문에 몇몇의 요청된 애트리뷰트는 적용되지 않을 수 있습니다. 예를 들어, 하부의 이미지 표현이 벡터 기반이고 장치 독립적이라면 이미지의 픽셀의 색을 물어볼 수 없습니다.

노트: Cocoa Drawings Guide 에서 NSImage와 이미지 표현에 대해 더 찾을 수 있습니다.


[편집] Iterator

객체 모음(콜렉션)의 개체를 하부 표현을 노출시키지 않고 순차적으로 접근할 수 있는 방법을 제공합니다. 이터레이터 패턴은 콜렉션의 개체에 접근하고 옮겨다니는 기능을 제공할 책임을 콜렉션으로부터 이터레이터 객체로 옮겨줍니다. 이터레이터는 콜렉션 개체에 접근할 인터페이스를 정의하며 현재 개체를 추적합니다. 다른 이동 정책에 따라 다른 이터레이터가 사용될 수 있습니다.

[편집] NSEnumerator

Foundation 프레임웍의 NSEnumerator 클래스가 이터레이터 패턴을 구현합니다. 추상 클래스인 NSEnumerator 클래스의 프라이빗, 구상 서브클래스는 다양한 타입(배열, 셋, 딕셔너리(밸류와 키))의 콜렉션을 순차적으로 이동하며 콜랙션의 객체를 클라이언트에게 반환합니다.

NSDictionaryEnumerator는 약간 관련된 클래스입니다. 이 클래스의 인스턴스는 반복해서 파일시스템안의 디렉토리의 컨텐츠를 하나하나 열거합니다.

[편집] Uses and Limitations

NSArray, NSSet, NSDictionary와 같은 콜렉션은 콜렉션의 타입에 적절한 열거자(enumerator)를 반환하는 메소드를 포함합니다. 모든 열거자는 동일한 방식으로 작동합니다. 루프에서 nextObject 메소드를 열거자 객체에 보내고 콜렉션에서 다음 객체 대신 nil을 반환할 때 루프를 빠져나옵니다.

[편집] Mediator

객체들의 집합이 상호작용하는 방법을 캡슐화하는 객체를 정의합니다. 매개자(Mediator)는 객체들이 서로 명시적으로 부르지 않게 하여 약한 결합을 촉진시키며 사용자가 이들의 상호작용을 독립적으로 바꿀 수 있게 합니다. 따라서 이들 객체가 재사용하기 더 좋아집니다.

매개자 객체는 시스템 안의 객체간 복잡한 통신과 컨트롤 로직을 중앙화합니다. 이들 객체들은 자신의 상태가 변화할 때 매개자 객체에게 말하여 매개자의 요청에 반응합니다.

[편집] Controller Classes

모델-뷰-컨트롤러 디자인 패턴은 응용프로그램과 같은 객체 지향 시스템의 객체들에게 역할을 부여합니다. 그들은 응용프로그램의 데이터를 가지고 데이터를 다루는 모델 객체 일 수도 있고, 사용자 액션에 반응하고 데이터를 표시하는 뷰 객체 일 수도 있고, 모델과 뷰 객체 사이에서 매개자의 역할을 하는 컨트롤러 객체 일 수도 있습니다. 컨트롤러 객체는 매개자 패턴에 잘맞습니다.

Cocoa에서 컨트롤러 객체는 두개의 일반적인 타입일 수 있습니다. 매개 컨트롤러이거나 혹은 조정하는 컨트롤러 일 수 있습니다. 매개 컨트롤러는 한 응용프로그램 안의 뷰 객체와 모델 객체 사이의 데이터의 흐름을 중재합니다. 매개 컨트롤러는 주로 NSController 객체입니다. 조정하는 컨트롤러는 한 응용프로그램의 중앙화된 통신과 컨트롤 로직을 구현하고 프레임웍 객체를 위한 델리게이트나 액션 메시지의 타겟으로 작동합니다. 그들은 주로 NSWindowController 객체이거나 커스텀 NSObject 서브클래스의 인스턴스입니다. 이들이 특정 프로그램을 위해 매우 전문화되었기 때문에 조정하는 컨트롤러는 보통 재사용가능하지 않습니다.

Application Kit 프레임웍의 추상 클래스인 NSController와 그 구상 서브클래스들은 자동으로 모델 객체의 데이터와 뷰 객체에서 표시되고 수정되는 데이터를 동기화시켜주는 Cocoa 바인딩 기술의 일부입니다. 예를 들어, 사용자가 텍스트필드에 스트링을 수정하면 바인딩이 이 변화를 매개 컨트롤러를 통해 묶여있는 모델 객체의 적절한 프로퍼티에 전달합니다. 모든 프로그래머들은 그들의 모델 객체를 잘 디자인 하여야 하고 Interface Builder를 사용하여 프로그램의 뷰, 컨트롤러, 모델 객체간의 바인딩을 설정해주어야 합니다.

구상 퍼블릭 컨트롤러 클래스의 인스턴스들은 Interface Builder의 팔렛트에서 사용할 수 있으며 재사용성이 매우 높습니다. 그들은 셀렉션, 플레이스홀더 값 관리와 같은 기능들을 제공합니다. 이들 객체는 다음의 특정한 기능들을 수행합니다.

  • NSObjectController는 하나의 모델 객체를 관리합니다.
  • NSArrayController는 모델 객체 배열을 관리하며 셀렉션을 유지합니다. 또한, 사용자가 배열에 객체를 더하거나 뺄 수 있도록 해줍니다.
  • NSTreeController는 계층적인 트리 구조의 모델 객체를 추가하고, 제거하고, 관리하도록 해줍니다.
  • NSUserDefaultsController는 프리퍼런스(유저 디폴트) 시스템에 편리한 인터페이스를 제공해줍니다.



[편집] Uses and Limitations

일반적으로 NSController 객체는 한 애플리케이션의 뷰 객체와 모델 객체 사이의 데이터를 전달하도록 디자인 되었기 때문에 매개 컨트롤러로 사용될 수 있습니다. 매개 컨트롤러를 사용하기 위해서는 보통 Interface Builder 팔렛트로부터 객체를 드래그하여 모델-객체 프로퍼티 키를 지정해주고, Interface Builder Info 창의 Bindings 팬을 사용하여 뷰와 모델 객체간의 바인딩을 설정해줍니다. 또한 NSController나 그 서브클래스중 하나를 서브클래스하여 더 특화된 행동을 얻을 수도 있습니다.

NSKeyValueCoding과 NSKeyValueObserving 비공식 프로토콜의 준수하는 객체들의 짝이면 어느 것이든 바인딩을 만들 수 있습니다. 그러나 NSController와 그 서브클래스가 제공하는 혜택을 받기 위해 매개 컨트롤러를 사용하여 바인딩을 만드는 것이 좋습니다.

조정하는 컨트롤러는 통신과 컨트롤 로직의 중앙화를 위해 다음을 수행합니다.

  • 모델과 뷰 객체의 아웃렛을 유지합니다.(아웃렛은 다른 객체로의 연결 혹은 레퍼런스를 쥐고 있는 객체입니다.)
  • 타겟-액션을 통해 사용자가 뷰 객체를 다루는 것에 반응합니다. ("Target-Action"을 보십시오.)
  • 프레임웍 객체가 보낸 메시지의 델리게이트로 동작합니다. ("Delegation"을 보십시오.)

보통 위의 모든 커넥션(아웃렛, 타겟-액션, 딜리게이션)은 Interface Builder에서 생성하며 응용프로그램의 nib 파일에 저장됩니다.

더 읽을 거리: "The Model-View-Controller Design Pattern"에서 매개 컨트롤러, 조정 컨트롤러, 컨트롤러와 관련된 디자인 결정사항 등에 대해 다루고 있습니다. Cocoa Bindings Programming Topics 에서는 매개 컨트롤러 클래스에 대해 더 상세히 설명합니다.



[편집] Memento

캡슐화를 위반하지 않고 객체의 내부 상태를 캡쳐하고 외부화하여 이후에 객체를 그 상태로 복원할 수 있도록 합니다. 메멘토 패턴은 키 객체의 중요한 상태를 객체로부터 외부화하여 결합성을 유지합니다.

[편집] Archiving

아카이빙은 프로그램의 객체를 객체의 프로퍼티(애트리뷰트와 관계)와 함께 아카이브로 전환시켜 파일 시스템에 저장하거나 프로세스 간, 혹은 네트워크를 통해 전송될 수 있도록 합니다. 아카이브는 프로그램의 객체 그래프를 아키텍쳐에 독립된 바이트 스트림으로 캡쳐하여 객체와 객체 간의 관계의 성격을 저장합니다. 객체의 타입이 데이터와 함께 저장되기 때문에 바이트 스트림으로부터 디코드된 객체는 보통 원래 인코드된 객체의 클래스를 사용해 인스턴스화 합니다.

[편집] Uses and Limitations

일반적으로 상태를 보존하기 원하는 객체를 아카이브합니다. 모델 객체는 거의 항상 이 카테고리에 속합니다. 인코딩하여 객체를 아카이브로 작성하고, 아카이브를 디코딩하여 객체를 읽습니다. 인코딩과 디코딩은 NSCoder 객체를 이용하여 수행하는데, keyed archiving 기법이 많이 사용됩니다. ( NSKeyedArchiver와 NSKeyedUnarchiver 클래스의 메소드를 호출합니다.) 인코드되고 디코드되는 객체는 반드시 NSCoding 프로토콜을 따라야 하며, 이 프로토콜의 메소드는 아카이빙시에 불려진다.

더 읽을 거리: Archives and Serialization Programming Guide for Cocoa에서 아카이빙에 대한 더 많은 정보를 얻을 수 있습니다.


[편집] Property List Serialization

프로퍼티 리스트는 NSDictionary, NSArray, NSString, NSData, NSNumber 이들 클래스의 객체만 사용하는 객체 그래프의 간단한 구조의 시리얼라이제이션입니다. 이들 객체는 보통 프로퍼티 리스트 객체로 불립니다. 몇몇 Cocoa 프레임웍 클래스는 이들 프로퍼티 리스트 객체를 시리얼라이즈 하는 메소드를 제공하며 객체의 컨텐츠와 그들의 계층적 관계를 기록하는 데이터 스트림을 위한 특별한 포맷을 정의합니다. NSPropertyListSerialization 클래스는 프로퍼티 리스트 객체를 XML 포맷이나 다른 최적화된 바이너리 포맷으로/으로부터 시리얼라이즈하는 클래스 객체를 제공합니다.

[편집] Uses and Limitations

객체 그래프의 객체가 단순하다면, 프로퍼티 리스트 시리얼라이제이션은 객체와 그 상태를 캡쳐하고 외부화하는데 유연하고 이동성이 높고, 적절한 방법입니다. 그러나 이런 형태의 시리얼라이제이션은 한계가 있습니다. 클래스 정의 객체를 완벽하게 보존하지 않고 일반적인 형태(배열, 딕셔너리, 스트링 등)만 저장합니다. 따라서 프로퍼티 리스트로부터 복원된 객체가 원래 클래스가 아닐 수도 있습니다. 객체의 변화 가능성이 달라진다면 이것이 특히 이슈가 됩니다. 프로퍼티 리스트 시리얼라이제이션은 한 객체에서 여러번 레퍼런스되는 객체들의 자취를 유지하지 않기 때문에, 잠재적으로 원래 그래프에서는 하나의 인스턴스였던 것이 디시리얼라이제이션 시에 복수의 인스턴스가 되는 문제를 낳을 수 있습니다.

더 읽을 거리: Archives and Serializations Programming Guide for Cocoa 에서 프로퍼티 리스트 시리얼라이제이션에 대해 더 많은 정보를 얻을 수 있습니다.


[편집] Core Data

코어 데이터는 객체 그래프를 관리하고 영속적으로 만들어주는 프레임웍이자 아키텍쳐입니다. 객체를 영속적으로 만드는 이 두번째 기능이 코어 데이터가 메멘토 페턴의 적용에 속하게 해줍니다.

코어 데이터 아키텍쳐에서 관리된 객체 컨텍스트라고 불리는 중앙 객체는 애플리케이션의 객체 그래프안의 다양한 모델 객체들을 관리합니다. 관리된 객체 컨텍스트 아래에는 모델 객체와 XML 파일이나 관계 데이터 베이스와 같은 외부 데이터 저장소 사이를 중개해주는 프레임웍 객체들의 콜렉션인 객체 그래프를 위한 영속 스택이 있습니다. 이 영속 스택 객체는 저장소의 데이터와 관리된 데이터 컨텍스트안에 해당되는 객체 사이를 매핑하며 다수의 데이터 저장소가 있는 경우 그들을 하나의 통합 저장소로 관리된 객체 컨텍스트에 표시해줍니다.

또한 코어 데이터의 디자인은 모델-뷰-컨트롤러와 객체 모델링 패턴에 많이 영향을 받았습니다.

중요: 코어 데이터 프레임웍은 Mac OS X v10.4에서 소개되었습니다.


[편집] Uses and Limitations

코어 데이터는 모델 객체의 복잡한 그래프가 정의되고 관리되고 데이터 저장소로부터 투명하게 아카이브되고, 언아카이브 되어야하는 기업용 애플리케이션의 개발에 특히 유용합니다. Xcode 개발 환경에는 일반적인 문서-기반, 문서-비 기반의 두 종류의 코어 데이터 애플리케이션을 생성하는데 필요한 프로그래밍 노력을 줄여줄 수 있는 프로젝트 템플릿과 디자인 도구를 포함하고 있습니다. Interface Builder 애플리케이션 또한 구성 가능한 코어 데이터 프레임웍 객체를 팔렛트에 포함하고 있습니다.

더 읽을 거리: 이 문서의 "Other Cocoa Architectures"에 코어 데이터의 요약이 포함되어 있습니다. 코어 데이터에 대해서 더 알기 원한다면 Core Data Programming Guide를 읽으십시오. NSPersistentDocument Core Data Tutorial과 Low-Level Core Data Tutorial이 두 개의 튜토리얼은 문서-기반, 비문서-기반의 코어 데이터 응용프로그램을 만들기위한 기본적인 절차를 단계적으로 안내합니다.


[편집] Observer

객체간 일대다 의존성을 정의하여 객체 하나의 상태가 변화하면 의존하는 모든 객체들은 자동으로 통지 받고 업데이트 됩니다. 옵저버 패턴은 본질적으로 출판-및-구독 모델로, 대상 객체와 그 관찰자들이 약하게 결합되어있습니다. 관찰하는 객체와 관찰되는 객체사이의 통신은 서로를 잘 알지 못하더라도 이루어질 수 있습니다.

[편집] Notifications

Cocoa의 노티피케이션 기법은 옵저버 패턴에 따라 메시지의 일대다 브로드캐스트를 구현합니다. 프로그램의 객체가 자기 자신이나 다른 객체를 각각의 글로벌 스트링(노티피케이션 이름)으로 구분할 수 있는 하나 혹은 그 이상의 노티피케이션의 옵저버로 등록합니다. 다른 객체에 통지하길 원하는 객체(관찰되는 객체)는 노티피케이션을 만들고 그것을 노티피케이션 센터에 보고합니다. 노티피케이션 센터는 특정 노티피케이션의 옵저버를 결정하고 메시지를 통해 그들에게 노티피케이션을 보냅니다. 노티피케이션 메시지에 의해 호출되는 메소드는 반드시 특정 단일 파라미터 시그니쳐를 따라야 합니다. 메소드의 파라미터는 노티피케이션의 이름, 관찰된 객체, 추가적인 정보를 담고있는 딕셔너리를 포함하는 노티피케이션 객체여야합니다.

노티피케이션을 포스팅하는 것은 동기화된 절차입니다. 포스팅하는 객체는 노티피케이션 센터가 모든 옵저버에 노티피케이션을 브로드캐스트 하기 전까지 컨트롤을 다시 얻어오지 않습니다. 비동기적 비헤이비어를 위해서, 노티피케이션을 노티피케이션 큐에 놓을 수 있습니다. 컨트롤은 포스팅하는 객체에 즉시 반환되며 노티피케이션 센터는 큐의 맨 위로 온 노티피케이션을 브로드캐스트합니다.

노티피케이션 센터에 의해 브로드캐스트되는 일반 노티피케이션은 프로세스 내부에서만 사용할 수 있습니다. 노티피케이션을 다른 프로세스에 브로드캐스트하길 원한다면 분산(distributed) 노티피케이션 센터와 관련된 API를 사용할 수 있습니다.

[편집] Uses and Limitations

노티피케이션을 사용하는 이유는 다양할 수 있습니다. 예를 들어, 유저 인터페이스 엘레먼트가 프로그램의 다른 곳에서 발생하는 특정한 이벤트에 기반한 정보를 표시하는 방식을 바꿔주는 노티피케이션을 브로드캐스트 할 수 있습니다. 혹은, 노티피케이션을 사용해 문서가 닫히기 전에 문서의 객체들의 상태를 저장하도록 할 수 있습니다. 노티피케이션의 일반적인 용례는 다른 객체들에게 프로그램 이벤트를 통지하여 적절히 반응하도록 하는 것입니다.

노티피케이션을 받는 객체는 이벤트가 발생한 이후에만 반응할 수 있습니다. 이것이 델리게이션과의 차이점 입니다. 델리게이트는 위임하는 객체에의해 제시된 작업을 수정하거나 거절할 기회를 갖습니다. 그러나 관찰하는 객체는 임박한 작업에 직접 영향을 받지 않습니다.

노티피케이션 클래스로 노티피케이션 객체에는 NSNotification, 노티피케이션을 포스트하고 옵저버를 추가하는데는 NSNotificationCenter, 노티피케이션을 대기시키기 위해서는 NSNotificationQueue와 NSDistributedNotificationCenter가 있습니다. 많은 Cocoa 프레임웍은 어느 객체든 관찰할 수 잇는 노티피케이션을 공개(publish)하고 포스트합니다.

더 읽을 거리: "Notification"에서 노티피케이션 기법을 더 상세히 설명하며 사용을 위한 가이드라인을 제공합니다.


[편집] Key-Value Observing

키-밸류 옵저빙은 다른 객체의 특정 프로퍼티의 변화를 통지받을 수 있도록 하는 기법입니다. NSKeyValueObserving 비공식 프로토콜에 기반하고 있습니다. 관찰되는 프로퍼티는 단순한 애트리뷰트이거나 대일 관계, 대다 관계일 수 있습니다. 모델-뷰-컨트롤러 패턴의 컨텍스트로 키-밸류 옵저빙은 뷰 객체가 컨트롤러 레이어를 통해 모델 객체의 변화를 관찰할 수 있도록 하기 때문에 특히 중요합니다. 그래서 Cocoa 바인딩 기술의 중요한 구성요소입니다. ("Controller Classes"를 보십시오.)

Cocoa는 많은 NSKeyValueObserving 메소드의 기본 "자동" 구현을 제공하여 준수하는 객체들에게 프로퍼티-옵저빙 기능을 부여합니다.

[편집] Uses and Limitations

키-밸류 옵저빙은 노티피케이션 기법과 비슷하지만 중요한 측면에서 차이점이 있습니다. 키-밸류 옵저빙에는 모든 객체에 변화 노티피케이션을 제공하는 중앙 객체 같은 것이 없습니다. 대신, 변화의 통지는 관찰하는 객체에 직접 전달됩니다. 키-밸류 옵저빙은 또한 특정 객체의 프로퍼티의 값과 직접 연결되어 있습니다. 반면 노티피케이션 기법은 프로그램 이벤트와 더 넓게 관련되어 있습니다.

키-밸류 옵저빙(KVO)에 참여하는 객체는 반드시 특정 요구사항을 준수하여야 합니다.(줄여 말하면 KVO-준수) 자동 옵저빙을 위해서 키-밸류 코딩의 요구사항을 준수(KVC-준수)와 KVC-준수 메소드를 사용을 요구합니다. 키 밸류 코딩은 객체 프로퍼티의 값을 자동으로 가져오고 지정하는데 (관련된 비공식 프로토콜에 기반하는) 관련된 기법입니다.

자동 옵저버 노티피케이션을 해제하고 NSKeyValueObserving 비공식 프로토콜의 메소드와 관련된 카테고리를 사용하여 KVO 노티피케이션을 더 다듬을 수 있습니다.

더 읽을 거리: Key-Value Observing Programming Guide에서 기법과 하부 프로토콜에 대해 더 배울 수 있습니다. 관련 문서인 Key-Value Coding Programming Guide와 Cocoa Bindings Programming Topics 도 읽으십시오.



[편집] Proxy

다른 객체의 대리인이나 플레이스홀더를 제공하여 그 객체의 액세스를 컨트롤합니다. 원거리에 있거나, 생성 비용이 높거나, 보안의 필요성이 있는 객체에 접근을 컨트롤하는 대리 객체를 만들고자 할때 이 패턴을 사용합니다. 이 패턴은 데코레이터 패턴과 구조적으로 비슷하나, 다른 목적을 수행합니다. 데코레이터는 객체에 비헤이비어를 추가하나 프록시는 객체의 접근을 컨트롤합니다.

[편집] NSProxy

NSProxy 클래스는 다른 객체 심지어 아직 존재하지 않는 객체의 플레이스홀더나 대리인으로 동작하는 객체의 인터페이스를 정의합니다. 프록시 객체는 보통 자신이 받은 메시지를 자신이 대리하는 객체에게 보내지만 위임하는 객체를 로딩하거나 자신을 위임하는 객체로 변환시켜서 메시지에 응답할 수도 있습니다. 비록 NSProxy가 추상 클래스이지만, NSObject 프로토콜과 루트 객체에게 기대되는 다른 기본적인 메소드를 구현하고 있습니다. 사실 NSObject 클래스처럼 클래스 계층의 루트 객체입니다.

NSProxy의 추상 서브클래스들은 비용이 높은 객체의 게으른 인스턴스화나 보안을 의해 센트리 객체로 동작하기와 같은 프록시 패턴에 언급된 목적들을 달성합니다. Foundation프레임웍의 NSProxy의 서브클래스인 NSDistantObject는 투명한 분산 메시징을 위해 원격 프록시를 구현합니다. NSDistantObject 객체는 분산 객체 아키텍쳐의 일부입니다. 다른 프로세스나 쓰레드에 있는 객체의 프록시로 동작하여 그 쓰레드와 프로세스의 객체간의 커뮤니케이션을 돕습니다. 커맨드 패턴을 적용한 NSInvocation 객체 역시 분산 객체 아키텍쳐의 일부입니다. ("Invocation Objects"를 보십시오.)

[편집] Uses and Limitations

Cocoa는 NSProxy 객체를 분산 객체에서만 사용합니다. NSProxy 객체는 구상 서브클래스인 NSDistantObject와 NSProtocolChecker의 인스턴스들입니다. 분산 객체를 프로세스간 메시징 (동일한 컴퓨터 상이거나 동일하지 않은 경우 모두 다) 에서 사용할 수도 있고, 분산 컴퓨팅이나 병렬 프로세싱의 구현을 위해 사용할 수도 있습니다. 만일 리소스 비용이 높은 객체를 만들어야 하는 경우나 보안 문제와 같이 프록시 객체를 다른 목적으로 사용하길 원하다면, NSProxy의 구상 서브클래스를 직접 구현해야 합니다.

더 읽을 거리: Cocoa 프록시 객체와 분산 메시징에서 이들의 역할에 대해 더 알길원한다면, Distributed Objects Programming Topics를 읽으십시오.


[편집] Singleton

클래스가 단 하나의 인스턴스만 갖도록 하며 그 인스턴스에 글로벌하게 접근할 수 있도록 합니다. 클래스는 그 유일한 인스턴스를 추적하고 다른 인스턴스가 생성되지 않도록 합니다. 싱글턴 클래스는 단 하나의 객체가 글로벌 리소스의 접근을 제공하는 것이 말이 되는 경우에 적합합니다.

[편집] Framework Classes

몇몇 Cocoa 프레임웍 클래스는 싱글턴입니다. 여기에는 NSFileManager, NSWorkspace, NSApplication이 포함됩니다. 프로세스당 이들 클래스의 인스턴스가 단 하나만 허용됩니다. 클래스에 인스턴스를 요청하면 맨 처음 요청될때 게으르게 생성되는 공유된 인스턴스(shared instance)를 받습니다.

[편집] Uses and Limitations

싱글턴 클래스로부터 반환된 공유 인스턴스를 사용하는 것은 일반 클래스의 인스턴스를 사용하는 것과 별 차이가 없지만, 카피, 리테인, 릴리즈를 할 수 없습니다. (관련된 메소드들은 무효화된 작업으로 재구현되어있습니다.) 상황에 따라 필요하다면 직접 싱글턴 클래스를 만들 수 있습니다.

더 읽을 거리: "Cocoa Objects"에서 싱글턴 객체를 만드는 방법이 설명되어 있습니다.


[편집] Template Method

특정 작업의 알고리즘의 골격을 정의하고 몇몇 단계는 서브클래스에서 구현하도록 연기합니다. 템플릿 메소드 패턴은 알고리즘의 구조를 바꾸지 않고 서브클래스에서 그 알고리즘의 특정한 단계를 재정의 할 수 있도록 합니다.

[편집] Overridden Framework Methods

템플릿 메소드 패턴은 Cocoa의 기본 디자인이며 전반적으로 객체지향입니다. Cocoa에서 이 패턴은 프로그램의 커스텀 컴포넌트가 알고리즘에 붙도록 하며, 프레임웍 컴포넌트가 그들이 언제 어떻게 필요한지 결정합니다. Cocoa 클래스의 프로그래밍 인터페이스는 종종 서브클래스로 오버라이드도되록 만들어져있는 메소드를 포함하고 있습니다. 런타임시에 프레임웍은 수행하는 작업의 특정 지점에서 제네릭 메소드라고 불리는 이들 메소드를 호출합니다. 제네릭 메소드는 커스텀 코드가 프로그램에 특정한 행동을 줄 수 있도록 하는 틀을 제공하며 프레임웍 클래스에 의해 수행되고 조정되어지는 작업에는 데이터를 제공합니다.

[편집] Uses and Limitations

템플릿 메소드 패턴의 Cocoa 적용을 활용하려면 서브클래스를 만들고 프레임웍이 애플리케이션-특정 입력을 수행하는 알고리즘에 집어넣기위해 호출하는 메소드를 오버라이드해야합니다. 만일 여러분의 프레임웍을 작성하고 있다면 이 패턴을 디자인에 포함해야할 것 입니다.

노트: "Adding Behavior to a Cocoa Program", 특히 "Inheriting From a Cocoa Class"에서 템플릿 디자인 패턴의 Cocoa 적용을 다루고 있습니다.


[편집] Document Architecture

Cocoa의 다큐먼트 아키텍쳐는 오버라이드된 프레임웍 메소드의 일반적인 디자인의 전형적이고 중요한 인스턴스이며, 템플릿 메소드 패턴의 적용입니다. 다수의 문서를 각각 자신의 창에서 만들고 다룰 수 있는 Cocoa 애플리케이션은 거의 항상 다큐먼트 아키텍쳐에 기반하고 있습니다. 이 아키텍쳐에는 NSDocument, NSWindowController, NSDocumentController 이 세개의 클래스의 객체들이 서로 협력합니다. NSDocument 객체는 문서의 데이터를 담당하는 모델 객체를 관리합니다. 사용자 요청이 있으면 데이터를 파일에 기록하고, 거기에 딸린 모델 객체를 재생성합니다. NSWindowController 객체는 특정 문서의 사용자 인터페이스를 관리합니다. 문서기반 응용프로그램의 NSDocumentController 객체는 열려있는 모든 문서를 추적하고 관리하며, 문서기반프로그램이 아닌 경우에는 애플리케이션의 활동을 조정합니다. 런타임시에 이들 객체는 각각 특정한 작업을 수행하도록 Application Kit으로부터 요청하는 메시지를 받습니다. 애플리케이션 특정한 행동을 추가하길 원한다면 프로그램의 개발자는 이들 메시지에 의해 호출되는 메소드의 많은 부분을 구현해야만 합니다.

Cocoa의 다큐먼트 아키텍쳐의 디자인은 모델-뷰-컨트롤러 패턴에 아주 많은 영향을 받았습니다.

[편집] Uses and Limitations

문서기반 Cocoa 애플리케이션을 만들고자 하면, Xcode의 New Project 어시스턴트에서 문서기반 애플리케이션 템플릿을 선택하여 프로젝트를 생성하면 됩니다. 그후, NSDocument의 커스텀 서브클래스를 구현해야만 하며 NSWindowController와 NSDocumentController의 커스텀 서브클래스를 구현하도록 선택할 수 있습니다. Application Kit에서 애플리케이션의 문서관리 로직을 상당부분 제공합니다.

노트: 이 문서의 "Other Cocoa Architectures"에 다큐먼트 아키텍쳐의 요약이 있습니다. 이 템플릿 메소드 패턴의 적용에 대한 상세한 설명은 Document-Based Applications Overviews에서 찾을 수 있습니다.



[편집] The Model-View-Controller Design Pattern



모델-뷰-컨트롤러(MVC) 디자인 패턴은 꽤 오래되었습니다. 적어도 스몰톡의 초창기부터 이 디자인 패턴의 변형들이 있어왔습니다. 이 디자인 패턴은 애플리케이션의 글로벌 구조에 관여하며 애플리케이션에서 객체들의 일반적인 역할에 따라 구분한다는 측면에서 고수준의 패턴입니다. 또한, 더 기초적인 패턴들로 되어있기에 복합 패턴이기도 합니다.

객체지향 프로그램은 MVC 디자인 패턴을 적용하여 많은 이득을 얻을 수 있습니다. 이런 프로그램의 많은 객체들은 재사용 가능하고 인터페이스는 더 잘 정의된 경향이 있습니다. 전반적으로 프로그램이 변화에 잘 적응하게 됩니다. 다른 말로 하면, MVC에 기반하지 않은 프로그램에 비해 더 쉽게 확장할 수 있게 됩니다. 게다가, 바인딩, 다큐먼트 아키텍쳐, 스크립팅 가능성과 같이 많은 Cocoa의 기술과 아키텍쳐가 MVC에 기반하고 있기때문에 커스텀 객체도 MVC에 정의된 역할을 수행하는 것이 요구합니다.

[편집] Roles and Relationships of MVC Objects

MVC 디자인 패턴은 모델객체, 뷰 객체, 컨트롤러 객체 이 세 종류의 객체가 있다고 봅니다. 이 패턴은 이들 객체가 애플리케이션 안에서 수행할 역할과 커뮤니케이션의 통로를 정의합니다. 애플리케이션을 디자인할때 혹은 커스텀 클래스를 디자인할때 중요한 단계는 객체들이 이 세 그룹 중 하나에 속하도록 하는 것입니다. 객체의 이 세 종류는 각각 추상적인 경계로 분리되어 있으며 이들 경계를 통해 다른 종류의 객체와 커뮤니케이션합니다.

[편집] Model Objects Encapsulate Data and Basic Behaviors

모델 객체는 전문 지식과 전문성을 나타냅니다. 이들은 애플리케이션의 데이터를 담고 있으며 데이터를 다룰 로직을 정의합니다. 잘 디자인된 MVC 애플리케이션은 중요한 데이터를 모두 모델 객체에 캡슐화합니다. 어느 데이터든 프로그램의 영속적인 상태의 일부라면 (그 상태가 파일에 저장되었든지 데이터베이스에 저장되었는지에 상관없이) 데이터가 응용프로그램에 로드된 이후에는 모델 객체에 거주해야합니다. 이들이 특정 문제 도메인에 관련된 지식과 전문성의 표현이기 때문에 주로 재사용이 가능합니다.

이상적으로는, 모델 객체에는 자신을 표시하고 수정하도록 하는 유저 인터페이스와 명시적인 연결이 없습니다. 예를 들어, (주소록 프로그램을 작성한다고 합시다)사람을 표시하는 모델 객체가 있을 때, 생일을 저장하고 싶을 수 있습니다. 생일은 Person 모델 객체에 저장하기 적당합니다. 그러나 데이터 포맷 스트링을 저장하는 것이나 그 날짜가 어떤식으로 표시될지에 대한 다른 정보는 다른 곳에 있는 것이 좋을 것입니다.

현실에서는 이런 분리가 항상 최선은 아니며 융통성도 있어야 합니다. 그러나 일반적으로 모델 객체는 인터페이스와 표시 문제와 관련이 없어야 합니다. 예외가 타당한 한 예로는 디스플레이되는 그래픽을 표시하는 모델 객체가 있는 드로잉 응용프로그램을 들 수 있습니다. 이 경우 그래픽 객체의 존재 목적이 시각적인 것을 정의하는 것이기 때문에 자신을 어떻게 그리는 지 알고 있는 것이 합당합니다. 그러나 이런 경우에도 그래픽 객체가 특정 뷰 아니 어느 뷰에든 의존해서는 안되며, 그들 자신을 언제 그려야 하는지 아는 것을 담당해서는 안됩니다. 그들은 그들을 표시하길 원하는 뷰 객체로부터 자신을 그리도록 요청받아야 합니다.

더 읽을 거리: Model Object Implementation Guide에서 모델 객체의 적절한 디자인과 구현을 다루고 있습니다.


[편집] View Object Present Information to the User

뷰 객체는 애플리케이션의 모델의 데이터를 어떻게 디스플레이하는지 알고 있으며 사용자가 그 데이터를 수정할 수 있도록 합니다. 뷰는 디스플레이하는 데이터를 저장하는 책임을 지지 않습니다. (물론 이것은 뷰가 디스플레이하는 데이터를 절대 저장하지 않는다는 것을 의미하지는 않습니다. 성능상의 이유로 뷰가 데이터를 캐쉬하거나 비슷한 기법을 사용할 수 있습니다.) 뷰 객체는 모델의 한부분이나 모델의 전체, 심지어는 많은 다른 모델 객체를 표시하는 것을 담당할 수 있습니다. 뷰는 많은 다양한 형태가 있습니다.

뷰 객체는 보통 재사용 가능하며 설정할 수 있습니다. 또한, 프로그램간의 일관성도 제공해줍니다. Cocoa에서는 Application Kit이 많은 수의 뷰 객체를 정의하며 그들 중 많은 수를 Interface Builder의 팔렛트에 제공하고 있습니다. NSButton 객체와 같은 Application Kit의 뷰 객체를 재사용하는 것으로 애플리케이션이 여타 다른 Cocoa 애플리케이션과 동일하게 동작할 것을 보장할 수 있습니다. 따라서, 애플리케이션간의 겉모습과 동작의 일관성을 높은 수준으로 유지할 수 있습니다.

뷰는 모델을 제대로 디스플레이해야 합니다. 따라서, 보통 모델의 변화를 알아야 할 필요가 있습니다. 모델 객체가 특정 뷰 객체와 묶여서는 안되기 때문에 그들의 변화를 알릴 수 있는 일반적인 방법이 필요하게 됩니다.

[편집] Controller Objects Tie the Model to the View

컨트롤 객체는 애플리케이션의 뷰 객체와 모델 객체 사이에서 중개자 역할을 합니다. 컨트롤러는 종종 뷰가 자신이 디스플레이할 필요가 있는 모델 객체에 접근할 수 있도록 하며 뷰가 모델 객체의 변화를 알 수 있게 하는 통로의 역할을 합니다. 컨트롤러 객체는 또한 애플리케이션을 위한 셋업을 수행하고 작업을 조정하며 다른 객체의 생명주기를 관리합니다.

전형적인 Cocoa MVC 디자인에서 사용자가 뷰 객체를 통해 값을 입력하거나 선택을 지시하면, 그 값이나 선택은 컨트롤 객체를 통해 커뮤니케이션됩니다. 컨트롤러 객체는 사용자의 입력을 애플리케이션에 특정한 방식으로 해석한 후 모델 객체에게 그 입력을 가지고 무엇인가를 하도록 할 수 있습니다. 예를 들어 "새로운 값을 더하라"거나 "현재 레코드를 삭제하라". 혹은 모델 객체의 프로퍼티중의 하나의 값의 변화를 반영하게 할 수 있습니다. 이 동일한 사용자 입력을 가지고 어떤 컨트롤러는 버튼을 사용불가능한 상태로 만드는 것과 같이 뷰 객체의 겉모습이나 행동을 바꾸도록 할 수 있습니다. 반대로, 새로운 데이터 소스가 접근한 것과 같이 모델 객체의 변화가 있을 때, 모델 객체도 보통 변화를 컨트롤러 객체에 커뮤니케이션하고 컨트롤러 객체는 하나 혹은 그 이상의 뷰 객체가 알맞게 업데이트 하도록 요청합니다.

컨트롤러 객체는 그들의 일반적인 형태에 따라 재사용 가능하기도 하며 불가능하기도 합니다. "Types of Cocoa Controller Objects"에서 Cocoa의 컨트롤러 객체들의 다른 타입에 대해서 설명하고 있습니다.

[편집] Combining Roles

객체가 다수의 MVC 역할을 수행하도록 할 수 있습니다. 예를 들어 객체가 컨트롤러와 뷰 역할을 담당할 수 있으며 이 경우는 뷰-컨트롤러라고 불리게 됩니다. 같은 방식으로 모델-컨트롤러 객체가 있을 수 있습니다. 몇몇 응용프로그램에서는 이렇게 역할을 혼합하는 것이 적합한 디자인일 수 있습니다.

모델-컨트롤러는 주로 모델 레이어에 관여하는 컨트롤러입니다. 모델을 소유하고 있으며, 주된 책임은 모델을 관리하고 뷰 객체와 의사소통하는 것입니다. 모델 전체에 적용되는 액션 메소드는 주로 모델-컨트롤러에 구현되어 있습니다. 다큐먼트 아키텍쳐는 이들 메소드의 많은 수를 제공하고 있습니다. 예를 들어 (다큐먼트 아키텍쳐의 중심점인) NSDocument 객체는 파일 저장과 관련된 액션 미시지를 자동으로 처리합니다.

뷰-컨트롤러는 주로 뷰 레이어에 관여하는 컨트롤러입니다. 인터페이스(뷰)를 소유하고 있으며 주된 책임은 인터페이스를 관리하고 모델 객체와 의사소통하는 것입니다. 뷰에 표시되는 데이터와 관련된 액션 메소드는 주로 뷰-컨트롤러에 구현되어 있습니다. 뷰-컨트롤러의 한 예로 (이 또한 다큐먼트 아키텍쳐의 일부인) NSWindowController 객체를 들 수 있습니다.

“Design Guidelines for MVC Applications”에서 통합된 MVC와 객체들에 대한 조언을 제공하고 있습니다.

더 읽을 거리: Document-Based Applications Overview에서 모델-컨트롤러와 뷰-컨트롤러를 다른 시각에서 다루고 있습니다.


[편집] Types of Cocoa Controller Objects

“Controller Objects Tie the Model to the View” 섹션이 컨트롤러 객체의 추상적인 개요를 설명하고 있지만, 현실은 훨씬 더 복잡합니다. Cocoa에는 두가지의 일반 컨트롤러 객체가 있습니다. 매개하는 컨트롤러와 조정하는 컨트롤러입니다. 각각의 컨트롤러 객체는 다른 클래스 집단과 관련되어 있으며 각각 다른 행동의 범주를 제공합니다.

매개 컨트롤러는 보통 NSController클래스로부터 상속받는 객체입니다. 매게 컨트롤러는 Cocoa 바인딩 기술에 사용되어집니다. 그들은 뷰 객체와 모델 객체간의 데이터 흐름을 용이하게(혹은 매개)합니다.

매개 컨트롤러는 보통 이미 만들어진 객체로 Interface Builder 팔렛트에서 드래그해서 쓸수 있습니다. 이들 객체를 구성하여 뷰 객체의 프로퍼티와 컨트롤러 객체의 프로퍼티간의 바인딩을 설정한 뒤, 이들 컨트롤러 객체의 프로퍼티와 모델 객체의 특정 프로퍼티를 바인딩합니다. 결과로, 사용자가 뷰 객체에 표시되는 값에 변화를 주면 새로운 값이 매개 컨트롤러를 통해 모델 객체에 자동으로 전송됩니다. 또 모델의 프로퍼티의 값이 변한다면, 그 변화는 뷰에 반영되어 표시됩니다. 추상 NSController 클래스와 그 구상 서브클래스인 NSObjectController, NSArrayController, NSUserDefaultsController는 변화의 수행 및 취소, 선택 관리 및 플레이스홀더 값과 같은 기능을 지원합니다.

조정 컨트롤러는 보통 NSWindowController 이거나 NSDocumentController 객체, 혹은 NSObject의 커스텀 서브클래스의 인스턴스입니다. 프로그램 전체 혹은 nib 파일로부터 언아카이브한 객체와 같은 프로그램 일부의 동작을 감독 혹은 조정하는 역할을 수행합니다. 조정 컨트롤러는 다음과 같은 서비스를 제공합니다.

  • 델리게이션 메시지에 반응하고 노티피케이션을 대기합니다.
  • 액션 메시지에 반응합니다.
  • 소유한 객체의 생명주기를 관리합니다.(예, 적절한 때 릴리즈하기)
  • 객체 사이의 연결을 설정하고 다른 셋업 작업을 수행합니다.

NSWindowController 와 NSDocumentController 클래스는 문서기반 응용프로그램을 위한 Cocoa 아키텍쳐의 일부입니다. 이들 클래스의 인스턴스는 위에 언급된 서비스의 일부를 위한 기본 구현을 제공하며 응용프로그램에 맞는 특정한 행동을 더 구현하기 위해 서브클래스를 만들 수도 있습니다. 심지어 NSWindowController를 이용하여 문서 기반이 아닌 응용프로그램의 창을 관리할 수도 있습니다.

조정 컨트롤러는 nib 파일에 아카이브된 객체를 자주 소유합니다. 파일의 소유주(File's Owner)로 nib파일의 객체들에게는 외부(external)이며 그들을 관리합니다. 이들 소유된 객체는 창 객체와 뷰 객체 뿐만 아니라 매개 컨트롤러도 포함합니다. "MVC as a Compound Design Pattern"에서 파일의 소유주로서의 조정 컨트롤러에 대해 더 많은 설명을 얻을 수 있습니다.

NSObject의 커스텀 서브클래스의 인스턴스는 조정 컨트롤러가 되기 적합합니다. 이런 종류의 컨트롤러 객체는 매개와 조정 기능을 결합합니다. 그들의 매개 행동으로 타겟-액션, 아웃렛, 델리게이션, 노티피케이션과 같은 기법들을 활용합니다. 코드가 응용프로그램에 독점적으로 적합하므로 많은 "글루"코드를 포함하게 되고, 이들이 응용프로그램 내에서 가장 재사용하기 어려운 종류의 객체입니다.

더 읽을 거리: 매개 컨트롤러의 역할을 컨트롤러 객체에 대한 더 많은 정보는 "Mediator" 디자인 패턴에서 찾을 수 있습니다. Cocoa 바인딩 기술에 대한 더 많은 정보는 Cocoa Binding Programming Topics에서 찾을 수 있습니다.


[편집] MVC as a Compound Design Pattern

모델-뷰-컨트롤러는 몇몇 더 기본적인 디자인 패턴으로 이루어져 있는 디자인 패턴입니다. 이들 기본 패턴들이 합작하여 MVC 응용프로그램의 특징인 기능적 구분과 커뮤니케이션 통로를 정의합니다. 그러나 전통적인 MVC의 개념은 Cocoa의 기본 패턴 모음과는 좀 다릅니다. 이 차이는 주로 응용프로그램의 컨트롤러와 뷰 객체에게 부여된 역할에 기인합니다.

원래(Smalltalk)의 개념에서 MVC는 컴포지트, 전략, 옵저버 패턴으로 이뤄져 있습니다.

  • 컴포지트(Composite)-응용프로그램의 뷰 객체는 사실 조정된 방식으로 함께 동작하는 네스트된 뷰의 컴포지트(뷰 계층)입니다. 이들은 창에서부터 테이블 뷰와 같은 복합 뷰와 버튼과 같은 개별 뷰까지 디스플레이합니다. 사용자 입력과 디스플레이는 컴포지트 구조의 어느 단계에서든 발생할 수 있습니다.
  • 전략(Strategy)-컨트롤러 객체는 하나 혹은 그 이상의 뷰 객체를 위한 전략을 구현합니다. 뷰 객체는 자신을 시각적인 측면을 유지하는 역할로 제한시키고 컨트롤러에게 응용프로그램에 특정한 인터페이스 행동의 의미에 대한 결정을 모두 컨트롤러에게 위임합니다.
  • 옵저버(Observer)-모델 객체는 응용프로그램 안에 관심있는 객체(보통 뷰 객체)의 상태 변화를 알게합니다.

이들 패턴은 Figure 4-4에 나타난 방식으로 함께 동작합니다. 사용자가 컴포지트 구조의 특정 단계에서 뷰를 다루고, 결과로 이벤트가 생성됩니다. 컨트롤러 객체는 이벤트를 받아 응용프로그램에 특정한 방식으로 해석합니다. 바로 여기서 전략이 적용됩니다. 이 전략은 메시지를 통해 모델 객체의 상태를 변화시키는 요청일 수도 있고, (컴포지트 구조의 어느 단계에 있는)뷰 객체가 그 행동이나 외양을 변화시키도록 요청하는 것일 수 있습니다. 그 결과로 모델 객체는 옵저버로 등록된 모든 객체에게 상태가 변화될 때 통보합니다. 옵저버가 뷰 객체라면 그에 따라 외양을 업데이트 할 수도 있습니다.

Figure 4-4 Traditional version of MVC as a compound pattern



컴파운드 패턴의 측면에서 Cocoa 버전의 MVC는 전통적인 버전과 비슷한 점이 좀 있고, 사실 Figure 4-4의 다이어그램에 기반하여 작동하는 응용프로그램을 구축하는 것이 가능합니다. 바인딩 기술을 사용하여 모델 객체를 직접 관찰하여 상태 변화의 통지를 받는 뷰 객체가 있는 Cocoa MVC 애플리케이션을 쉽게 만들 수 있습니다. 그러나 이 디자인에는 이론상 문제가 있습니다. 뷰 객체와 모델 객체는 응용프로그램에서 재사용성이 가장 높은 객체여야 합니다. 뷰 객체는 운영체제와 그 시스템이 지원하는 응용프로그램의 "룩앤필"을 나타냅니다. 외양과 행동의 일관성은 필수적이며 고도로 재사용성이 높은 객체를 요구합니다. 대다수의 객체는 정의 자체로 문제 도메인에 연관된 데이터를 캡슐화하고 그 데이터에 작업을 수행합니다. 디자인 적인 면에서 모델과 뷰 객체를 분리된 상태로 유지하는 것이 재사용성을 높일 수 있기에 최선의 방식이라 할 수 있습니다.

대다수의 Cocoa 응용프로그램에서, 모델 객체의 상태 변화의 통지는 컨트롤러 객체를 통해 뷰 객체로 커뮤니케이션됩니다. Figure 4-5는 두개의 기본 디자인 패턴이 더 관여함에도 훨씬 깔끔해진 다른 구성을 보여주고 있습니다.

Figure 4-5Cocoa version of MVC as compound design pattern

 

이 복합 디자인 패턴의 컨트롤러 객체는 전략 패턴 뿐만 아니라 매개 패턴도 통합합니다. 모델과 뷰 객체 사이의 쌍방 데이터 흐름을 매개합니다. 모델 상태의 변화는 응용프로그램의 컨트롤러 객체를 통해 뷰 객체에 전달됩니다. 게다가 뷰 객체는 타겟-액션 기법의 구현으로 커맨드 패턴도 통합합니다

노트: 뷰 객체가 사용자 입력과 선택과 커뮤니케이션하도록 해주는 타겟-액션 기법은 조정 컨트롤러 객체와 매개 컨트롤러 객체 모두에 구현될 수 있습니다. 그러나 각 컨트롤러 타입에 따라 이 기법의 디자인은 다릅니다. 조정 컨트롤러의 경우 Interface Builder에서 뷰 객체를 (컨트롤러 객체인) 타겟에 연결하고 특정 시그니쳐를 따르는 액션 셀렉터를 지정해줍니다. 조정 컨트롤러는 창과 글로벌 애플리케이션 객체의 딜리게이트가 되기에 리스폰더 체인에 있을 수 있습니다. 매개 컨트롤러에서 사용되는 바인딩 기법 또한 뷰 객체를 타겟에 연결하고 액션 시그니쳐에 다양한 수의 임의 타입의 인자를 사용할 수 있도록 합니다. 그러나 매개 컨트롤러는 리스폰더 체인에 포함되지 않습니다.


Figure 4-5에서 보여지는 개정된 복합 디자인 패턴의 이유는 이론적인 것 외에도 실용적인 것도 있습니다. 특히 Mediator 디자인 패턴에서 더욱 그러합니다. NSController의 구성 서브클래스로부터 파생된 매개 컨트롤러와 그 클래스들은 Mediator 패턴을 구현하는 것 외에도 셀렉션 및 플레이스 홀더 값 관리 같이 응용프로그램들이 활용할 수 있는 많은 기능들을 제공합니다. 만일 바인딩 기술을 사용하지 않기로 했다면, 뷰 객체는 Cocoa 노티피케이션 센터 같은 기법을 사용하여 모델 객체로부터 노티피케이션을 받을 수 있습니다. 그러나 이 방식을 사용하기 위해서는 모델 객체로부터 오는 노티피케이션의 이해를 추가하기 위해 커스텀 뷰 서브클래스를 만들어야 합니다.

잘 디자인된 Cocoa MVC 응용프로그램에서 조정 컨트롤러는 nib 파일에 아카이브되어있는 매개 컨트롤러를 종종 소유합니다. Figure 4-6에서 두 종류의 컨트롤러 객체의 관계를 보여줍니다.

Figure 4-6 Coordinating controller as the owner of a nib file
 


[편집] Design Guidelines for MVC Applications

다음 가이드라인은 응용프로그램의 디자인시 모델-뷰-컨트롤러 고려사항에 적용됩니다.

  • NSObject의 커스텀 서브클래스를 매개 컨트롤러로 사용할 수 있으나, 이를 위해 필요한 모든 작업을 수고스럽게 해야할 이유가 없습니다. 대신 Cocoa 바인딩 기술을 위해 이미 디자인 되어있는 NSController 객체중 하나를 사용하십시오. 그것은 NSController의 구상 서브클래스인 NSObjectController, NSArrayController, NSUserDefaultsController, NSTreeController의 인스턴스나 이들의 커스텀 서브클래스를 사용하는 것입니다.

그러나 응용프로그램이 매우 단순하고 아웃렛과 타겟-액션을 사용하는 매개 행동을 구현하는데 필요한 "글루 코드"를 작성하는게 편리하다면 NSObject의 커스텀 서브클래스의 인스턴스를 매개 컨트롤러로 사용해도 좋습니다. NSObject 커스텀 서브클래스에서, 키-밸류 코딩, 키-밸류 옵저빙, 에디터 프로토콜을 사용하여 매개 컨트롤러를 NSController와 같은 개념으로 구현할 수 있습니다.

  • 한 객체에 MVC 역할을 모두 합쳐 넣을 수 있지만, 가장 좋은 전략은 각 역할을 분리하는 것입니다. 이렇게 분리하면 객체의 재사용성과 그들을 사용하는 프로그램의 확장성을 높일 수 있습니다. 만일 MVC 역할을 클래스에 병합하려 한다면, 그 클래스의 주 역할을 고르고 (관리를 위해) 동일한 구현 파일에 카테고리를 사용하여 클래스가 다른 역할을 수행하도록 하십시오.
  • 잘 디자인된 MVC 응용프로그램의 목표는 (적어도 이론적으로) 재사용가능한 객체들을 가능한한 많이 사용하는 것이어야 합니다. 특히, 뷰 객체와 모델 객체는 재사용성이 높아야 합니다. (이미 만들어져있는 매개 컨트롤러도 당연히 재사용 가능합니다.) 응용프로그램에 특정한 행동은 종종 최대한 컨트롤러 객체에 집중됩니다.
  • 뷰가 모델 객체의 변화를 직접 관찰하는 것이 가능하지만, 그렇게 하는 것을 권하지는 않습니다. 뷰 객체는 언제나 매개 컨트롤러 객체를 통해 모델 객체의 변화를 알아야 합니다. 이렇게 하는 이유는 두가지가 있습니다.
    • 바인딩 기법을 사용하여 뷰 객체가 모델 객체의 프로퍼티를 직접 관찰하면, NSController와 그 서브클래스들이 제공하는 이점들을 모두 놓치게 됩니다. 그 이점들은 변화 수행 및 취소 기능 뿐만 아니라 선택 및 플레이스홀더 관리도 포함합니다.
    • 만일 바인딩 기법을 사용하지 않는다면, 현존하는 뷰 클래스를 서브클래스하여 모델 객체가 올리는 변화 통지를 관찰하는 기능을 추가해야합니다.
  • 응용프로그램의 클래스간 코드 의존성을 제한하도록 노력하십시오. 한 클래스가 다른 클래스에 갖는 의존성이 높으면 높을 수록 재사용성이 떨어지게 됩니다. 관련된 두 클래스의 MVC 역할에 따라 구체적인 조언은 다를 수 있습니다.
    • 뷰 클래스는 모델 클래스에 의존해서는 안됩니다. (몇몇 커스텀 뷰에서는 이런 상황을 피하지 못할 경우도 있습니다.)
    • 뷰 클래스는 매개 컨트롤러 클래스에 의존해서는 안됩니다.
    • 모델 클래스는 다른 모델 클래스를 제외한 다른 클래스에 의존해서는 안됩니다.
    • 매개 컨트롤러 클래스는 모델 클래스에 의존해서는 안됩니다. (비록 뷰와 같은 경우 커스텀 컨트롤러 클래스라면 이렇게 하는 것이 필요할 수 있습니다.)
    • 매개 컨트롤러 클래스는 뷰 클래스나 조정 컨트롤러 클래스에 의존해서는 안됩니다.
    • 조정 컨트롤러 클래스는 모든 MVC 역할 타입에 의존합니다.
  • 만일 Cocoa에서 특정 타입의 객체에 MVC 역할을 부여하는 아키텍쳐를 제공한다면 그 아키텍쳐를 사용하십시오. 이렇게 하면 프로젝트를 통합하기 더 쉬워질 것입니다. 예를 들면, 다큐먼트 아키텍쳐는 NSDocument 객체를 (nib 컨트롤러-모델 당 하나) 파일의 소유주(File's Owner)로 선구성하는 Xcode 프로젝트 템플릿을 포함합니다.



[편집] Model-View-Controller in Cocoa (Mac OS X)

모델-뷰-컨트롤러 디자인 패턴은 많은 Cocoa 기법과 기술의 기초입니다. 결과로 객체 지향 디자인에서 MVC 사용의 중요성은 응용프로그램의 더 높은 재사용성과 확장성을 확보하는 것 이상이 됩니다. 만일 프로그램에 MVC 기반의 기술을 통합하고자 한다면, 프로그램 자체의 디자인도 MVC 패턴을 따르고 있어야 가장 잘 동작할 것입니다. 프로그램에 MVC 분리가 잘 되어있다면 이들 기술을 사용하는 것이 상대적으로 덜 괴롭겠지만, 분리가 잘 안되어 있다면 이들 기술을 사용하기 위해 더 많은 노력을 들여야 할 것입니다.

Cocoa는 다음과 같이 모델-뷰-컨트롤러에 기반한 아키텍쳐, 기법, 기술을 포함합니다.

  • 다큐먼트 아키텍쳐 이 아키텍쳐에서 문서 기반 응용프로그램은 전체 응용프로그램을 위한 컨트롤러 객체(NSDocumentController), 각 문서 창을 위한 컨트롤러(NSWindowController), 각 문서를 위해 컨트롤러와 모델 역할을 합친 객체(NSDocument)로 구성되어 있습니다.
  • 바인딩 위에서 지적했듯이, MVC는 Cocoa의 바인딩 기술의 중심입니다. 추상 NSController의 구상 서브클래스들인 바로 사용할 수 있는 컨트롤러 객체들은 뷰 객체와 제대로 디자인된 모델 객체 사이에 바인딩을 설정하도록 해줍니다.
  • 응용프로그램 스크립트 기능 응용프로그램에 스크립트 기능을 넣길 원한다면, MVC 디자인 패턴을 따르는 것 뿐만 아니라 응용프로그램의 모델 객체가 제대로 디자인되는 것이 필수입니다. 응용프로그램 상태에 접근하고 응용프로그램 행동을 요청하는 스크립팅 명령은 일반적으로 모델 객체나 컨트롤러 객체에 보내져야 합니다.
  • Core Data Core Data 프레임웍은 모델 객체의 그래프를 관리하며 그들을 영속 저장소에 저장하여(그리고 저장소로부터 반환하여) 이들 객체의 영속성을 보장합니다. Core Data는 Cocoa 바인딩 기술과 깊이 통합되어 있습니다. MVC와 객체 모델링 디자인 패턴이 Core Data 아키텍쳐의 필수적인 결정요인입니다.
  • 작업취소(undo) 작업 취소 아키텍쳐에서 모델 객체는 또 한번 중심 역할을 수행합니다. 모델 객체의 원시 메소드(보통 액세서 메소드)에서 작업취소/복귀 작업을 구현해줍니다. 액션의 뷰와 컨트롤러 객체 역시 이들 작업과 관련이 있을 수 있습니다. 예를 들어, 그런 객체가 작업취소/복귀 메뉴 아이템에 특정 타이틀을 주도록 하거나 텍스트 뷰의 선택을 작업취소하게 할 수 있습니다.
더 읽을 거리: "Other Cocoa Architectures"에서 다큐먼트 아키텍쳐, 응용프로그램 스크립트 기능, Core Data의 개요와 이들 기술을 상세히 다루고 있는 문서의 레퍼런스를 찾을 수 있습니다.



[편집] Object Modeling

이 섹션은 Cocoa 바인딩과 Core Data 프레임웍에 특정한 객체 모델링과 키-밸류 코딩의 용어를 정의하며 그 예를 제시합니다. 키 패스와 같은 용어를 이용하는 것이 이들 기술을 효과적으로 사용하기 위한 기본입니다. 만일 객체지향 디자인 혹은 키-밸류 코딩을 처음 배운다면 이 섹션을 읽는 것을 추천합니다.

Core Data 프레임웍을 사용할 때, 뷰나 컨트롤러에 의존하지 않고 모델 객체를 설명할 방법이 필요합니다. 재사용 가능한 좋은 디자인에서는, 뷰와 컨트롤러는 그들 간에 의존성을 부여하지 않고 모델 프로퍼티에 접근할 방법이 필요합니다. Core Data 프레임웍은 데이터베이스 기술, 특히 개체-관계 모델(ER 모델)의 개념과 용어를 빌려와 이 문제를 해결합니다.

개체-관계 모델링은 객체를 표시하는 방법으로, 주로 데이터 소스의 데이터 구조를 객체 지향적인 시스템의 객체에 매핑되도록 하는 방식으로 표시하는데 사용되어집니다. 개체-관계 모델링은 Cocoa만 가지고 있는 독특한 특징은 아닙니다. 그것은 데이터베이스의 세계에서 문서화된 규칙과 용어를 갖추고 있는 인기있는 방식입니다. 그것은 데이터 소스의 객체 저장과 복원을 더 쉽게 만드는 표시법입니다. 데이터 소스는 데이터베이스, 파일, 웹 서비스, 혹은 다른 어떤 영속 저장소일 수 있습니다. 어떤 종류의 데이터 소스에도 의존하지 않기 때문에 어느 종류의 객체와 다른 객체와의 관계도 표시하는데 사용되어질 수 있습니다.

Cocoa는 이 글에 객체 모델링으로 언급된 전통적인 개체-관계 모델링의 규칙의 수정된 버전을 사용합니다. 객체 모델링은 MVC 디자인 패턴의 모델 객체를 표시하는데 특히 유용합니다. 단순한 Cocoa 응용프로그램에서도 모델은 파일과 같은 특정 데이터 컨테이너에 저장되기 때문에 특히 영속적입니다.

[편집] Entities

MVC 디자인 패턴에서 모델은 여러분의 응용프로그램에서 특정 데이터를 캡슐화하고 그 데이터에 무언가를 수행하는 메소드를 제공해주는 객체입니다. 모델은 주로 영속적이지만, 모델은 그 데이터가 사용자에게 표시되는 방식에 의존해서는 안됩니다.

개체-관계 모델에서 모델은 개체라고 불리며 개체의 구성요소는 애트리뷰트라고 불리며 다른 모델로의 레퍼런스는 관계라고 불립니다. 애트리뷰트와 관계는 함께 프로퍼티로 알려져 있습니다. 이 세개의 단순한 구성 요소(개체, 애트리뷰트, 관계)로 어느 복잡한 시스템이든 모델화 할 수 있습니다.

예를 들어, 객체 모델은 회사의 고객층, 책의 라이브러리, 컴퓨터의 네트워크를 묘사하는데 사용되어질 수 있습니다. 라이브러리 책은 제목, ISBN 번호, 저작권 날짜와 같은 애트리뷰트와 저자, 라이브러리 멤버와 같은 다른 객체들과 관계를 가지고 있습니다. 이론적으로, 시스템의 일부를 정의할 수 있다면 시스템은 객체 모델로 표현될 수 있습니다.

Figure 4-7은 직원 관리 프로그램에서 사용되는 객체 모델의 예를 보여줍니다. 이 모델에서 Department는 부서를 모델링하고, Employee는 직원을 모델링합니다.

Figure 4-7 Employee management application object diagram

 

[편집] Attributes

애트리뷰트는 데이터를 포함하는 구조를 표현합니다. 객체의 애트리뷰트는 스칼라(integer, float, double)와 같이 단순한 값일 수 있으며, C 구조체(char의 배열이나 NSPoint), 혹은 원시 클래스(Cocoa의 NSNumber, NSData, NSColor)일 수도 있습니다. NSColor와 같이 불변하는 객체 역시 애트리뷰트로 여겨집니다. (Core Data는 "NSAttributeDescription"에서 설명된 것처럼 특정 애트리뷰트 타입만을 네이티브하게 지원합니다. 그러나 Core Data Programming Guide의 "Non-Standard Attributes" 에 설명된 대로 추가적인 애트리뷰트 타입을 사용할 수 있습니다.)

Cocoa에서 애트리뷰트는 일반적으로 모델의 인스턴스 변수나 액세서 메소드를 표시합니다. 예를 들어, Employee는 firstName, lastName, salary 인스턴스 변수를 가지고 있습니다. 직원 관리 프로그램에서, 테이블 뷰가 Employee 콜렉션 객체와 그들의 애트리뷰트 일부를 Figure 4-8에 나타난 대로 디스플레이하도록 구현할 수 있습니다. 테이블의 각각의 행은 Employee의 인스턴스에 해당하며 각각의 열은 Employee의 애트리뷰트에 해당합니다.

Figure 4-8 Employees table view 

 

[편집] Relationships

모델의 모든 프로퍼티가 애트리뷰트인 것은 아닙니다, 몇몇의 프로퍼티는 다른 객체에 대한 관계입니다. 여러분의 응용프로그램은 일반적으로 복수의 클래스로 모델링됩니다. 런타임시에, 여러분의 객체 모델은 객체 그래프를 구성하는 관련된 객체의 컬렉션입니다. 이들은 보통 여러분의 사용자가 생성하고 응용프로그램을 종료하기 이전에 어떤 데이터 컨테이너나 파일에 저장하는데(문서-기반 응용프로그램에서처럼) 사용하는 영속적인 객체입니다. 이런 모델 객체 간의 관계는 런타임시에 관련된 객체의 프로세스에 접근하기위해 찾아질 수 있습니다.

예를 들어, 직원 관리 프로그램에서, 종업원과 그들이 일하는 부서 간, 직원과 직원의 관리자 간의 관계가 있을 수 있습니다. 후자는 개체가 자기 자신과 관계를 만드는 재귀 관계의 예입니다.

관계는 본질적으로 양방향이기에 개념적으로는 적어도 부서와 그 부서에서 일하는 사람들 사이와 직원과 그들의 직속상관 사이의 관계가 있을 수 있습니다. Figure 4-9는 Department와 Employee 객체 사이의 관계와 Employee 객체의 재귀 관계를 묘사하고 있습니다. 이 예에서, Department 객체의 "employees" 관계는 Employee 개체의 "department" 관계와 반대입니다. 그러나, 관계가 반대 관계가 없기 때문에 단방향으로만 이동하도록 할 수 있습니다. 예를 들어, 부서 객체로부터 어느 직원이 관계되어 있는지 결코 관심이 없다면, 그 관계를 모델링할 필요가 없습니다. (일반적인 경우에 이것이 맞지만, Core Data는 일반적인 Cocoa 객체 모델링에 추가적인 제약을 부과할 수 있습니다. 반대 관계를 모델링하지 않은 것은 아주 고급 옵션으로 여겨야 합니다.)

Figure 4-9 Relationships in the employee management application

 

[편집] Relationship Cardinality and Ownership

모든 관계에는 카디널리티가 있습니다. 카디널리티는 (잠재적으로)얼마나 많은 목적 객체가 그 관계를 구축할 수 있는지 말해줍니다. 목적 객체가 하나라면, 관계는 대일 관계라고 불립니다. 만일 목적지에 하나 이상의 객체가 있다면 그 관계는 다대 관계라고 불립니다.

관계는 필수적이거나 선택적일 수 있습니다. 필수적인 관계는 목적지가 요구되는 관계에서 그렇습니다. 예를 들어 모든 직원은 반드시 한 부서와 연결되어야 합니다. 선택적인 관계는, 그 이름에서부터 알 수 있 듯, 선택적입니다. 예를 들어 모든 직원이 직접적인 상사가 없을 수 있습니다.

또한 카디널리티의 범위를 지정해 주는 것도 가능합니다. 선택적인 대일 관계는 0에서 1의 범위를 갖습니다. 직원은 어느 수의 상사든 가질 수 있으며 최소와 최대 범위를 지정해 줄 수 있습니다. 예를 들어 0-15의 범위를 지정해줄 수 있습니다. 이런 관계는 선택적인 다대 관계를 묘사합니다.

Figure 4-10은 직원 관리 프로그램의 카디널리티를 설명합니다. Employee 객체와 Department 객체 사이의 관계는 필수적인 대일 관계입니다. 직원은 반드시 하나, 그리고 오직 하나의 부서에만 속해야 합니다. Department와 거기 속한 Employee 객체의 관계는 선택적인 대다 관계("*"로 표시)입니다. 직원과 관리자 사이의 관계도 선택적인 대일 관계(범위 0-1)입니다. 최상위 직원들에게는 그들이 속한 관리자가 없습니다.

Figure 4-10 Relationship cardinality 

 

관계의 목적 객체 역시 때로 소유되고 공유됩니다.

[편집] Accessing Properties

모델, 뷰, 컨트롤러가 서로 독립적이기 위해서는 모델의 구현에 독립적인 방식으로 프로퍼티에 접근할 필요는 있습니다. 이것은 키-밸류 묶음을 이용해서 이루어집니다.

[편집] Keys

모델의 프로퍼티를 단순한 키, 보통 스트링을 이용해 지정합니다. 해당하는 뷰나 컨트롤러는 이 키를 사용해 해당 애트리뷰트 값을 찾습니다. "애트리뷰트의 값" 구축은 애트리뷰트 자체가 필수적으로 데이터를 포함할 필요 없이 간접적으로 값을 얻거나 부여받을 수 있다는 생각을 강화해줍니다.

키-밸류 코딩은 이런 룩업을 하는데 사용됩니다. 이것은 객체 프로퍼티에 간접적으로, 특정 컨텍스트에서는 자동으로 접근하는 기법입니다. 키-밸류 코딩은 객체 프로퍼티의 이름을 그들 프로퍼티(보통 그 인스턴스 변수나 액세서 메소드)의 개념에 접근하는 키로 사용하여 작동합니다.

예를 들어, Department 객체의 이름을 name 키를 사용하여 얻을 수 있습니다. 만일 Department 객체가 인스턴스 변수나 name 이라고 불리는 메소드를 가지고 있다면 그 키를 위한 값이 반환됩니다. (그렇지 않는다면, 에러가 발생합니다.) 비슷하게, Employee 애트리뷰트를 firstName, lastName, salary 키를 사용해 얻을 수 있습니다.

[편집] Values

주어진 개체의 특정 애트리뷰트의 모든 값은 동일한 데이터 타입입니다. 하나의 애트리뷰트의 데이터 타입이 해당하는 인스턴스 변수 선언부나 액세서 메소드의 리턴값에 지정됩니다. 예를 들어, Department 객체 name 애트리뷰트의 데이터 타입은 Objective-C의 NSString 객체일 수 있습니다.

키-밸류 코딩은 객체 값만 반환합니다. 만일 특정 키의 값을 제공하는데 사용되는 특정 인스턴스 변수의 데이터 타입이나 액세서 메소드의 리턴 타입이 객체가 아니라면 NSNumber 혹은 NSValue 객체가 그 값으로 생성되어 그 위치에 반환됩니다. 만일 Department의 name 애트리뷰트가 NSString 타입이라면, 키-밸류 코딩을 사용하여 Department 객체의 name 키에 반환되는 값이 NSString 객체입니다. 만일, Department의 budget 애트리뷰트가 float타입이면, 키-밸류 코딩을 사용하여 Department의 budget 키에 반환되는 값은 NSNumber 객체입니다.

비슷하게, 키-밸류 코딩을 이용하여 값을 설정할 때, 특정 키를 위한 적절한 액세서나 인스턴스 변수에 의해 요청된 데이터 타입이 객체가 아니라면 적절한 -<type>Value 메소드를 사용해 전달하는 객체로부터 값이 추출됩니다.

대일 관계의 값은 단순히 그 관계의 목적 객체입니다. 예를 들어, Employee 객체의 department 프로퍼티의 값은 Department 객체입니다. 대다 관계의 값은 그 관계의 목적 객체들을 포함하는 콜렉션 객체입니다.(배열이나 셋(set)일 수 있습니다. Core Data를 사용한다면 셋이고 그 외의 경우라면 배열입니다.) 예를 들어, Department 객체의 employees 프로퍼티의 값은 Employee 객체들을 포함하고 있는 콜렉션입니다. Figure 4-11에서 직원 관리 프로그램의 객체 그래프의 예를 보여주고 있습니다.

Figure4-11 Object graph for the employee management application 

 

[편집] Key Paths

키-패쓰는 객체 프로퍼티를 찾아가고자 하는 객체 프로퍼티의 시퀀스를 지정해주는 .으로 분리된 키 입니다. 프로퍼티의 첫번째 키는 이전의 프로퍼티에 의해 결정되며 각각 연속되는 키들은 이전 프로퍼티에 상대적으로 평가됩니다. 키 패쓰는 관련된 객체의 프로퍼티를 모델 구현과 상관없는 방식으로 지정할 수 있도록 합니다. 키 패쓰를 사용하여 객체 그래프를 통해 어느 깊이에 있건 상관없이 관련된 객체의 특정 애트리뷰트의 패쓰를 지정할 수 있습니다.

키-밸류 코딩 기법은 키-밸류 페어와 비슷하게 키-패쓰로 주어진 값 찾기를 구현합니다. 예를 들어, 어카운팅 프로그램에서 Employee 객체를 통해 Department의 이름에 접근할 때 department.name 키 패쓰를 사용할 수 있습니다. 이 경우에 department 는 Employee의 관계이며, name은 Department의 이름입니다. 키 패쓰는 목적 개체의 애트리뷰트를 표시하고자 할때 유용합니다. 예를 들어, Figure 4-12에 보이는 직원 테이블 뷰는 직원의 부서 객체 자체가 아니라 그 이름을 표시하도록 설정되어 있습니다. Cocoa 바인딩을 사용하여 "Department" 열의 값은 표시된 배열의 직원 객체의 department.name에 묶여 있습니다.

Figure 4-12  Employees table view showing department name

 

키 패쓰의 모든 관계가 값을 갖는 것은 아닙니다. 만일 직원이 CEO라면 manager 관계는 nil이 될 것입니다. 이런 경우 키-밸류 코딩 기법에 오류가 나진 않습니다. 그저 이 경로를 탐색하는 것을 멈추고 nil과 같이 적절한 값을 반환합니다.




덧글

  • 독립적인 아기백곰 2012/09/04 10:56 # 답글

    Objective-C 디자인 패턴 책을 보면서도 정리가 잘 안되었는데
    이 글을 보니 굉장히 많은 도움이 되었습니다.
    감사드립니다.
댓글 입력 영역