본문 바로가기

- Programming/- 디자인 패턴

★ 2. 디자인 패턴 정리

반응형

디자인 패턴 정리


패턴은 특정 컨텍스트(패턴이 적용되는 상황. 반복적으로 일어날 수 있는 상황) 내에서 주어진 문제(해당 컨텍스트 내에서 이루고자 하는 목적 또는 제약 조건)에 대한 해결책(일련의 제약 조건 내에서 목적을 달성할 수 있는 일반적인 디자인)입니다.


"어떤 컨텍스트 내에서 일련의 제약 조건에 의해 영향을 받을 수 있는 문제에 봉착했다면, 그 제약조건 내에서 목적을 달성하기 위한 해결책을 찾아낼 수 있는 디자인을 적용한다."

1. 범주별 분류

※ 생성 관련 패턴(싱글턴, 추상 팩토리, 팩토리 메소드, 빌더, 프로토 타입)

객체 인스턴스 생성을 위한 패턴으로, 클라이언트와 그 클라이언트에서 생성해야 할 객체
인스턴스 사이의 연결을 끊어주는 패턴

※ 행동 관련 패턴(템플릿 메소드, 커맨드, 이터레이터, 옵저버, 스테이트, 스트래티지)

클래스와 객체들의 상호작용하는 방법 및 역할을 분담하는 방법과 관련된 패턴

※ 구조 관련 패턴(데코레이터, 컴포지트, 프록시, 퍼사드, 어댑터)

클래스 및 객체들을 구성을 통해서 더 큰 구조로 만들 수 있게 해주는 것과 관련된 패턴

2. 클래스, 객체 분류


※ 클래스 패턴(템플릿 메소드, 팩토리 메소드, 어댑터)


클래스 사이의 관계가 상속을 통해서 어떤 식으로 정의되는지를 다룬다. 클래스 패턴에서는 컴파일시에 관계가 결정

※ 객체 패턴(컴포지트, 데코레이터, 프록시, 스트래티지, 브리지, 퍼사드, 커맨드, 이터레이터, 옵저버, 프로토 타입, 스테이트, 추상 팩토리, 싱글턴)

객체 사이의 관계를 다루며, 객체 사이의 관계는 보통 구성을 통해서 정의.
객체 패턴에서는 일반적으로 실행 중에 관계가 생성되기 때문에 더 동적이고 유연함

3. 패턴으로 생각하기

※ 최대한 단순하게

"이 문제에 어떤 패턴을 적용할까?"가 아닌 "어떻게 하면 단순하게 해결할 수 있을까?"에 초점.
가장 단순하고 유연한 디자인을 만들기 위해서 패턴을 사용해야 한다면 그때 패턴을 적용하면 된다.

※ 디자인 패턴은 만병 통치약이 아니다

패턴을 사용할 때는 그 패턴을 사용했을 때 설계한 디자인의 다른 부분에 미칠 수 있는 영향과 결과에
대해 주의 깊게 생각해봐야한다.

※ 패턴이 필요한 경우

- 구상중인 디자인상에 적용이 적합하다 확신이 드르 경우.
- 시스템의 어떤 부분이 변경될 것이라고 예측할 수 있는 경우.

※ 리팩터링과 패턴

행동이 아닌 구조를 개선하는데 목적

※ 패턴 제거

시스템이 점점 복잡해지면서 처음에 기대했던 유연성이 전혀 발휘되지 않게 되는 경우
패턴을 과감하게 제거해 버리는게 최선책일 수 있다. 즉, 패턴을 사용하지 않은 간단한
해결책이 더 나을 것 같다 싶을 때 패턴을 제거하면 된다.

※ 필요한 경우에만 적용하라

지금 당장 변화에 대처하기 위한 디자인을 만들어야 한다면 패턴을 적용해서 그 변화에 적응해야 한다.
하지만 꼭 필요하지 않음에도 불구하고 괜히 패턴을 추가하는 것은 피해야 한다.
괜히 시스템만 복잡해지고 사용률도 현저히 낮거나 없을 수 있다.

4. 패턴을 대하는 마음가짐

초보자들은 언제나 패턴을 사용하는 경향이 있다. 그 과정에서 패턴을 쓰는 연습을 하면서 다양한 경험을 쌓을 수 있는
측면에서는 좋다. 하지만 그러다보면 반드시 그렇지만은 않다는 것을 배우게 된다. 어떤 디자인이든 될 수 있으면 단순하게
만들어야 한다는 것을 터득하게 된다. 반드시 확장성이 필요한 경우에만 패턴을 써서 조금 복잡하게 만드는 것이 좋다.


경험이 늘어 중급자 수준에 오르게 되면 어떤 상황에서 패턴이 필요하고 어떤 상황에서 패턴이 필요하지 않은지를 파악할 수 있다.
여전히 잘 맞지 않는 패턴을 억지로 적용하려는 경향이 보이긴 하지만, 그 과정에서 정형적인 패턴이 적합하지 않은 상황에서는 패턴을
적당히 변형시켜서 써야 한다는 것을 깨닫게 된다.

달인의 경지에 오르면 패턴을 자연스럽게 구사할 수 있다. 더이상 패턴을 사용하는 것에 얽매이지 않는다. 문제를 가장 효과적으로
해결할 수 있는 해결책을 찾는데 주안점을 둘 뿐이다. 이는 객체지향 원칙들을 종합적으로 고려함이다. 자연스럽게 패턴이 필요한
상황에 이르면 패턴을 적당히 변형시켜서 적용한다. 그리고 달인들은 유사한 패턴 사이의 관계를 확실히 파악하여 관련된 패턴들의
용도 사이의 미묘하나 차이점을 잘 이해하고 활용한다. 달인의 마음 가짐은 초보자의 마음가짐이기도하다. 디자인 과정에서 의사 결정을
할 때 패턴에 대한 지식이 그리 큰 영향을 끼치지 않기 때문이다.

5. 패턴 정리



 패턴

설명 

 스트래티지

 교환 가능한 행동을 캡슐화하고 위임을 통해서 어떤 행동을 사용할지 결정한다.

 옵저버

 상태가 변경되면 다른 객체들한테 연락을 돌릴 수 있게 한다.

 데코레이터

 객체를 감싸서 새로운 행동을 제공한다.

 팩토리

 생성할 구상 클래스를 서브 클래스에서 결정한다.

 추상 팩토리

 클라이언트에서 구상 클래스를 지정하지 않으면서도 일군의 객체를 생성할 수 있도록 한다.

 싱글턴

 딱 한 객체만 생성되도록 한다.

 커맨드

 요청을 객체로 감싼다.

 어댑터

 객체를 감싸서 다른 인터페이스를 제공한다.

 퍼사드

 일련의 클래스에 대해서 간단한 인터페이스를 제공한다.

 템플릿 메소드

 알고리즘의 개별 단계를 구현하는 방법을 서브클래스에서 결정한다.

 이터레이터

 컬렉션이 어떤식으로 구현되었는지 드러내진 않으면서도 컬렉션 내에 있는 모든 객체에

 대해 반복 작업을 처리할 수 있게 한다.

 컴포지트

 클라이언트에서 객체 컬렉션과 개발 객체를 똑같이 다룰 수 있도록 한다.

 스테이트

 알고리즘의 개별 단계를 구현하는 방법을 서브클래스에서 결정한다.

 프록시

 객체를 감싸서 그 객체에 대한 접근을 제어한다.

 컴파운드

 반복적으로 생길 수 있는 일반적인 문제를 해결하기 위한 용도로 두 개 이상의 패턴을

 결합해서 사용하는 것

 브리지

 구현 뿐만 아니라 추상화된 부분까지 변경시켜야하는 경우

 빌더

 제품을 여러 단계로 나눠서 만들 수 있도록 제품 생산 단계들을 캡슐화할 때

 역할 사슬

 한 요청을 두 개 이상의 객체에서 처리하고 싶을 때

 플라이 웨이트

 어떤 클래스의 인스턴스 한 개만 가지고 여러 개의 "가상 인스턴스"를 제공하고 싶을 때

 인터프리터

 어떤 언어에 대한 인터프리터를 만들 때

 미디에이터 서로 고나련된 객체 사이의 복잡한 통신과 제어를 한 곳으로 집중시키고자 할 때
 메멘토 객체를 이전의 상태로 복구시켜야 하는 경우
 프로토 타입 어떤 클래스의 인스턴스를 만드는 것이 자원/시간을 많이 잡아먹거나 복잡한 경우
 비지터 다양한 객체에 새로운 기능을 추가해야 하는데 캡슐화가 별로 중요하지 않은 경우



반응형