디자인 패턴 간단하게 정리하기

서론

아래 내용은 헤드퍼스트 디자인 패턴(https://www.yes24.com/Product/Goods/108192370)

책을 읽고 간단하게 정리한 내용입니다.

디자인 원칙 모아보기

  • 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분과 분리한다.
  • 구현보다는 인터페이스 맞춰서 프로그래밍 한다.
  • 상속보다는 구성을 활용한다.
  • 상호작용하는 객체 사이에서는 가능하면 느슨한 결합을 사용한다.
  • 클래스는 확장에는 열려있어야 하지만 변경에는 닫혀 있어야 한다.
  • 의존성 뒤집기 원칙(Dependency Inversion Principle)
    • 추상화 된 것에 의존하게 만들고, 구상 클래스에 의존하지 않게 만든다.
  • 의존성 뒤집기 원칙을 지키는 가이드라인
    1. 변수에 구상 클래스의 레퍼런스를 저장하지 않는다.(new 연산자 사용을 하지 않도록 한다.)
    2. 구상 클래스에서 유도된 클래스를 만들지 않는다.(추상화된 것으로부터 클래스를 만든다.)
    3. 베이스 클래스에 이미 구현되어 있는 메소드를 오버라이드 하지 않는다. (베이스 클래스의 제대로 된 추상화를 위해)
  • 클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공한다.
  • 최소 지식 원칙 : 진짜 절친에게만 이야기해야 한다.
    • 가이드 라인(아래에 해당되는 경우에만 메소드 호출을 한다.)
      • 객체 자체
      • 메소드에 매개변수로 전달된 객체
      • 메소드를 생성하거나 인스턴스를 만든 객체
      • 객체에 속하는 구성 요소
  • 할리우드 원칙
    • 먼저 연락하지 마세요. 저희가 연락 드리겠습니다.
    • 저수준의 구성 요소가 시스템에 접속되어 있지만, 어떻게 구성 요소를 사용할 지는 고수준의 구성 요소에서 결정한다.
    • 저수준의 구성 요소가 고수준의 구성 요소를 호출할 수 없는게 아니다. 결국 순환 의존성(고->저->고->저..)이 생기지 않도록 하는게 중요하다.
  • 단일 책임 원칙
    • 어떤 클래스가 바뀌는 이유는 하나 뿐이어야 한다.
    • 하나의 클래스는 하나의 역할을 맡아야 한다.

전략 패턴

디자인 원칙

  • 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분과 분리한다.
  • 구현보다는 인터페이스 맞춰서 프로그래밍 한다.
  • 상속보다는 구성을 활용한다.

기본 개념

  • 알고리즘군을 정의하고 캡슐화 해서 각각의 알고리즘 군을 수정해서 쓸 수 있게 한다.
  • 알고리즘에 해당하는 부분을 분리/독립하여 변경 및 사용할 수 있다.

개념 적용하기

  • 일반적인 클래스를 설계할 때, 기본이 되는 클래스(제일 하단)를 정의하고 그에 맞게 부수적으로 나오는 Act에 대한 부분을 기본 클래스에서 분리하여 사용하게끔 작성한다.
  • 업무에서의 잔고관리에 해당하는 부분으로 살펴보면, 잔고를 관리하는 메인 테이블 객체가 있고, 해당 테이블에 CRUD하는 메소드가 있는 클래스가 기본으로 정의되어 있고, 업무에 따라(적요입출고, 대체입출고 등) CRUD 시, 변경하는 부분(금액 계산, 잔고 계산 등)이 존재하는 메소드를 따로 빼서 관리하도록 설계하는게 전략 패턴에 맞는 패턴이라 볼 수 있다.

옵저버 패턴

디자인 원칙

  • 상호작용하는 객체 사이에서는 가능하면 느슨한 결합을 사용한다.

기본 개념

  • 특정 데이터를 관리하는 주체가 있고, 이를 관찰/구독 하는 옵저버(Observer)가 존재하여 데이터의 변경이 있을 때 마다 데이터를 전달받아 처리하는 방식.
  • 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에 연락이 가고, 자동으로 내용이 갱신되는 방식으로 일대다 의존성을 정의한다.

구조

  • Subject
    • 주제에서는 자신을 구독하는 옵저버들을 관리할 수 있는 메소드가 존재해야 한다.
  • Observer
    • 옵저버에서는 자신이 구독한 주제에 대한 데이터를 가져와 업데이트 할 수 있도록 해야 한다.
  • Subject 구현 클래스
    • 주제를 구현한 실제 클래스에서는 옵저버 관리 메소드를 구현하고, 데이터가 변경 될 때마다 옵저버들에게 데이터를 전달하도록 구현한다.
  • Observer 구현 클래스
    • 옵저버를 구현한 실제 클래스에서는 어떤 주제에 대해 구독할 것인지 판단 및 구독 할 수 있게끔 구현해야 한다.
    • 필요한 데이터를 주제에게 수동적으로 받는 Push 방식과 필요한 데이터를 주제에게 능동적으로 가져오는 Pull 방식 중 선택하여 구현한다.

데코레이터 패턴

디자인 원칙

  • 클래스는 확장에는 열려있어야 하지만 변경에는 닫혀 있어야 한다.

기본 개념

  • 데코레이터의 슈퍼 클래스는 자신이 장식하고 있는 객체의 슈퍼클래스와 같다.
  • 한 객체를 여러 데코레이터로 감쌀 수 있다.
  • 데코레이터는 자신이 장식하고 있는 객체에게 어떤 행동을 위임하는 일 말고도 추가 작업을 할 수 있다.
  • 언제든지 감쌀 수 있으므로 실행 중에 필요한 데코레이터를 마음대로 적용할 수 있다.

구조

Untitled

  • 추상 구성 요소로 돌아가는 코드에 해당 패턴을 적용해야 한다.
  • 추상 클래스를 상속받는 데코레이터 클래스를 만들고 데코레이터에서 상속받은 객체의 행동에 작업을 추가하여 구현 한다.

팩토리 패턴

디자인 원칙

  • 의존성 뒤집기 원칙(Dependency Inversion Principle)
    • 추상화 된 것에 의존하게 만들고, 구상 클래스에 의존하지 않게 만든다.
  • 의존성 뒤집기 원칙을 지키는 가이드라인
    1. 변수에 구상 클래스의 레퍼런스를 저장하지 않는다.(new 연산자 사용을 하지 않도록 한다.)
    2. 구상 클래스에서 유도된 클래스를 만들지 않는다.(추상화된 것으로부터 클래스를 만든다.)
    3. 베이스 클래스에 이미 구현되어 있는 메소드를 오버라이드 하지 않는다. (베이스 클래스의 제대로 된 추상화를 위해)

기본 개념

  • 객체 생성을 캡슐화 하는 것이 핵심이다.
  • 객체를 생성할 때 필요한 인터페이스를 만든다.
  • 어떤 클래스의 인스턴스를 만들지는 서브 클래스에서 결정한다.
  • 객체 생성과 관련된 내용들을 전부 한 곳으로 모은다.

팩토리 메소드 패턴

  • 상속을 활용하여 객체의 생성을 서브 클래스에게 맡긴다.
  • 서브 클래스는 팩토리 메소드를 구현해서 객체를 생산한다.

사용 방법

  • 객체를 생성하는 인터페이스 작성.
  • 서브 클래스에서 인터페이스를 구현하고, 객체를 생성하도록 한다.

추상 팩토리 패턴

  • 객체 구성을 활용하여 팩토리 인터페이스에서 선언한 메소드에서 객체 생성이 구현된다.
  • 구상 클래스에 의존하지 않고도 서로 관련된 객체로 이루어진다.

사용 방법

  • 추상 인터페이스를 작성.
  • 해당 인퍼페이스를 구현하는 서브클래스에서 객체를 생성한다.
  • 해당 객체 구현하는 생성자는 추상 팩토리를 구현한 팩토리 객체를 넘겨받아 생성한다.

싱글톤 패턴

디자인 원칙

  • 클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공한다.

기본 개념

  • 하나의 인스턴스만 만들고 추가로 생성하지 못하게 해야 한다.
  • 인스턴스가 필요한 경우 자기 자신을 거치도록 해야 한다.

문제 및 해결 방법

  • 멀티 스레딩에서의 문제점
    • synchronized 키워드 사용.
    • 정적 초기화 부분에서 인스턴스를 바로 생성.
    • DCL(Double-Checked Locking) 사용.
      • volatile 키워드를 사용하여 인스턴스 변수 선언.
      • (null chk -> synchronized -> null chk)

사용 방법

  • 하나의 인스턴스를 담을 변수를 private static 으로 내부에 선언한다.
  • 생성자를 private로 선언한다.
  • public getInstance() 정적 메소드를 통해 객체를 제공한다.

왜 enum 클래스가 완벽한 싱글턴 인가?

  • enum class는 외부에서 인스턴스화 할 수 있는 생성자 자체가 없다. 다만, 내부에서 관리되는 상수를 생성하는 생성자는 존재한다.
  • enum 타입은 기본적으로 직렬화 가능하므로 Serializable 인터페이스를 구현할 필요가 없고, 리플렉션 문제도 발생하지 않는다.
  • 인스턴스가 JVM 내에 하나만 존재한다는 것이 100% 보장 되므로, Java에서 싱글톤을 만드는 가장 좋은 방법으로 권장된다.

참고 : https://dataportal.kr/54https://scshim.tistory.com/361

커맨드 패턴

기본 개념

요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 따라 매개변수화 할 수 있다.

  • 작업을 요청하는 객체와 수행하는 객체를 분리한다.
  • Invoker, Receiver 를 통한 작업을 수행한다.
    • invoker : 어떤 작업을 수행할 지 가지고 있다가 Receiver 에게 넘겨준다.
    • receiver : invoker 가 전달해준 작업을 실제 수행한다.
  • command 객체를 배열로 가지거나, 작업을 취소하는 Undo Commnad 저장 객체를 가지는 등의 구조적인 변경이 가능하다.
  • 스택이나 큐를 통해 커맨드의 저장 공간을 정의함으로써 특정 작업의 수행이 가능하다.

구현 방법

Untitled

  1. 커맨드 인터페이스를 생성한다.
  2. 해당 인터페이스를 구현하는 구상 커맨드 클래스를 생성한다.
    • 해당 구상 클래스에는 특정 작업을 수행하는 리시버의 메소드를 호출하여 작업을 수행하는 execute()가 존재한다.
  3. 커맨드 객체를 인보커에게 전달한다.
  4. 인보커는 해당 커맨드 객체를 execute() 하여 리시버의 메소드를 실행시켜 작업을 수행한다.

인보커는 커맨드를 세팅하는 친구(setCommand), 리시버는 받아서 처리하는 친구(실제 작업을 수행하는)

객체 어댑터 패턴

기본 개념

  • 특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환한다.
  • 같이 쓸 수 없었던 클래스를 사용할 수 있게 도와준다.
  • 객체 구성(클래스가 다른 클래스의 객체를 멤버 데이터로 포함하는 기능)을 통해 어댑티에 요청을 전달한다.

구현 방법

Untitled

  1. 타겟 인터페이스를 구현하는 어댑터를 생성한다.
  2. 수신 객체(파라미터)는 기존 클래스이며, 어댑터가 감싸는 형태로 구현된다.
  3. 타겟 인터페이스에 있는 메소드를 모두 구현하는데 메소드 내부 기능은 모두 기존 객체에게 요청한다.

용어 설명

  • 어댑터 : 타겟 인터페이스를 구현한 클래스
  • 어댑티 : 수신 받는 기존 객체, 어댑터에 인스턴스가 들어있다. 내부 기능 구현 시, 요청을 받는다.

클래스 어댑터 패턴

기본 개념

  • 타겟과 어댑티 모두 서브클래스로 만들어 사용한다.
  • 타겟과 어댑티 모두를 확장한 클래스이기에 타겟 메소드 호출을 가로채 어댑티의 메소드 호출로 변환한다.

구현 방법

Untitled

  • 자바에서는 다중 상속이 불가능해서 사용 못한다.
    1. 타겟과 어댑티 클래스를 둘 다 상속받는 어탭터를 생성한다.
    2. 구현하고자 하는 메소드 내부에서 양쪽 클래스 메소드를 사용할 수 있어 취사 선택하여 구현한다.
    3. Target 클래스가 필요한 곳에서도 사용 될 수 있고 Adaptee 클래스가 필요한 곳에서도 사용 될 수 있게 한다.

퍼사드 패턴

기본 개념

  • 서브 시스템에 있는 일련의 인터페이스를 통합 인터페이스로 묶어준다. 또한 고수준의 인터페이스도 정의하므로 서브시스템을 더 편리하게 사용할 수 있다.
  • 인터페이스를 단순하게 만들고 클라이언트와 구성 요소로 이루어진 서브 시스템으로 분리하는 역할을 한다.
  • 여러 개의 클래스를 감쌀 수 있으나, 인터페이스를 단순하게 만드는 용도로 사용한다.

구현 방법

Untitled

  1. 퍼사드 클래스에는 사용하고자 하는 서브 시스템의 모든 구성요소가 인스턴스 변수로 가지고 있어야 한다.
  2. 퍼사드의 생성자에 서브시스템 구성 요소의 레퍼런스가 전달된다.(구성 서브 시스템 전부)
  3. 서브 시스템 인스턴스를 조합하여 단순화된 인터페이스를 만든다.(여기서 인터페이스는 인터페이스 클래스가 아닌 일반 인터페이스를 말한다.)
  4. 작업은 서브 시스템에 있는 구성요소에게 위임된다.

템플릿 메소드 패턴

디자인 원칙

할리우드 원칙

  • 먼저 연락하지 마세요. 저희가 연락 드리겠습니다.
  • 저수준의 구성 요소가 시스템에 접속되어 있지만, 어떻게 구성 요소를 사용할 지는 고수준의 구성 요소에서 결정한다.
  • 저수준의 구성 요소가 고수준의 구성 요소를 호출할 수 없는게 아니다. 결국 순환 의존성(고->저->고->저..)이 생기지 않도록 하는게 중요하다.

의존성 뒤집기와는 다른점?

  • 추상화를 되도록 사용하자는 의존성 뒤집기, 다른 클래스가 너무 구성 요소에 의존하지 않게 해주는 할리우드 원칙.
  • 객체를 분리한다는 점에서는 공통 목표를 공유하지만 세부 내용은 다르다.

기본 개념

  • 알고리즘의 골격을 정의하여, 일부 단계는 서브 클래스에서 구성할 수 있고 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브 클래스에서 재정의 할 수 있게 한다.(고수준 구성에서 추상 메소드 선언 -> 서브 클래스에서 구현)

장점

  • 알고리즘 독점
  • 서브 클래스에서 코드를 재사용
  • 유지보수 용이
  • 프레임워크를 제공 > 다른 클래스가 추가되어도 문제 없다!
  • 일부 구현만 서브클래스에서 의존한다.

구현 방법

Untitled

  1. 추상 클래스를 선언하고 알고리즘을 수행할 메소드를 선언한다.(final void)
  2. 해당 메소드 내에는 알고리즘에서 공통적으로 수행하는 메소드가 정의되어 있다.
    • 여러 요소에서 동일한 동작을 하는 일반 메소드, 템플릿 메소드 클래스 내에서 직접 구현한다.
    • 여러 요소마다 다른 동작을 하는 추상 메소드, 템플릿을 가져가는 서브 클래스에서 구현하여 사용한다.
  3. 서브 클래스(해당 템플릿을 가져가 확장하는 클래스) 에서는 일부 구현되지 않은 단계(추상 메소드로 정의된 것)를 구현하여 자기에 맞게 사용하도록 한다.

후크(Hook)

템플릿 메소드에서 내용이 별게 없는 메소드를 구현해 놓는다. 이를 서브 클래스에서 가져다가 입맛에 맞게 구현한다. 내용이 별게 없으므로(return true; 만 있거나 내용이 없는) 구현하지 않고 수행해도 크게 상관이 없다.

이를 통해 사용자의 입력을 받거나 조건을 통해 실행여부를 결정하여 사용한다.

비슷한 패턴과의 비교

  • 템플릿 메소드 패턴 : 알고리즘의 어떤 단계를 구현하는 방법을 서브 클래스에서 결정한다.
  • 전략 패턴 : 바꿔 쓸 수 있는 행동을 캡슐화 하고, 어떤 행동을 할 지는 서브 클래스에 맡긴다.

반복자 패턴

디자인 원칙

단일 책임 원칙

  • 어떤 클래스가 바뀌는 이유는 하나 뿐이어야 한다.
  • 하나의 클래스는 하나의 역할을 맡아야 한다.

기본 개념

  • 컬렉션의 구현 방법을 노출하지 않으면서 집합체 내의 모든 항목에 접근하는 방법을 제공한다.
  • 각 항목에 접근하는 기능을 집합체가 아닌 반복자 객체가 책임 진다.
  • 각자 자신이 맡은 일에만 집중할 수 있게 한다.

구현 방법

Untitled

  1. 서로 다른 객체를 통합하는 인터페이스를 만든다.
  2. 해당 인터페이스에서는 자신을 구현하는 객체의 컬렉션에 접근하여 요소를 제공하는 “반복자” 객체를 제공하여야 한다.
  3. 클라이언트에서는 서로 다른 객체에서 반복자 객체를 제공받아 요소를 접근하여 원하는 작업을 수행한다.

응집도(cohesion)

한 클래스 또는 모듈이 특정 목적이나 역할을 얼마나 일관되게 지원하는가에 대한 척도. 응집도가 낮다 = 서로 연관 없는 기능이 묶여있다. 응집도가 높다 = 서로 연관된 기능이 묶여있다. 응집도는 올리고, 결합도는 낮추어야 한다.

컴포지트 패턴

기본 개념

Untitled

  • 객체를 트리구조로 구성하여 부분-전체 계층 구조를 구현한다.
  • 클라이언트에서 개별 객체와 복합 객체를 똑같은 방법으로 다룰 수 있게 한다.

구현 방식

  1. 계층 구조를 갖는 부모와 자신의 통합 인터페이스(또는 추상 클래스)를 정의한다. 여기에는 부모와 자식 객체에서 사용하는 모든 메소드가 정의되어있다. (기본적으로 모든 메소드를 정의하면서 예외를 던지게하면 구현 클래스에서 부모/자식에 맞게 메소드를 가져와 구현하여 사용할 수 있다.)
  2. 클라이언트에서는 해당 통합 인터페이스를 구현한 객체를 가져와 사용한다. 사용할 때는 부모와 자식 객체 상관없이 동일한 메소드를 이용해 사용한다.

단일 책임 원칙을 깨는 컴포지트 패턴?

  • 투명성을 확보하는 패턴, 어떤 객체가 복합객체 인지 아닌지를 투명하게 알 수 있다.
  • 상황에 따라 원칙을 적절하게 사용해야 하는 것이지, 무조건 지켜야하는 것이 아니다.

상태 패턴

기본 개념

Untitled

  • 객체의 내부 상태가 바뀜에 따라 객체의 행동을 바꿀 수 있다.
  • 객체의 클래스과 바뀌는 것과 같은 결과를 얻을 수 있다.
  • 상태를 단순히 상수로 선언하는 것이 아닌, 캡슐화를 한다.
  • 전략 패턴과 비슷해보이지만, 용도가 다르다.

핵심 정리

  • 내부 상태를 바탕으로 여러 가지 서로 다른 행동을 할 수 있다.
  • 각 상태를 클래스로 표현한다.
  • Context 객체는 현재 상태에게 행동을 위임한다.
  • 각 상태를 클래스로 캡슐화함으로써, 나중에 변경해야 하는 내용을 국지화할 수 있다.
  • 내부 상태가 바뀜에 따라 객체가 알아서 행동을 바꿀 수 있도록 한다.
  • 상태 전환은 State 클래스로 제어할 수도, Context 객체에서 행동을 바꿀 수도 있다.
    • 상태 전환이 고정되어 있다면, Context 객체 내에서 전환해도 된다.
    • 상태 전환이 동적으로 결정된다면 상태 클래스 내에서 하는 것이 좋다.(그러나 상태 클래스 사이에 의존성이 생긴다.)
  • 여러 Context 객체 인스턴스에서 공유하도록 디자인 할 수도 있다.

전략 패턴과 다른 이유?

  1. 전략 패턴에서는 어떤 객체를 사용할 지 지정하고 사용한다.(행동을 알고리즘화 하여 필요한 것을 취사선택한다.)
  2. 상태 패턴은 객체의 상태에 따라 어떤 특정 객체에게 모든 행동을 위임한다.(미리 정한게 아닌, 상태에 따라 알아서 바뀔 수 있다.)

설계 방식

  1. 상태의 기본 골조로 사용할 인터페이스/추상 클래스를 선언한다.
    • 모든 상태는 이 베이스를 기준으로 구현된다.
  2. 상태를 구현하는 클래스에서는 상태 기반으로 행동할 메소드를 정의한다.
    • 기존 IF 반복 구문으로 상태에 따라 처리하던 메소드들이 각 상태의 메소드로 빠지게 된다.
  3. 상태를 관리하는 Context 객체에서는 구현된 상태 외에 현재 상태를 저장할 상태 객체를 갖는다.
    • 현재 상태 저장 객체는 당연히, 구현된 상태 클래스들과 동일한 인터페이스/추상 클래스를 베이스로 한다.
    • 이 상태 객체에 현재 상태를 저장함으로써, 구현한 상태에 맞는 행동을 수행할 수 있다. (OCP; 각 상태를 변경에는 닫혀있지만, 확장에는 열려있게 했다.)
  4. Context 객체에서 프로세스를 진행하며 상태를 변경해가며 행동을 수행한다.

프록시 패턴

기본 개념

Untitled

  • 특정 객체로의 접근을 제어하는 객체를 제공한다.
  • 예를 들면, 원격 객체/보안이 중요한 객체/생성하기 힘든 객체 등에 대해 접근하는 객체를 제공한다.

핵심 정리

  • 원격 프록시와 가상 프록시
    • 원격 프록시는 객체를 호출하여 실제 객체의 메소드가 호출된다.
    • 가상 프록시는 진짜 객체를 호출하기 전 최대한 미룬다. 실제 객체 생성 전이나 도중에 역할을 대신하기도 한다.
  • 동적 프록시
    • 즉시 하나 이상의 인터페이스를 구현하고, 지정한 클래스에 메소드 호출을 전달하는 프록시 클래스.
    • 핸들러를 통해 프록시의 호출을 가로채 행동 및 접근을 제어할 수 있게 만든다.
  • 보호 프록시
    • 특정 객체에 대한 접근을 제어한다.
  • 캐싱 프록시
    • 객체에 대한 요청을 캐싱하여 가지고 있으며 응답하다가, 새로운 요청에 의해 비로소 객체에 접근하거나 호출.

비슷한 패턴

프록시 패턴 -> 다른 객체를 감싸서 “접근을 제어”

  • 데코레이터 : 다른 객체를 감싸서 새로운 행동을 추가.
  • 퍼사드 : 여러 객체를 감싸서 인터페이스를 단순하게.
  • 어댑터 : 다른 객체를 감싸서 다른 인터페이스를 제공.

설계 방법

  1. 프록시와 원래 객체 간 상호 교환이 가능하도록 서비스 인터페이스를 하나 만든다.
  2. 프록시 클래스를 생성하여 원래 객체의 레퍼런스를 저장하고, 필요한 메소드를 구현한다.
  3. 원래 객체 클래스에서는 진짜 작업을 처리하는 목적에 맞게 구현한다.
  4. 프록시 클래스에서 원래 객체의 인스턴스를 생성하는 등의 생명 주기 및 “접근”을 관리 및 제어 한다.

복합패턴 : MVC 패턴

기본 개념

Untitled

  • M(모델) : 옵저버 패턴을 통해 의존성을 낮추면서, 자신의 상태가 변경됨을 알린다.
    • 보통, 데이터 객체 또는 뷰에서 표현을 위한 객체 등이 구성된다.
  • V(뷰) : 컴포지트 패턴을 이용해 사용자 인터페이스를 구성한다. 종속된 것이 아닌 여러 모델,컨트롤러와 상호작용 할 수 있다.
    • 웹 프레임워크에서는 사용자가 노출되는 화면을 의미한다.
    • 하나의 뷰가 꼭 하나의 컨트롤러와 상호작용하는 것은 아니다. 여러 개와 할 수도 있고, 변경할 수도 있다.
  • C(컨트롤러) : 뷰의 전략 객체, 뷰에서 요청한 내용을 처리하기 위해 요청을 받아 적절한 모델에게 넘겨준다.
    • 뷰에서 요청을 받아 처리하기 적절한 프로세스를 수행한다.
    • 단순히 데이터를 받아 전달하는 용도만 있는게 아니다. 적절하게 다른 프로세스도 수행하거나 여러가지 과정을 거친다.

복합패턴?

  • 반복적으로 생길 수 있는 하나의 문제를 해결하기 위해 2개 이상의 패턴을 결합해서 사용한다.

Untitled

핵심 요소

각 요소끼리 느슨하게 결합(!) 되어 있다는 것이 중요하다. 웹 프레임워크에서는 기본이 되는 개념으로, 여러 클라이언트-서버 웹 프레임워크에서 해당 패턴을 통해 서비스의 구조를 구성하고 있다.

브리지 패턴

기본 개념

구현과 더불어 추상화 까지 변경해야 하는 경우 사용하는 패턴.

큰 클래스 또는 밀접하게 관련된 클래스들의 집합을 두 개의 개별 계층구조(추상화 및 구현)로 나눈 후 각각 독립적으로 개발할 수 있도록 하는 구조.

Untitled

핵심 정리

  • 구현과 추상화 부분은 분리되어 있어야 한다.
  • 추상화 부분을 구현한 구상 클래스가 바뀌어도 클라이언트에는 영향을 끼치지 않는다.
  • 독립적으로 확장이 가능해야 한다.

빌더 패턴

기본 개념

객체의 생성 단계를 캡슐화 하고 싶을 때 사용한다.

클라이언트가 빌더에게 생성을 요청하면, 빌더는 추상 인터페이스를 사용해 객체를 생성한다.

Untitled

핵심 정리

  • 복합 객체 생성 과정이 캡슐화 된다.
  • 여러 단계와 다양한 절차를 거쳐 객체를 만든다.(팩토리 패턴에서는 한 단계에서 모두 처리 됨)
  • 내부 구조를 클라이언트와 분리하여 보호가 가능하다.
  • 클라이언트는 구현 코드를 쉽게 변경할 수 없다.

책임 연쇄 패턴

기본 개념

1개 요청을 2개 이상의 객체에서 처리해야 할 때 사용하는 패턴

요청을 검토하는 핸들러가 속해있는 각 객체에 요청을 검사해서 처리하도록 요청하거나 다른 객체에게 넘긴다.

Untitled

핵심 정리

  • 요청을 보낸 쪽과 받는 쪽을 분리할 수 있다.
  • 객체는 핸들러의 구조를 몰라도 되고, 다른 객체의 레퍼런스를 가지지 않아도 되어 단순하게 만들 수 있다.
  • 핸들러에 속한 객체의 순서를 바꾸거나 교체하여 역할을 동적으로 추가하거나 제거할 수 있다.

플라이웨이트 패턴

기본 개념

어떤 클래스의 인스턴스 하나로 여러 개의 가상 인스턴스를 제공하고 싶을 떄 사용한다.

실제 객체는 하나지만, 이 객체의 인스턴스가 여러 개 생성되었을 때 이를 묶어서 관리하는 또 다른 객체를 생성한다.

Untitled

핵심 정리

  • 실행 시에 객체 인스턴스의 개수를 줄여서 메모리 절약을 할 수 있다.
  • 여러 가상 객체의 상태를 한 곳에 모아둘 수 있다.
  • 실제 가상 객체를 제공하는 객체는 팩토리 패턴을 사용하여 객체를 제공할 수도 있다.(예제 사진 처럼)

인터프리터 패턴

기본 개념

어떤 언어의 인터프리터를 생성할 때 사용한다.

언어의 문법과 구문을 번역하는 인터프리터 클래스를 기반으로 정의된다.

Untitled

핵심 정리

  • 문법을 클래스로 표현하여 쉽게 언어를 구현할 수 있다.
  • 클래스 구조에 메소드만 추가하면 프로그램을 해석하는 기능 외에도 새로운 기능을 추가할 수 있다.
  • 효율 보다는 단순하고 간단하게 만드는 것에 더 초점을 둘 때 유용하다.

중재자 패턴

기본 개념

서로 관련된 객체 사이의 복잡한 통신과 제어를 한 곳으로 집중하고 싶을 때 사용한다.

모든 객체가 서로를 알고있을 필요가 없고 중재자를 통해 완전히 분리되어 작동한다.

Untitled

핵심 정리

  • 시스템과 객체를 분리함으로써 재사용성을 향상 시킨다.
  • 제어 로직을 한 군데 모아놨으므로 관리하기가 수월하다.
  • 시스템에 들어있는 객체 사이에서 오가는 메세지를 줄이고 단순화시킬 수 있다.

메멘토 패턴

기본 개념

객체를 이전의 상태로 복구해야 하는 경우 사용한다.

“작업 취소” 기능, “세이브 지점으로 복귀” 와 같은 경우가 이에 해당한다.

Untitled

핵심 정리

  • 시스템에서 핵심적인 기능을 담당하는 객체의 상태 저장이 가능해야 한다.
  • 핵심적인 객체의 캡슐화 유지가 되어야 한다.
  • 저장된 상태를 핵심 객체와는 별도의 다른 객체에 보관하여 안전성을 추구한다.
  • 핵심 객체의 데이터를 계속해서 캡슝화된 상태로 유지할 수 있다.

프로토타입 패턴

기본 개념

어떤 클래스의 인스턴스를 만들 때, 자원과 시간이 많이 들거나 복잡한 경우 이 패턴을 사용한다.

기존 인스턴스를 복사하기만 해도 새로운 인스턴스를 만들 수 있다.

Untitled

핵심 정리

  • 클라이언트는 새로운 인스턴스를 만드는 과정을 몰라도 된다.
  • 구체적인 형식을 몰라도 객체를 생성할 수 있다.
  • 상황에 따라서 객체를 새로 생성하는 것 보다 기존 객체를 복사하는 것이 더 효율적일 수 있다.

비지터 패턴

기본 개념

다양한 객체에 새로운 기능을 추가해야 하는데, 캡슐화가 별로 중요하지 않다면 사용하는 패턴.

비지터 객체는 트래버서 객체와 함께 동작한다. 트래버서는 컴포지트 패턴을 쓸 때, 복합 객체 내에 속해 있는 모든 객체에 접근하는 것을 도와준다.

비지터 객체 내에서 복합 객체 내의 모든 객체를 대상으로 원하는 작업을 처리하게 도와준다.

Untitled

핵심 정리

  • 구조를 변경하지 않으면서 복합 객체 구조에 새로운 기능을 추가할 수 있다.
  • 비지터가 수행하는 기능과 관련된 코드를 한 곳에 모아둘 수 있다.
  • 컬렉션 내 모든 항목에 접근하는 트래버서 때문에 복합 구조를 변경하기가 더 어렵다.

© 2024. Chiptune93 All rights reserved.