Hyun's Wonderwall

[CS 지식의 정석] 2. 디자인패턴 본문

Study/CS

[CS 지식의 정석] 2. 디자인패턴

Hyun_! 2025. 10. 24. 13:46

[디자인패턴의 소개]

[디자인패턴의 의의]
프로그램 설계 시 반복적 문제를 객체 간 관계를 이용해 해결하도록 정의된 규약.
라이브러리·프레임워크 설계의 기초 원리로 사용됨.
패턴 학습을 통해 문제 해결력 및 팀 내 의사소통 효율 향상.

[디자인패턴의 종류]

  • 생성패턴: 객체 생성 규약
    ex) 싱글톤, 팩토리, 추상팩토리, 빌더, 프로토타입
  • 구조패턴: 클래스·객체 구조 설계 규약
    ex) 프록시, 어댑터, 브리지, 복합체, 데코레이터, 퍼사드, 플라이웨이트
  • 행동패턴: 객체 간 알고리즘·책임 할당 규약
    ex) 이터레이터, 옵저버, 전략, 책임연쇄, 커맨드, 중재자, 메멘토, 상태, 템플릿메서드, 비지터
    (추가 예: Flux, MVC, MVVM 등)

[라이브러리와 프레임워크의 차이]

  • 공통점: 재사용 가능한 기능을 모듈화한 구성 요소 집합
  • 라이브러리: 폴더·파일 구조 규약 없음, 호출 주도권이 사용자에게 있음
    예시 → axios: .get(), .then() 등 일정한 호출 규약 존재
  • 프레임워크: 폴더·파일 구조 등 엄격한 규약 존재, 제어 흐름이 프레임워크 중심
    예시 → Vue.js: 컴포넌트 기반 구조, 명확한 코드 작성 규약

[싱글톤패턴]

  • 의의: 하나의 클래스가 단 하나의 인스턴스만 갖도록 하는 생성패턴 규약
  • 활용: 인스턴스 생성 비용이 큰 객체(DB 연결 모듈 등)에 사용
  • 장점: 인스턴스 생성 효율화, 자원 절약
  • 단점:
    • 전역 상태 → 결합도 증가
    • 단위 테스트 어려움
    • 멀티스레드 환경 동기화 복잡
    • 객체 생명주기 관리 어려움
    • OOP 원칙(캡슐화, DI) 위반 가능성

[JAVA에서의 싱글톤 구현 방식]

  1. 단순 메서드 호출

    • 인스턴스 존재 여부 확인 후 생성
    • 멀티스레드 환경에서 원자성 결여
  2. synchronized 사용

    • 메서드 단위 잠금으로 동시성 보장
    • 호출 시마다 lock 발생 → 성능 저하
  3. 정적 멤버 (Eager Initialization)

    • 클래스 로드 시 즉시 인스턴스 생성
    • 호출 전에도 메모리 점유
  4. 정적 블록 초기화

    • static 블록에서 인스턴스 초기화
    • 즉시 초기화로 메모리 비효율 가능
  5. 정적 내부 클래스 (Lazy Holder)

    • 내부 클래스 로딩 시 최초 생성
    • thread-safe, lazy-loading 보장
    • 외부 new 호출 방지를 위한 private 생성자 필요
  6. 이중 확인 잠금 (Double Checked Locking)

    • 두 번의 null 검사로 동기화 최소화
    • volatile로 메모리 일관성 보장
    • 멀티스레드 환경 안전
  7. enum 방식

    • JVM이 인스턴스 생성·동기화 보장
    • thread-safe, 직렬화 안전
    • Joshua Bloch(Effective Java) 추천 방식
  • 추천 구현 방식: 정적 내부 클래스(5번) 또는 enum 방식(7번)

[팩토리패턴]

  • 의의: 상속 관계 클래스 간 객체 생성 책임을 하위 클래스에 위임하는 생성패턴 규약
  • 특징:
    • 상위 클래스 → 객체 생성 방식 모름
    • 하위 클래스 → 구체적 생성 로직 관리
    • 객체 생성 구조의 유연성 및 유지보수성 향상

[이터레이터패턴]

  • 의의: 이터레이터(iterator)를 통해 컨테이너 요소에 순차 접근하는 행동패턴 규약
  • 특징:
    • 자료구조(배열, 맵 등)와 무관한 동일 인터페이스 제공
    • 데이터 순회 로직 분리로 코드 일관성 확보
    • 예시 → for...of (JavaScript)

[DI (Dependency Injection)와 DIP (Dependency Inversion Principle)]

  • DI 의의:

    • 메인 모듈이 직접 하위 모듈을 생성하지 않고 외부 주입자를 통해 의존성 전달
    • 의존성 결합 완화, 모듈 교체 용이 구조 확보
  • DI 코드 예시:

    • Project 클래스가 BackendDeveloper, FrontEndDeveloper 객체를 생성자 주입으로 전달받음
    • 생성자 주입은 DI 형태이지만, 구체 클래스에 직접 의존 → DIP 위반
  • DIP 의의:

    • 상위 모듈과 하위 모듈 모두 추상화에 의존해야 함
    • 세부 구현이 추상화에 따라 변경되어야 함
  • DIP 규칙:

    1. 상위 모듈은 하위 모듈에 의존하지 않아야 함
    2. 추상화는 세부사항에 의존하지 않아야 함
  • DI 장점: 모듈 교체 용이 (외부 주입 구조), 단위 테스트 및 마이그레이션 용이, 의존 방향 일관성 확보

  • DI 단점: 모듈 증가로 인한 복잡도 상승, 런타임 의존 주입 → 컴파일 시 오류 검출 어려움


[전략패턴]

  • 의의: 캡슐화된 알고리즘(전략)을 컨텍스트 내에서 상호 교체 가능하게 하는 행동패턴 규약
  • 특징:
    • 실행 중 전략 교체 가능
    • 알고리즘 독립성 및 유연성 확보

[옵저버패턴]

  • 의의: 주체(subject)가 상태 변화를 감지해 옵저버(observer)들에게 통지하는 행동패턴 규약
  • 특징:
    • 주체-옵저버 간 느슨한 결합
    • 이벤트 기반 구조 구현에 적합
    • 예시 → 트위터 알림 로직, MVC 패턴

[프록시패턴]

  • 의의: 객체 접근 전 중간 계층(proxy)을 두어 접근 제어, 로깅, 캐싱 등을 수행하는 구조패턴 규약
  • 특징:
    • 실제 객체 접근 전 필터링·제어 가능
    • 대표 사례 → 프록시 서버(Cloudflare 등), 캐싱·보안 필터
    • 코드 예시 → Proxy 객체로 변경 감지 및 콜백 실행

[MVC, MVP, MVVM 패턴]

[MVC 패턴]

  • 의의: Model–View–Controller로 구성된 대표적 아키텍처 규약
  • 구성요소:
    • Model: 데이터 및 비즈니스 로직 관리 계층 (DB, 상수, 변수 등)
    • View: 사용자 인터페이스(UI) 계층, 데이터 표시 담당
    • Controller: Model과 View를 연결하며 이벤트 및 로직 처리 담당
  • 특징:
    • Controller가 Model↔View 간 데이터 흐름 제어
    • 각 계층의 책임 분리로 재사용성·확장성 확보
  • 장점:
    1. 역할 분리로 병렬 개발 및 유지보수 용이
    2. 재사용성과 확장성 우수
  • 단점:
    • 복잡한 애플리케이션에서는 Model–View 간 의존관계 복잡화
  • 적용사례:
    • Spring Web MVC (DispatcherServlet 중심 아키텍처)

[Spring MVC 적용 사례]

  • 구조: DispatcherServlet(Front Controller)이 중심이 되어 요청–응답 흐름 제어
  • 처리 과정:
    1. 클라이언트 요청 → DispatcherServlet 수신
    2. HandlerMapping 참고 후 적절한 Controller 선택
    3. Controller가 비즈니스 로직 수행 및 Model 생성
    4. ViewResolver가 뷰 위치 결정
    5. View 렌더링 및 사용자 응답 반환
  • 핵심 역할: DispatcherServlet이 요청 분배자이자 중앙 제어기 역할 수행

[MVP 패턴]

  • 의의: MVC의 Controller를 Presenter로 교체한 구조
  • 특징:
    • View와 Presenter가 1:1 관계
    • View가 Presenter를 직접 참조
    • Controller보다 강한 결합 구조
  • 장점:
    • 뷰 로직 테스트 용이
    • 프레젠테이션 로직 분리로 코드 가독성 향상
  • 단점:
    • View–Presenter 간 결합도 증가로 복잡도 상승

[MVVM 패턴]

  • 의의: MVC의 Controller를 ViewModel로 대체한 패턴
  • 구조:
    • ViewModel은 View를 추상화한 계층
    • ViewModel : View = 1 : N 관계
  • 핵심 개념:
    • Command: 여러 UI 동작을 하나의 액션으로 처리
    • Data Binding: 화면(UI) 데이터와 메모리 데이터의 자동 동기화
  • 특징:
    • View와 ViewModel 간 양방향 데이터 바인딩
    • UI와 비즈니스 로직 분리로 유지보수성 향상
  • 대표 프레임워크: Vue.js
  • 관계 비교:
    구분 MVC MVP MVVM
    관계 Controller–View: 1:N Presenter–View: 1:1 ViewModel–View: 1:N
    View 참조 Controller X Presenter O ViewModel O

[Flux 패턴]

  • 의의: 데이터의 흐름을 단방향(One-way)으로 유지하는 구조 패턴
  • 등장 배경:
    • MVC 구조의 양방향 데이터 흐름으로 인한 복잡성 및 일관성 문제 해결
  • 구성요소:
    • Action: 사용자 이벤트(입력·클릭 등) 발생 및 디스패처로 전달
    • Dispatcher: Action의 유형(type)에 따라 로직 결정 및 Store로 전달
    • Store: 애플리케이션의 상태(state) 저장 및 관리 계층
    • View: Store 데이터를 기반으로 UI 렌더링
  • 장점:
    • 데이터 일관성 강화
    • 버그 추적 및 단위 테스트 용이
  • 대표 구현체: Redux
  • 예시 코드:
    • switch(action.type) 구문으로 Action 타입별 상태 갱신 로직 수행

[전략패턴 vs 의존성주입]

  • 공통점:
    교체 가능한 구조를 설계하기 위한 패턴 규약

  • 차이점:

    • 전략패턴:
      동일한 행동 계약(인터페이스)을 정의하고, 이를 기반으로 다양한 알고리즘 구현체를 교체 가능하게 하는 행동패턴 규약
      → “어떤 전략(행동)을 사용할지 결정하는 구조”
    • 의존성주입(DI):
      객체 간 의존성을 외부에서 주입하여 결합도를 낮추는 설계 패턴이자 구조적 원칙
      → “어떤 객체를 사용할지 외부에서 주입하는 구조”
  • 핵심 구분:

    구분 전략패턴 의존성주입(DI)
    목적 알고리즘 교체 의존성 관리
    구성 요소 인터페이스 + 다형성 생성자/세터/인터페이스 주입
    제어 흐름 런타임에 전략 변경 외부 컨테이너(Spring 등)가 제어
    관계 성격 내부 객체 간 캡슐화 중심 외부 주입자 중심의 의존성 제어

[컨텍스트(Context)]

  • 의의:
    특정 상태나 환경을 캡슐화하거나, 중단된 작업을 재개할 수 있도록 저장하는 최소 데이터 집합을 의미하는 개념적 규약

  • 두 가지 의미:

    1. 상태·환경의 캡슐화 — 실행 중인 상황(환경)을 묶어 관리하는 개념
    2. 작업 재개용 정보 저장 — 예: 컨텍스트 스위칭 시 프로세스의 레지스터 값, 스택 포인터 등을 저장
  • 구분:

    • Context: 환경 자체 (예: 병원 방문 상황)
    • Contextual Information: 해당 환경에서 의미를 갖는 부가 정보 (예: 이름, 주민번호 등)
  • 예시:

    1. 병원 방문 context → “이름”은 contextual information
    2. HTTP 요청 context → “HTTP Header”는 contextual information

[React의 Context API 예시]

  • 의의:
    전역적으로 상태(state)를 전달하기 위한 React 내장 상태 전파 API 규약

  • 구조:

    const ThemeContext = React.createContext('light');
    
    class App extends React.Component {
      render() {
        return (
          <ThemeContext.Provider value="dark">
            <Toolbar />
          </ThemeContext.Provider>
        );
      }
    }
    
    function Toolbar() {
      return (
        <div>
          <ThemedButton />
        </div>
      );
    }
    
    class ThemedButton extends React.Component {
      static contextType = ThemeContext;
      render() {
        return <Button theme={this.context} />;
      }
    }
    

'Study > CS' 카테고리의 다른 글

[CS 지식의 정석] 1. 개발자 필수 지식  (0) 2025.10.16