1. 디자인 패턴의 개요

1.1. 디자인 패턴이란?

  • 디자인 패턴 (Design Pattern)
    • 소프트웨어 모듈의 세분화된 역할이나 모듈 간의 인터페이스 등을 설계할 때 참고할 수 있는 전형적인 해결 방식, 예제, 재사용 가능한 샘플 코드

1.2. 디자인 패턴의 주요 특징

  • “바퀴를 다시 발명하지 마라 (Don’t reinvent the wheel)”

    • 개발 중 문제가 발생했을 때 처음부터 새로운 해결책을 만들어내느라 시간을 낭비하지 말고,
    • 이미 검증된 디자인 패턴을 참고하여 적용하는 것이 훨씬 효율적이라는 의미이다.
  • 디자인 패턴 안에는 문제와 배경, 실제 적용 사례, 재사용 가능한 샘플 코드 등이 모두 담겨 있다.

  • 상황에 맞게 하나의 패턴을 변형하거나 요구사항을 반영해 다른 형태의 패턴으로 유연하게 변화시킬 수 있다.

1.3. GoF (Gang of Four)의 디자인 패턴

  • 탄생

    • 1995년 에릭 감마, 리차드 헬름, 랄프 존슨, 존 블리시디스 등 4명의 학자(GoF)가
    • 수많은 디자인 패턴 중 가장 보편적으로 적용할 수 있는 것들을 모아 처음으로 체계화했다.
  • 현재까지도 소프트웨어 공학 및 현업에서 가장 많이 사용되는 표준적인 디자인 패턴이다.

3. 디자인 패턴 사용의 장단점

3.1. 장점

  • 구조 파악 용이

    • 범용적인 코딩 스타일을 사용하므로 시스템의 구조를 쉽게 파악할 수 있다.
  • 생산성 향상

    • 객체지향 설계 및 구현의 생산성을 높이는 데 매우 적합하다.
  • 시간 및 비용 절감

    • 이미 검증된 패턴 구조를 재사용하기 때문에 개발에 드는 시간과 비용을 절약할 수 있다.
  • 원활한 의사소통

    • 개발자 간 공통된 패턴(언어)을 사용하므로 원활한 의사소통이 가능하다.
  • 유연한 대처

    • 요구사항이나 설계 변경 요청이 있을 때 유연하게 대처하고 수정할 수 있다.

3.2. 단점

  • 초기 투자 비용 부담

    • 요구사항을 직관적으로 바로 구현하는 것이 아니라 패턴에 맞춰 설계하고 구현해야 하므로 초기에 시간과 노력(투자 비용)이 많이 들 수 있다.
  • 객체지향에 국한됨

    • 객체지향을 기반으로 한 설계와 구현을 다루기 때문에, 다른 프로그래밍 패러다임 기반의 애플리케이션 개발에는 적합하지 않다.

4. 생성 패턴

  • 생성 패턴
    • 객체의 생성과 참조 과정을 캡슐화하여, 객체가 생성되거나 변경되더라도 프로그램 구조에 영향을 크게 받지 않도록 유연성을 더해주는 패턴

4.1. 싱글톤

  • 개념

    • 특정 클래스 내에서 인스턴스가 오직 하나뿐임을 보장하는 패턴
  • 특징

    • 생성된 하나의 객체를 어디서든 참조할 수 있다.
    • 여러 프로세스가 동시에 참조할 수 없다.
    • 불필요한 메모리 낭비를 최소화할 수 있다.

4.2. 팩토리 메서드

  • 개념

    • 상위 클래스에서는 인터페이스만 정의하고,
    • 실제 객체의 생성은 하위(서브) 클래스에서 담당하도록 분리하여 캡슐화한 패턴
  • 특징

    • 하위 클래스에서 어떤 객체를 생성할지 결정하므로,
    • ‘가상 생성자(Virtual Constructor)’ 패턴이라고도 부른다.

4.3. 추상 팩토리

  • 개념

    • 구체적인 클래스(하위 클래스)에 의존하지 않고,
    • 인터페이스를 통해 서로 연관되거나 의존하는 객체들을 그룹으로 묶어 추상적으로 표현하는 패턴
  • 특징

    • 연관된 서브 클래스 그룹을 묶어서 한 번에 교체하는 것이 가능

4.4. 빌더

  • 개념

    • 작게 분리된 인스턴스들을 건축하듯 차곡차곡 조합하여 하나의 객체를 생성하는 패턴
  • 특징

    • 객체의 생성 과정과 표현 방법을 분리한다.
    • 따라서 동일한 생성 과정(예: 인사말 생성)을 거치더라도 서로 다른 결과(영어, 중국어, 일어 등)를 만들어 낼 수 있다.

4.5. 프로토타입

  • 개념

    • 원본 객체를 복제(Copy)하는 방식으로 새로운 객체를 생성하는 패턴
  • 특징

    • 일반적인 방법으로 객체를 생성할 때 비용(시간, 리소스)이 매우 큰 경우에 주로 사용

5. 구조 패턴

  • 구조 패턴
    • 클래스나 객체들을 조합하여 더 큰 구조로 만들고,
    • 이를 통해 복잡한 시스템을 개발하기 쉽도록 돕는 패턴

5.1. 어댑터

  • 개념

    • 호환성이 없는 클래스들의 인터페이스를 다른 클래스가 이용할 수 있도록 변환해 주는 패턴
  • 특징

    • 기존의 클래스를 수정하지 않고 인터페이스를 맞춰준다.
    • (비유: 스마트폰 충전기 젠더)

5.2. 데코레이터

  • 개념

    • 객체 간의 결합을 통해 능동적으로 기능을 확장할 수 있는 패턴
  • 특징

    • 임의의 객체에 부가적인 기능을 추가하기 위해,
    • 기본 객체에 다른 객체를 덧붙이는(포장하는) 방식으로 구현

5.3. 브리지

  • 개념

    • 구현부에서 추상층(기능)을 분리하여,
    • 서로가 독립적으로 확장할 수 있도록 구성한 패턴
  • 특징

    • 기능과 구현을 서로 다른 별도의 클래스로 구현

5.4. 컴포지트

  • 개념

    • 단일 객체와 복합 객체를 구분 없이 동일하게 다루고자 할 때 사용하는 패턴
  • 특징

    • 폴더(디렉터리) 안에 또 폴더가 들어갈 수 있는 것처럼,
    • 객체들을 트리(Tree) 구조로 구성

5.5. 퍼싸드

  • 개념

    • 복잡한 하위(서브) 클래스들을 피하고,
    • 더 상위에 통합 인터페이스를 구성하여 서브 클래스들의 기능을 간편하게 사용할 수 있도록 하는 패턴
  • 특징

    • 서브 클래스들 사이의 통합 인터페이스를 제공하는 Wrapper(래퍼) 객체가 필요

5.6. 플라이웨이트

  • 개념

    • 인스턴스가 필요할 때마다 매번 새로 생성하는 것이 아니라,
    • 가능한 한 공유해서 사용함으로써 메모리를 절약하는 패턴이다.
  • 특징

    • 다수의 유사한 객체를 생성하거나 조작할 때 유용하며, 메모리 절약이 핵심 목적

5.7. 프록시

  • 개념
    • 접근이 어려운 객체(네트워크 연결, 대용량 객체 등)와 연결하려 할 때,
    • 해당 객체에 바로 접근하지 않고 대신 인터페이스 역할을 수행해 주는 패턴

6. 행동 패턴

  • 행동 패턴
    • 클래스나 객체들이 서로 상호작용하는 방법이나 책임을 분배하는 방법을 정의하는 패턴
    • 하나의 객체가 혼자 수행할 수 없는 작업을 여러 객체로 분배하여 객체 간의 결합도를 최소화하는 것이 목적

6.1. 11가지 행위 패턴 종류 및 특징

  1. 반복자

    • 개념: 자료 구조(배열 등)의 내부 표현을 노출하지 않고, 그 안의 객체들에 순차적으로 접근할 수 있게 해주는 패턴
  2. 상태

    • 개념: 객체의 내부 상태에 따라 동일한 동작을 다르게 처리해야 할 때 사용하는 패턴
    • (비유: 엄마의 기분 상태에 따라 용돈을 더 받거나 못 받는 상황)
  3. 옵서버

    • 개념: 한 객체의 상태가 변화하면, 그 객체에 상속(구독)되어 있는 다른 객체들에게 변화된 상태를 자동으로 전달하는 패턴
    • (비유: 단톡방에서 내가 메시지를 읽으면 다른 사람 화면의 안 읽음 숫자가 줄어드는 기능)

  1. 책임 연쇄 (Chain of Responsibility)

    • 개념: 요청을 처리할 수 있는 객체들을 고리(Chain)로 묶어, 한 객체가 처리하지 못하면 다음 객체로 책임을 넘기는 패턴
    • (비유: 책임을 다음 사람에게 넘기는 의리 게임)
  2. 커맨드 (Command)

    • 개념: 요청을 객체의 형태로 캡슐화하여 재이용하거나 취소할 수 있도록 하는 패턴
    • 요청에 필요한 정보를 저장하거나 로그에 남길 수 있다.
  3. 인터프리터 (Interpreter)

    • 개념: 특정 언어의 문법 표현을 정의하는 패턴
    • (비유: 맞춤법 검사기, SQL 구문 분석 등)
  4. 중재자 (Mediator)

    • 개념: 수많은 객체들 간의 복잡한 상호작용을 캡슐화하여, 객체들이 직접 통신하지 않고 중재자를 통해 통신하게 함으로써 결합도를 낮추는 패턴
    • (비유: 친구들 싸움을 말리고 의견을 조율하는 중재자)
  5. 메멘토 (Memento)

    • 개념: 특정 시점의 객체 내부 상태를 객체화하여 저장해 두었다가, 필요할 때 그 상태로 되돌릴 수 있게 하는 패턴
    • (비유: 실행 취소(Ctrl+Z), 되돌리기 기능)
  6. 전략 (Strategy)

    • 개념: 동일한 계열의 알고리즘들을 캡슐화하여, 클라이언트의 변경 없이 알고리즘을 서로 교환해서 사용할 수 있게 하는 패턴
  7. 템플릿 메서드 (Template Method)

    • 개념: 상위 클래스에서 알고리즘의 전체적인 골격(뼈대)을 정의하고, 하위 클래스에서 세부적인 처리를 구체화하는 패턴
    • 코드의 양을 줄이고 유지보수를 용이하게 한다.
    • (생성 패턴의 ‘팩토리 메서드’와 유사한 구조)
  8. 방문자 (Visitor)

    • 개념: 객체의 데이터 구조에서 처리 기능(연산)을 분리하여 별도의 클래스로 구성하는 패턴
    • 분리된 처리 기능은 각 클래스를 방문(Visit)하여 수행된다.