디자인 패턴이란
반복적으로 일어나는 문제들에 대한 해법이다. 일반적으로 하나의 패턴에는 다음 4가지 요소가 들어있다.
- 패턴 이름 : 패턴의 이름.
- 문제 : 언제 패턴을 사용하는가.
- 해법 : 설계를 구성하는 요소들과 요소들 간의 책임, 협력관계 서술.
- 결과 : 패턴을 적용해 얻는 결과와 장단점.
이 책에서는 주로 C++을 사용하고 간간이 스몰토크로 만든 예제가 제시된다.
디자인 패턴 기술하기
디자인 패턴을 설명하는 템플릿들입니다.
- 패턴 이름과 분류
- 의도 : 뭘 하는 패턴인지?
- 다른 이름 : 별명
- 동기 : 설계 문제 제시. 어떻게 문제를 해결하는지 시나리오.
- 활용성 : 어떤 상황에 적용할 수 있는지.
- 구조 : 객체 모델링 기법, 상호작용 다이어그램을 사용해 클래스들을 시각적으로 표기.
- 참여자 : 패턴을 구성하는 클래스 또는 객체에 대한 설명.
- 협력방법 : 참여자들 간의 협력 관계 정의.
- 결과 : 이 패턴을 이용한 결과와 장단점.
- 구현 : 패턴 구현 시 주의점, 힌트, 기법 등.
- 예제 코드 : 실제로 어떻게 C++나 스몰토크를 사용해 구현할 수 있는가.
- 잘 알려진 사용 예 : 실제 시스템에서 찾아볼 수 있는 패턴들의 예.
- 관련 패턴 : 이 패턴과 관련된 다른 패턴. 그 패턴과의 차이점. 이 패턴에 사용된 다른 패턴.
부록 A : 이 책에서 사용된 용어 정리
부록 B : 책에서 사용한 부호 및 표기법 정리
부록 C : 예제에 사용된 코드 및 기본 클래스들.
디자인 패턴 카탈로그 & 카탈로그 조직화
패턴들의 이름과 의도만 정리. 목적(생성, 구조, 행동)과 범위(클래스, 객체)를 기준으로 조직화 함.
클래스 패턴은 클래스와 서브 클래스 간의 관련성을 다루는 패턴임.
객체 패턴은 객체 관련성을 다루는 패턴임. 런타임에 변경할 수 있으며 동적인 성격을 지님.
- 생성 패턴 : 객체의 생성 과정에 관여하는 패턴.
- 클래스
- 팩토리 메서드(Factory Method)
- 객체
- 추상 팩토리(Abstract Factory) : 구체적인 클래스를 지정하지 않고 관련성 있는 객체들을 생성하거나 서로 독립적인 객체들을 생성할 수 있는 인터페이스 제공.
- 빌더(Builder) :
- 원형(Prototype)
- 단일체(Singleton)
- 클래스
- 구조 패턴 : 클래스나 객체의 합성에 관한 패턴
- 클래스
- 적응자(Adapter,class) : 클래스의 인터페이스를 다른 인터페이스로 변환하는 패턴.
- 객체
- 적응자(Adapter,object) : 클래스의 인터페이스를 다른 인터페이스로 변환하는 패턴.
- 가교(Bridge) : 구현부에서 추상층을 분리해 독립적으로 변형할 수 있게 하는 패턴.
- 복합체(Composite)
- 장식자(Decorator)
- 퍼사드(Facade)
- 플라이급(Flyweight)
- 프록시(Proxy)
- 클래스
- 행동 패턴 : 클래스나 객체가 상호작용하는 방법과 책임을 분산하는 방법
- 클래스
- 해석자(Interpreter)
- 템플릿 메서드(Template Method)
- 객체
- 책임 연쇄(Chain of Resposibility)
- 명령(Command)
- 반복자(Iterator)
- 중재자(Mediator)
- 메멘토(Memento)
- 감시자(Observer)
- 상태(State)
- 전략(Strategy)
- 방문자(Visitor)
- 클래스
패턴들은 다른 패턴과 같이 사용되기도 하고, 어떤 패턴은 다른 패턴의 대안이 되기도 한다. 어떤 패턴은 의도가 다르지만 결과적으로 유사한 설계 구조를 만드는 패턴도 있다.
디자인 패턴을 이용해 문제를 푸는 방법
적당한 객체 찾기
객체지향 설계에서 객체를 분할하는 것은 가장 어렵고 중요한 부분이다.
대부분의 객체는 분석 모델에서부터 만들어진다. 그러나 설계 모델의 객체에는 배열, 리스트와 같이 구현에 가까운 클래스들도 있다.
실세계를 그대로 반영하는 모델링만 강조하면 현재의 실세계는 반영할 수 있지만, 미래의 실세계는 반영하기 힘들다. 추상화된 객체들을 추가해서 미래의 실세계도 반영할 수 있도록 해야한다.
이런 추상화된 객체들은 분석 단계에서는 식별하기 힘들고 설계를 해가면서 리팩토링 과정에서 천천히 찾아낼 수 있게 된다.
객체의 크기 결정
객체의 크기 결정도 디자인 패턴에서 답을 얻을 수 있다.
- 퍼사드 패턴 : 서브시스템을 객체로 표현.
- 플라이급 패턴 : 작지만 개수가 많은 객체들을 다루는 방법.
- 추상 팩토리, 빌더 패턴 : 다른 객체를 생성하는 객체 생성.
- 방문자, 명령 패턴 : 요청을 다른 객체가 처리하고 구현하도록 책임지는 객체 생성.
객체 인터페이스의 명세
- 객체가 선언하는 연산은 이름, 매개변수, 반환값을 명세하고, 이를 연산의 시그너처라고 한다.
- 객체의 모든 시그너처들을 인터페이스라고 한다.
- 특정 인터페이스를 타입이라고 한다. 예를 들어 Window 타입의 객체는 Window 인터페이스에 정의한 연산들을 모두 처리할 수 있다는 뜻.
- 다른 인터페이스를 포함하는 인터페이스를 서브타입이라고 한다.
- 다른 인터페이스가 포함하는 인터페이스를 슈퍼타입이라고 한다. 서브타입은 슈퍼타입을 상속한다고 한다.
- 외부에서 객체를 알 수 있는 방법은 인터페이스 밖에 없다.
- 동일한 인터페이스를 갖는 두 객체가 다른 구현을 가질 수 있다.
- 요청과 그 요청을 처리할 객체를 런타임에 결정짓는 것을 동적 바인딩이라고 한다.
- 객체는 동일한 인터페이스를 갖는 다른 객체로 대체할 수 있는데, 이것을 다형성이라고 한다.
디자인패턴은 인터페이스에 정의해야 하는 요소가 무엇인지, 어떤 종류의 데이터를 주고 받아야 하는지 식별하여 인터페이스를 정의하도록 도와준다. 메멘토 패턴은 객체에 두 개의 인터페이스를 정의하도록 규정한다. 사용자가 상태를 저장하고 복사할 수 있도록 해주는 인터페이스와, 원본 객체가 상태를 저장하고 검색하기 위해 사용하는 인터페이스이다.
디자인 패턴은 인터페이스 간의 관련성도 정의한다. 장식자, 프록시 패턴은 객체에게 장식자 객체나 프록시 객체의 인터페이스를 요청한다. 방문자 패턴은 방문자 객체가 방문하는 객체들의 인터페이스를 모두 반영하도록 한다.
객체 구현 명세하기
OMT(클래스 다이어그램)에 대한 설명. 기본적인건 제하고 평소에 기억하기 힘든 것만 정리함.
점선 화살표 : 클래스가 다른 클래스의 객체를 인스턴스화(객체 생성) 함. 화살표는 생성 당하는 쪽 클래스로 향함.
실선 화살표 : 한 클래스가 다른 클래스의 인스턴스에 대한 참조자를 가지고 있음.
다이아몬드 실선 화살표 : 집합관계. 소유하는 관계.
수직선, 삼각형 : 상속관계. 삼각형의 꼭지점이 부모 클래스.
이탤릭체: 추상클래스와 추상연산의 이름은 이탤릭체로 표기함.
믹스인 클래스 : 다른 클래스에게 선택적인 인터페이스 또는 기능을 제공하기 위한 클래스. 추상 클래스와 비슷함.
클래스 상속 대 인터페이스 상속
객체의 타입과 클래스는 조금 다르다. 객체의 클래스는 객체의 내부 구현을 정의하고, 객체의 타입은 객체가 응답할 수 있는 요청의 집합(인터페이스)을 정의한다. 하나의 객체가 여러 타입을 가질 수 있고, 다른 클래스의 객체들이 같은 타입을 가질 수 있다.
C++및 기타 몇몇 언어에서는 클래스와 타입, 이 둘을 구분하고 있지 않다.
즉 클래스 상속은 내부 구현을 공유받는 것이고, 인터페이스 상속은 어떤 객체가 다른 객체 대신 사용될 수 있는 경우를 지정하는 매커니즘이다.
구현에 따르지 않고, 인터페이스에 따르는 프로그래밍
- 사용자가 원하는 인터페이스를 그 객체가 만족하고 있는 한, 사용자는 그들이 사용하는 특정 객체 타입에 대해 알아야 할 필요가 없다.
- 사용자는 이 객체들을 구현하는 클래스를 알 필요가 없고, 단지 인터페이스를 정의하는 추상 클래스가 무엇인지만 알면 된다.
이렇게 하면 서브 시스템 간 구현 종속성이 없어진다. 즉 다음과 같은 개발 원칙이 나온다.
구현이 아닌 인터페이스에 따라 프로그래밍한다.
재사용을 실현 가능한 것으로
상속 대 합성
합성이란 객체에게 다른 객체를 참조하도록 하는 것이다. 이런 스타일은 객체가 다른 객체의 인터페이스만 볼 수 있기 때문에 내부가 보이지 않는다고 하여 블랙박스 재사용 이라고 하기도 한다. (클래스 상속은 화이트박스 재사용이라고 함.) 객체 합성은 클래스 상속과 달리 런타임에도 변경될 수 있다.
객체 합성이 클래스 합성보다 더 나은 방법이다.
상속과 합성은 적절히 조합되어야 한다.
위임
위임은 합성을 상속만큼 강력하게 만드는 방법이다. 위임은 두 객체가 하나의 요청을 처리하는 방식이다. 요청을 수신하는 객체가 요청을 처리하는 객체(위임자, delegate)에게 전달하는 방식이다.
위임의 장점은 런타임에 행동의 복합을 가능하게 한다는 것이다. 단점은 이런 동적이고 매개변수화된 소프트웨어는 이해하기가 어렵다는 것이다.
상속 대 매개변수화된 타입
C++의 템플릿을 말한다. 매개변수화된 타입은 행동을 복합할 수 있는 세 번째 방법임. (첫 번째는 상속, 두 번째는 합성)
클래스가 사용하는 타입을 변경하게 할 수 있다. 그러나 이 책에서는 매개변수화된 타입을 사용하지 않는다.
런타임 및 컴파일 타임의 구조를 관계짓기
코드 구조는 컴파일 타임에 결정되는 것이고, 런타임 구조는 실행 시간에 교류하는 객체들에 따라 달라질 수 있다. 즉 두 구조는 별개이다.
객체 관계 중에는 집합(aggregation)과 인지(acquaintance)가 있다. 집합은 한 객체가 다른 객체를 소유하고 책임지는 것이다. 인지는 한 객체가 다른 객체를 참조하는 것이다.
디자인 패턴을 고르는 방법
패턴의 의도
그림 1.1(p64)
설계에서 가변적인 부분.
'GOF의 DesignPattern' 카테고리의 다른 글
장식자 패턴 (0) | 2023.09.09 |
---|---|
3장 팩토리 메서드 패턴 (0) | 2023.03.02 |
3장 빌더 패턴 (0) | 2023.03.01 |
3장. 생성 패턴 & 추상 팩토리 패턴 (0) | 2023.02.27 |
2장 사례 연구: 문서 편집기 설계 (0) | 2023.02.25 |