따봉도치야 고마워

Head First Design Patterns : (13)실전에서의 디자인 패턴 본문

카테고리 없음

Head First Design Patterns : (13)실전에서의 디자인 패턴

따봉도치 2020. 10. 9. 16:19

디자인 패턴이란

  • 특정 컨텍스트 내에서 주어진 문제에 대한 해결책
  • 컨텍스트(context) : 패턴이 적용되는 상황, 반복적으로 일어날 수 있는 상황이어야 함
  • 문제(problem) : 그 컨텍스트 내에서 이루고자 하는 목적 / 컨텍스트 내에서 생길 수 있는 제약조건
  • 해결책(sloution) : 일련의 제약조건 내에서 목적을 달성할 수 있는 디자인

+ 포스(Force) = 문제 = 목적과 제약조건 (이 둘 사이에서 적절하게 균형을 잡아야 패턴의 해결책이 완성됨)

 


패턴 카탈로그

  • 패턴의 배경, 용도, 해결책, 결과 등이 모든 내용이 수록되어 있음 
  • ex. GOF의 디자인 패턴

디자인 패턴 분류

  • 점점 많은 디자인 패턴이 발견되면서 패턴을 그룹화해서 분류하게됨
  • 가장 유명한 분류 방법 : 용도에 따라 생성, 행동, 구조 세 가지 범주로 나누는 것
  1. 생성 관련 패턴(Creational Pattern) : 객체 인스턴스 생성을 위한 패턴, 클라이언트와 거기서 생성할 객체 인스턴스 사이의 연결을 끊어줌
  2. 행동 관련 패턴(Behavioral Pattern) : 클래스와 객체들이 상호작용하는 방법 및 역할을 분담하는 방법과 관련됨
  3. 구조 관련 패턴(Structural Pattern) : 클래스 및 객체들을 구성을 통해서 더 큰 구조로 만들 수 있게 해주는 것과 관련됨.

 

  생성 구조 행동
클래스 Factory Method Adapter(class) Template Method
Interpreter
객체 Singleton
Abstract Factory
Builder
Prototype
Adapter(object)
Composite
Decorator
Facade
Proxy
Flyweigth
Bridge
Iterator
Command
Strategy
State
Observer
Mediator
Visitor
Memento
Chain of Responsibility

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

+ 객체 패턴 : 객체 사이의 관계를 다룸. 보통 구성을 통해 정의되고 일반적으로 실행 중에 관계가 생성되어 더 동적이고 유연함

 

 

Q&A

Q. 다른 분류 방법은 없는지

  • 다른 분류 방법도 있음
  • 위의 3 가지 범주로 나눈 뒤 "분리 패턴" 같은 식으로 하위 범주로 다시 나누기도 함

 

Q. 데코레이터가 왜 구조 패턴인지? 행동을 추가하기 위한 건데 행동 패턴이 아닌지

  • GoF) 구조 패턴은 클래스와 객체가 새로운 구조와 기능을 만들어내기 위해 클래스와 객체를 구성하는 방법인데
  • 데코레이터는 한 객체를 다른 객체로 감싸 새로운 기능을 제공해주는 패턴이므로 행동 패턴의 용도인 상호작용보단 동적으로 새로운 기능을 얻는 쪽에 초점을 맞춤

 


패턴으로 생각하기

  1. 최대한 단순하게 : "어떻게 패턴을 적용할까" 가 아니라 "어떻게 하면 단순하게 해결할까"에 초점
  2. 패턴은 만병통치약이 아니다 : 패턴 사용 시 다른 부분에 대한 영향과 결과에 대해 주의
  3. 디자인상 문제에 적합하다는 확신 + 문제와 제약조건을 고려 + 추후 변경될 부분有 -> 디자인 패턴 적용
    • 더 간단한 해결책이 있다면 그것부터 사용해복
  4. 기대했던 유연성이 전혀 발휘되지 않는다면 과감하게 패턴 제거
  5. 꼭 필요하지 않은 패턴은 추가하지 말기

 

+ 패턴 관련 도서/문서 : GoF 디자인패턴, 포틀랜드 패턴 리포지토리, 힐사이드 그룹 등

 


안티 패턴

  • 어떤 문제에 대한 나쁜 해결책에 이르는 길을 알려줌
  • 어떤 이유로 나쁜 해결책에 유혹되는지, 장기적인 관점에서 나쁜 이유, 좋은 해결책을 위한 다른 패턴 제시 

 

객체지향 디자인 원칙 정리

  • 바뀌는 부분은 캡슐화 한다
  • 상속보다는 구성을 활용한다
  • 구현이 아닌 인터페이스에 맞춰 프로그래밍한다
  • 서로 상호작용을 하는 객체 간의 결합은 느슨하게 한다
  • 클래스는 확장에 대해서는 열려 있지만 변경에 대해서는 닫혀 있어야 한다 (OCP)
  • 추상화된 것에 의존하라. 구상 클래스에 의존하지 않도록 한다
  • 친한 친구들하고만 이야기한다
  • 먼저 연락하지 마세요. 저희가 연락 드리겠습니다
  • 어떤 클래스가 바뀌게 되는 이유는 한 가지 뿐이어야만 한다

 


부록) 기타 패턴

 

1. 브리지(Bridge) 패턴

  • 구현과 추상화된 부분(기능)을 서로 다른 클래스 계층구조로 나누는 패턴
  • 각각 독립적으로 확장이 가능하고 변경해도 클라이언트에 영향이 없음
  • 디자인이 복잡해진다는 단점
  • ex. 그래픽스, 윈도우 처리 + 구현부와 인터페이스를 서로 다른 방식으로 처리해야되는 경우

좌측이 기능부(추상화), 우측이 구현부

 


 

2. 빌더(Builder) 패턴

  • 복합 객체 생성을 캡슐화. 객체의 생성과 표현 방법을 분리하여 같은 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴
  • 여러 단계와 다양한 절차를 통해 객체 생성 (팩토리는 한 단계에서 처리), 팩토리보다 클라이언트에 대해 많이 알아야함
  • 제품의 내부 구조를 클라이언트로부터 보호
  • ex. 복합 객체 구조를 구축하기 위한 용도

 

+ 빌더와 팩토리의 차이  c10106.tistory.com/4399

 


 

3. 역할 사슬(Chain of Responsibility) 패턴

  • 명령 객체와 일련의 처리 객체(객체 사슬)를 포함하는 디자인 패턴
  • 사슬의 각 객체는 핸들러 역할을 하며, 주어진 요청을 처리할 수 있으면 처리하고, 그렇지 않다면 다음 객체에게 넘김
  • 클라이언트는 사슬의 구조를 몰라도 됨.
  • 사슬의 구조를 바꿔 역할을 동적으로 추가/제거 가능
  • 요청이 반드시 끝까지 수행된다는 보장이 없음
  • 실행 시에 과정을 살펴보거나 디버깅하기가 힘들 수 있음
  • ex. 윈도우 시스템에서 마우스 클릭이나 키보드 이벤트를 처리할 때 흔하게 쓰임

 


 

4. 플라이웨이트(Flyweight) 패턴

  • 동일하거나 유사한 객체들 사이에 가능한 많은 데이터를 서로 공유하여 사용하도록 하여 메모리 사용량을 최소화하는 패턴
  • 어떤 클래스의 인스턴스가 매우 많이 필요하지만 모두 같은 방식으로 제어할 때 사용
  • 여러 가상 객체들을 한 곳에 모아놓을 수 있고, 실행에 객체 인스턴스 개수를 줄여 메모리를 절약
  • 특정 인스턴스만 다른 식으로 행동하는 것은 불가능하다는 단점

 


 

 

5. 인터프리터(Interpreter) 패턴

  • 문법 및 구문을 번역하기 위한 인터프리터를 클래스로 표현
  • 언어를 쉽게 구현/변경/확장
  • 메소드만 추가하면 기타 기능(예쁘게 출력, 프로그램 확인 등)들을 쉽게 추가할 수 있음
  • ex. 간단한 언어(효율보단 단순함이 더 중요한)를 구현할 때 유용
  • 문법 규칙의 개수가 많아지면 아주 복잡해진다는 단점 -> 그럴 땐 파서/컴파일러 생성기 사용

 

 


 

6. 미디에이터(Mediator) 패턴

  • 어떻게 객체들의 집합이 상호작용하는지를 함축해놓은 객체를 정의
  • 시스템과 각 객체를 분리해 재사용성이 높아지고, 제어로직을 한 군데 모아 관리가 수월해짐
  • 객체 사이에 오가는 메시지의 종류도 줄이고 단순화 시킴
  • 잘못 디자인하면 미디에이터 객체 자체가 너무 복잡해질 수 있음
  • ex. 서로 연관된 GUI 구성요소들을 관리하기 위한 용도

 


 

7. 메멘토(Memento) 패턴

  • 객체를 이전 상태로 되돌릴 수 있는 기능을 제공하는 패턴 (상태 저장 + 객체의 캡슐화)
  • 저장된 상태를 핵심 객체와는 다른 별도의 객체에 보관하여 안전함
  • 복구 기능을 구현하기 쉽고, 데이터를 계속해서 캡슐화된 상태로 유지
  • 상태 저장/복구에 시간이 오래 걸릴 수 있다는 단점
  • 자바 시스템에서 시스템의 상태를 저장할 땐 직렬화를 사용하는 것이 좋음


 

8. 프로토타입(Prototype) 패턴

  • 원형이 되는(Prototypical) 인스턴스를 사용하여 생성할 객체의 종류를 명시하고, 그걸 복사해서 새로운 객체를 생성
  • 인스턴스를 만들 때 자원/시간을 많이 잡아먹거나, 복잡한 경우에 사용
  • 복잡한 클래스 계층구조에 묻혀 있는 다양한 형식의 객체 인스턴스를 새로 만들어야 하는 경우에 유용
  • 클라이언트에선 새로운 인스턴스를 만드는 복잡한 과정을 몰라도 됨
  • 때때로 복사본을 만드는 일이 매우 복잡한 경우가 있다는 단점
  • 팩토리 패턴과 반대 되는 개념 : 서브클래스 사용을 막음

 


 

9. 비지터(Visitor) 패턴

  • 알고리즘을 객체 구조에서 분리시키는 디자인 패턴
  • 구조를 수정하지 않고도 복합 객체 구조에 새로운 동작을 추가 (OCP)
  • 비지터에 관련 코드를 집중 시켜놓을 수 있음
  • 복합 클래스의 캡슐화가 깨지고, 컬렉션 내 모든 항목에 접근하기 위한 트래버서가 있어 복합 구조를 변경하기 더 어려워짐