GoF의 디자인 패턴

GoF의 디자인 패턴

에릭 감마·리처드 헬름·랄프 존슨·존 블리시디스(GoF, Gang of Four)의 『GoF의 디자인 패턴 — 재사용성을 지닌 객체지향 소프트웨어의 핵심 요소』를 정리합니다. 오브젝트가 “객체에게 어떤 책임을 줄 것인가”, 리팩터링이 “굳은 코드를 어떻게 무를 것인가”였다면, 이 책은 그 사이에서 반복되는 해법의 이름입니다 — 앞선 설계자들이 같은 문제를 수십 번 만나며 다듬어 낸, 검증된 구조 23개.

이 서재는 책의 구성을 따라 이렇게 정리합니다.

  • 패턴 하나당 노트 하나. 서론과 문서 편집기 사례로 문을 열고, 생성·구조·행위 세 갈래의 패턴 23개를 각각 독립된 글로 다룬 뒤, 결론으로 닫습니다.
  • 각 노트는 패턴을 카탈로그가 아니라 이야기로 풉니다 — 어떤 코드가 아파서 이 패턴이 태어났는지(동기), 무엇을 주고받아 문제를 푸는지(구조), 그리고 그 대가는 무엇인지(결과).
  • 패턴의 본질은 코드 변형이므로, 문제 코드에서 패턴이 emerge하는 과정을 스텝 플레이어의 diff로 기록합니다.

패턴은 외우는 주문이 아니라 트레이드오프의 목록입니다. 그래서 모든 노트가 “이걸 쓰면 무엇이 유연해지고 무엇이 복잡해지는가”, “언제 써야 하고 언제 과용인가”를 끝까지 묻습니다.

Contents

  1. 01
    서론 — 디자인 패턴이란 무엇인가패턴은 맥락 속에서 반복되는 문제와 그 해법의 쌍이다. 이름·문제·해법·결과 네 요소로 기록되고, 생성·구조·행위 세 갈래로 묶인다. 이 책 전체를 관통하는 두 원칙 — 상속보다 합성, 구현이 아니라 인터페이스에 프로그래밍 — 을 먼저 세운다.
  2. 02
    사례 연구 — 문서 편집기를 짓는 여덟 패턴WYSIWYG 편집기 Lexi 하나를 지으며 일곱 개의 설계 문제를 만난다. 문서 구조·줄바꿈·테두리·룩앤필·창 시스템·실행 취소·철자 검사가 각각 다른 패턴을 부르고, 그 패턴들이 한 화면 위에서 서로 맞물려 돌아간다. 패턴은 홀로가 아니라 함께 일한다.
  3. 03
    생성 패턴 · 추상 팩토리(Abstract Factory)서로 어울려야만 하는 객체 여럿을 한 벌로 만들어야 할 때, 구체 클래스 이름을 코드에 박는 대신 '제품군을 만드는 공장'을 인터페이스 뒤에 숨긴다. 룩앤필 위젯 세트, DB 드라이버 세트처럼 '섞이면 안 되는 한 벌'을 통째로 갈아 끼우는 패턴.
  4. 04
    생성 패턴 · 빌더(Builder)복합 객체를 만드는 절차와 그 결과물의 표현을 떼어 놓는다. 같은 조립 순서로 RTF도, 평문도, TeX도 뽑아내고, 인자가 폭발하는 거대 생성자를 단계별 조립으로 길들인다.
  5. 05
    생성 패턴 · 팩토리 메서드(Factory Method)상위 코드는 전체 흐름은 알지만 어떤 구체 객체를 만들지는 모를 때, 생성을 추상 메서드로 비워 두고 서브클래스가 채우게 한다. 프레임워크가 '무엇을 만들지'의 결정을 사용자에게 위임하는, 확장점을 여는 패턴.
  6. 06
    생성 패턴 · 프로토타입(Prototype)만들 것을 클래스로 지정하지 않고, 이미 완성된 인스턴스 하나를 복제(clone)해 새것을 얻는다. 그래픽 에디터의 도형 팔레트처럼 '종류'가 런타임에 늘어나고, 각 종류가 미리 설정된 상태를 품고 태어나야 하는 자리의 패턴.
  7. 07
    생성 패턴 · 싱글턴(Singleton)어떤 클래스의 인스턴스가 딱 하나여야 하고, 그 하나에 어디서든 닿아야 할 때. 가장 짧게 배우고 가장 자주 후회하는 패턴 — 전역 상태라는 안티패턴적 성격을 정직하게 마주하고 DI라는 대안까지 저울에 올린다.
  8. 08
    구조 패턴 · 어댑터(Adapter)원하는 인터페이스와 이미 있는 클래스의 인터페이스가 어긋날 때, 기존 코드를 고치는 대신 둘 사이에 변환기 한 겹을 끼운다. 레거시·서드파티처럼 손댈 수 없는 클래스를 내 세계의 규격에 맞춰 재사용하는 패턴.
  9. 09
    구조 패턴 · 브리지(Bridge)추상(도형·리모컨)과 구현(플랫폼·기기)이 각각 독립적으로 늘어날 때, 둘을 상속으로 엮으면 조합의 수만큼 클래스가 폭발한다. 브리지는 구현을 인터페이스로 뽑아 합성으로 잇고, 두 축이 서로를 건드리지 않고 따로 자라게 한다.
  10. 10
    구조 패턴 · 컴포지트(Composite)그래픽 그룹·파일시스템·메뉴처럼 부분과 전체가 같은 트리를 이룰 때, 잎(개별 객체)과 가지(복합 객체)를 클라이언트가 구분해 다루면 곳곳에 if(폴더냐 파일이냐)가 번진다. 둘에게 같은 인터페이스를 씌워 하나처럼 재귀적으로 다루는 패턴.
  11. 11
    구조 패턴 · 데코레이터(Decorator)한 객체에 기능을 이것저것 덧붙이는데 그 조합이 자꾸 늘어날 때, 상속으로 조합마다 클래스를 만들면 클래스가 폭발한다. 같은 인터페이스로 원본을 감싸는 껍질을 겹겹이 씌워, 기능을 런타임에 동적으로 쌓는 패턴.
  12. 12
    구조 패턴 · 퍼사드(Facade)복잡한 서브시스템을 쓰려고 클라이언트가 부품 하나하나를 직접 알고 순서대로 조립해야 하면 결합이 폭발한다. 퍼사드는 그 앞에 단순한 통합 창구 하나를 세워 흔한 사용을 한 번의 호출로 만들되, 하위 부품에 직접 손대는 길은 막지 않는다.
  13. 13
    구조 패턴 · 플라이웨이트(Flyweight)문서의 글자 하나하나, 숲의 나무 하나하나를 전부 객체로 만들면 메모리가 폭발한다. 객체가 든 상태를 공유 가능한 본질(intrinsic)과 문맥별 부가(extrinsic)로 갈라, 본질만 공유하고 부가는 밖에서 넘겨 쓴다.
  14. 14
    구조 패턴 · 프록시(Proxy)실제 객체를 클라이언트가 곧바로 만지지 못하게, 같은 얼굴을 한 대리 객체가 앞에 서서 접근을 통제한다. 무거운 이미지를 볼 때가 돼서야 로딩하고(가상), 권한을 확인하고(보호), 원격 호출을 감추고(원격), 참조를 세는(스마트) — 실체로 가는 길목에 문지기를 세우는 패턴.
  15. 15
    행위 패턴 · 책임 연쇄(Chain of Responsibility)요청을 누가 처리할지 발신자가 콕 집으면 그 둘이 결합된다. 처리 후보들을 사슬로 엮어 요청을 흘려보내고, 각자 '내가 처리하거나 다음으로 넘긴다'만 판단하게 한다. 도움말 컨텍스트·승인 단계·필터 체인처럼 처리자가 런타임에 정해지는 자리의 패턴.
  16. 16
    행위 패턴 · 커맨드(Command)'무엇을 하라'는 요청 자체를 객체로 만든다. 버튼과 메뉴는 자기가 무슨 일을 시키는지 몰라도 되고, 요청이 값이 되면 실행 취소·재실행·큐·로그·매크로가 전부 열린다. 호출하는 쪽과 실제로 일하는 쪽을 떼어 놓는 패턴.
  17. 17
    행위 패턴 · 인터프리터(Interpreter)자주 되풀이되는 간단한 언어 — 불린식·정규식·계산식 — 를 만났을 때, 파싱 분기를 키우는 대신 문법 규칙 하나하나를 클래스로 만들어 문장을 트리로 세우고, 그 트리에게 스스로 해석하라고 시킨다. 문법이 곧 클래스 계층이 되는 패턴.
  18. 18
    행위 패턴 · 반복자(Iterator)리스트든 배열이든 트리든, 집합체의 내부 표현을 클라이언트에게 노출하지 않고 원소를 하나씩 훑는다. 순회하는 책임을 집합체에서 떼어 내 별도 객체(hasNext/next)에 맡기고, 같은 컬렉션을 여러 방식으로·동시에 훑게 하는 패턴.
  19. 19
    행위 패턴 · 중재자(Mediator)여러 객체가 서로를 직접 참조해 상호작용하면 관계가 다대다로 폭발한다. 대화상자의 위젯들, 관제탑과 항공기처럼 얽힌 협력을 중재자 하나로 모아, 각 동료는 서로가 아니라 중재자만 알게 만든다.
  20. 20
    행위 패턴 · 메멘토(Memento)실행 취소를 만들려면 객체의 이전 상태를 어딘가 저장해 두었다가 되돌려야 한다. 그런데 상태를 게터로 다 열어 꺼내면 캡슐화가 무너진다. 메멘토는 내부를 아무도 못 여는 '불투명한 상태 꾸러미'로 봉해, 캡슐화를 지키면서 상태를 저장·복원하는 패턴이다.
  21. 21
    행위 패턴 · 감시자(Observer)한 데이터가 바뀌면 그것에 매달린 여러 뷰·의존자가 함께 갱신돼야 한다. 이들이 서로 직접 알면 결합이 폭발한다. 감시자는 '변했다'는 사실만 방송하고, 관심 있는 쪽이 알아서 구독해 따라오게 만든다 — 그 대가로 갱신 순서와 갱신 폭풍, 구독 누수를 떠안는다.
  22. 22
    행위 패턴 · 상태(State)한 객체의 행동이 내부 상태에 따라 달라지고 그 상태들이 서로 얽혀 전이할 때, 메서드마다 커지는 상태 분기 대신 상태 하나를 객체 하나로 뽑는다. 주문 처리·TCP 연결·자판기처럼 '지금 어떤 상태냐'가 '무엇을 할 수 있느냐'를 결정하는 자리의 패턴.
  23. 23
    행위 패턴 · 전략(Strategy)하나의 일을 처리하는 방법이 여럿이고 자꾸 바뀔 때, if/switch로 분기를 늘리는 대신 각 알고리즘을 객체로 뽑아 갈아 끼운다. 결제·정렬·줄바꿈처럼 '무엇을 하느냐'는 같은데 '어떻게 하느냐'만 다른 자리의 패턴.
  24. 24
    행위 패턴 · 템플릿 메서드(Template Method)여러 절차가 큰 흐름은 똑같고 몇몇 단계만 다를 때, 그 흐름을 복제하는 대신 골격을 상위 클래스에 못 박고 달라지는 단계만 서브클래스에 비워 둔다. 데이터 파서·프레임워크 훅처럼 '순서는 고정, 내용은 가변'인 자리의 패턴.
  25. 25
    행위 패턴 · 방문자(Visitor)안정된 객체 구조(AST 노드, 파일 트리)에 새 연산을 자꾸 더해야 할 때, 연산을 각 노드에 흩뿌리는 대신 한 방문자 객체로 모은다. accept/visit의 더블 디스패치로 '노드 종류 × 연산'의 교차점을 해소하되, 연산 추가는 쉬워지고 노드 추가는 어려워지는 정확히 반대 방향의 트레이드오프를 산다.
  26. 26
    결론 — 패턴을 넘어서패턴이 준 것은 코드가 아니라 설계 어휘·재사용 가능한 해법·트레이드오프를 보는 눈이다. 23개를 관통한 두 원칙(상속보다 합성·인터페이스에 프로그래밍)을 다시 세우고, 패턴을 위한 패턴이라는 가장 흔한 실패를 정직하게 짚은 뒤, 리팩터링·안티패턴·언어 진화로 이어지는 길로 책을 닫는다.