⚠️ 이번 글은 각 디자인 패턴에 대한 상세한 설명보다는 전체적인 내용 정리를 하는 글입니다. 각 패턴에 대해 자세히 알아보고 싶다면 아래쪽 '같이 보면 좋은 링크'를 참고해주세요.
헤드 퍼스트 디자인 패턴에 나오는 패턴을 총 정리 해보자. 디자인 패턴은 OOP에 기반을 두고 있다. 새 기능이나 개념이 필요하면 일단 객체나 인터페이스를 만드는 식이다.
A ⇢ B (점선 화살표): A가 B를 extends
혹은 implement
한다.
A ➔ B (실선 화살표): A가 B를 멤버(필드)로 갖는다.
원본 이미지 링크(github): broccolism/how-they-work/design_patterns.jpg
늘 그렇듯 무언가 범주화 하는 데에는 다양한 방식이 있다. 헤드 퍼스트 디자인 패턴 책에서 소개하는 방법은 아래 3가지 방법으로 분류하는 것이다. 책에 나와 있듯이 4가지로 분류하자는 의견, 완전히 다르게 분류해야 한다는 의견 등이 있지만 일단은 아래 범주로 나눠보자. (그리고 이렇게 나누면 글자수도 딱 맞아서 마음이 편안-해진다.)
설명만 보면 '그냥 객체 생성하고, 역할 정하고, 크게 더 붙이면 되는거 아닌가?' 라고 생각할 수도 있지만 디자인 패턴은 그 작업들을 어떻게하면 '잘' 할 지에 대한 것이다. 잘 한다는 것은...
... 등등 한번쯤 들어봤을만한 '좋은 설계'를 위한 원칙을 지키면서 구조를 만드는 것이다.
: 객체 생성과 관련된 패턴
- 객체를 생성하는 코드를 재사용할 수 있다. 복붙하지 않아도 된다는 뜻이다.
- 객체 생성 부분을 다른 로직과 분리하여 느슨한 결합을 달성할 수 있다.
PizzaStore
라는 Factory 인터페이스를 종류별 피자 가게가 구현하고, 각 피자 가게에서는 종류별 피자를 생성한다.Pizza
라는 Product 인터페이스를 구현한다.uniqueInstance
를 미리 만든 다음 그 객체와 생성자를 private하게 숨긴다.getInstance()
를 통해서만 얻을 수 있다.: 객체 간 역할(= 행동)을 정해주는 패턴
- 여러 클래스, 객체에 걸친 알고리즘을 패턴화한다.
- 누가 어떤 역할을 할 지 책임을 분리하는 것을 목적으로 한다.
notifyObservers()
를 호출해 변경이 발생했음을 알려준다.State.handle()
을 호출한다.hasNext()
, next()
등 새로운 접근 방식을 제공한다.Command
를 구현하는 커맨드 객체는 클라이언트의 요청을 의미한다.Receiver
리시버만 알고 있다. 따라서 커맨드를 실행해야 할 때는 커맨드 객체 내에서 receiver.action()
을 호출한다.command.execute()
을 호출한다.AbstractClass
에서는 전체 알고리즘의 뼈대를 잡는다. 개별 단계 중 일부가 항상 같은 동작을 해야 한다면 이곳에서 구현할 수도 있다.ConcreteClass
에서는 알고리즘 단계 중, 매번 바뀌는 부분을 구현한다.FlyBehavior
를 만들고 클라이언트는 이를 갖는다.FlyBehavior
를 구현하는 클래스에서 종류별 '날기' 동작을 정의할 수 있다.: 객체를 더 큰 구조로 만들기 위한 패턴
- 기존 구조를 크게 바꾸지 않고 객체와 클래스를 더 큰 구조로 조립한다.
- 전체 구조는 유연성이 있어야 하고 효율적이어야 한다.
Leaf
는 트리 구조의 리프 노드, Composite
는 내부 노드(internal node)를 의미한다. 이 둘은 같은 인터페이스를 구현하기 때문에 클라이언트에서는 객체 컬렉션과 개별 객체를 똑같이 다룰 수 있게 한다.Decorator
는 Component
를 구현하기도 하면서 필드로 가지고 있는다. ConcreteDecorator
에서 새로운 기능을 추가한다.RealSubject
로 들어오는 요청을 Proxy
가 가로챈 다음 RealSubject.request()
를 호출한다.Subject.request()
를 호출하기 때문에 이 사실을 알 수 없다.
- https://refactoring.guru/design-patterns: 각 디자인 패턴에 대한 설명, 코드 예시, 다이어그램.
다음 책은 뭘까요!?