[ Programming ]
Design Pattern
빌더 패턴디자인 패턴[디자인 패턴] 빌더 패턴
빌더 패턴(Builder Pattern) 빌더 패턴은 복잡하게 여러 단계로 나눠는 객체 생성 과정을 캡슐화하고 싶을때 쓰는 생성 패턴이에요. 객체 생성 로직이 복잡한 경우나 동일한 구조에서 서로 다른 설정으로 객체를 만들고 싶은 경우 유용해요. SQL을 코드로 작성하는 경우, 프론트엔드는 zod라는 타입 검증을 만드는 라이브러리에서 많이 사용되요. 빌더 패턴 구조 (Director 사용하는 빌더패턴) Director 방식을 사용하는 빌더 패턴은 복잡한 생성 과정을 제어하는 Director, 제품 생성에 필요한 방법을 추상화한 인터페이스인 Builder, Builder 인터페이스를 구현한 ConcreteBuilder, 그리고 결과물인 Product로 구성되요. Director 역할: Builder를 사용해서 객체 생성 순서와 과정을 제어하는 역할이에요. Client 대신 복잡한 생성 로직을 관리해요. 특징: 어떤 ConcreteBuilder가 사용될지 모르지만, Builder 인터페이스만 알고 있으면 일관된 방식으로 객체를 만들 수 있어요. 예시: 건축 감독 → 어떤 집을 짓든 "기초 → 골조 → 벽 → 지붕" 순서로 지시해요. Builder 역할: 복잡한 객체를 생성하는데 필요한 단계들을 추상 메서드로 정의하는 인터페이스에요. 특징: Product를 만드는 최소 기준을 정의하고, ConcreteBuilder들이 따라야 할 공통 API를 제공해요. 예시: 집 짓기 설계도 → buildFoundation(), buildWalls(), buildRoof() 등의 단계를 정의해요. ConcreteBuilder 역할...2025-11-14✏️ 작성중...
브릿지 패턴디자인 패턴[디자인 패턴] 브릿지 패턴
브릿지 패턴(Bridge Pattern) 브릿지 패턴은 추상화 계층(Abstraction)과 구현 계층(Implementor)를 분리해서 독립적으로 확장할 수 있게 만드는 구조 패턴이에요. 추상화 계층을 기능 클래스 계층이라고 보기도 해요. 그래서 기능을 추가하고 싶으면 추상화 계층을, 구현을 추가하고 싶으면 구현 계층을 활용하면 되니 독립적으로 확장이 가능하게 되는 거에요. 브릿지 패턴 구조 Abstraction(추상화 계층, 기능 계층)과 Implementor(구현 계층)을 분리하여 이어주는 구조가 되기 때문에 브릿지 패턴이에요. 두 계층을 직접 묶지 않고, 중간에 다리를 놓아 서로 독립적으로 발전할 수 있도록 이은 거에요. 그림의 각 요소에 대해 설명해 볼게요. Abstraction (추상화 계층의 상위 역할, 기능 계층의 상위 역할) 역할: Client가 사용하는 추상 인터페이스로 내부에 Implementor를 참조하여 구현 일부를 위임해요. 특징: 어떤 Implementor를 사용할 지 모르지만, 단지 호출하여 기능을 만드는데 사용해요. 예시: 리모컨 -> TV가 삼성인지 LG인지 모르지만 "전원 키기", "전원 끄기"가 가능해요. RefinedAbstraction (추상화 계층의 구현 클래스) 역할: Abstraction에 정의된 operation()을 실제로 구현 및 확장해요. 여전히 Implementor를 사용해여 구현해요. 특징: Abstraction을 상속받기 때문에 기능 계층과 약한 결합을 가져요. 예시: LG 리모콘, 종합 리모콘 등.. Implementor (구현 계층의 인터페이스...2025-11-14
디자인 패턴컴파운드 패턴[디자인 패턴] 컴파운드 패턴
컴파운드 패턴 오늘은 여러 패턴의 조합으로 문제를 해결하는 컴파운드 패턴에 대해서 알아봐요. 컴파운드 패턴은 딱 정해진 형식이 없어요. 단순히 여러 패턴을 조합하여 문제를 해결하는 것이에요. 대표적인 예로 MVC, MVP, VIPER과 같은 많은 아키텍처들이 있어요. 그런데 Head Frist 디자인 패턴 책처럼 한 단계씩 설명하기는 글 내용이 너무 길어질 것 같아요. 그래서 통째로 설명할 수 있게 예시 코드를 통해 설명하고자 해요. 컴파운드 패턴 예시 우선 컴파운터 패턴 예시 코드를 만들기 위해 배경이 필요해요. 피그마 기능을 컴파운드 패턴으로 구현해보자 저가 만들고 싶은 기능은 피그마처럼 화면에 요소를 추가하여 꾸밀수 있는 기능이에요. 생각한 기능들은 다음과 같아요. 기능 정의 화면에 삼각형, 사각형 같은 요소 추가가 가능하다. 추가된 요소는 이동 가능하다. 이동 했던 동작들은 다시 뒤로 되돌릴 수 있다. 여러 사람이 작업하기 때문에 요소에 대한 소유권이 필요하다. 그러면 각 기능을 위해 무엇이 필요할까요? 정리해봐요 필요한 코드들 Viewer에 삼각형, 사각형 등을 렌더링 해야한다. Viewer와 상호 작용 가능한 요소가 필요하다. 상호 작용을 통해 데이터의 수정(위치 이동)할 수 있는 기능이 필요하다. 데이터가 수정되면 수정된 데이터를 Viewer에 전달하여 렌더링할 수 있어야 한다. Viewer에서 요소를 이동시키려할 때 소유권을 가져 다른 사람이 함께 이동시키지 못하게 해야한다. 이동 했던 이력을 저장하여 되돌릴 수 있어야한다. 그러면 위 코드들을 보고 어떠한 패턴들을 사용해야할까요? 사람마다 다를...2025-10-31
프록시 패턴[디자인 패턴] 프록시 패턴
프록시 패턴(Proxy Pattern) 프록시 패턴은 어떤 객체에 대한 접근을 제어하기 위한 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 행동 패턴이에요. 원격, 가상, 보호, 캐싱, 로깅 프록시와 같이 다양한 종류가 있어요. 이런 프록시들의 목적을 하나로 요약하면 자원 접근 제한 및 통제에요. 대표적인 예로 자바나 자바스크립트의 Class로 만든 Instance의 자원 접근을 Proxy를 통해서 부가 적인 기능을 수행할 수 있게 만드는 것이에요. 프록시 패턴 구조 프록시는 특정 객체에 대한 접근 제어를 하기 위해 사용되고 특정 객체는 Subject라고 해요. 프록시(Proxy)는 Subject 인터페이스를 따라 구현하여 실제 RealSubject와 완전히 호환되도록 바꿀수 있어요. 이렇게 구현하면 Client가 사용할 때 기존의 Subject 인터페이스를 그대로 사용하며 Proxy가 어떻게 생겼는지 몰라도 사용할 수 있어요. Subject : RealSubject가 구현하는 인터페이스에요. 아마 프록시를 추가한다는 것은 이미 Subject가 있을 확률이 높을 거라 생각해요. RealSubject : 접근 제어할 원본 객체이며, 실제 핵심 작업을 수행하는 객체에요. Proxy : RealSubject에 대한 접근을 제어할 중개자(대리인) 프록시 패턴 시퀀스 다이어그램 위 그림은 실제 Client가 Proxy 패턴으로 코드를 사용하면 어떤 순서로 코드가 실행될 지 보여줘요. Proxy의 request() 메서드를 사용하면, RealSubject의 알고리즘을 대신 위임하여 사용하고 그 값을 리턴해주거나 자...2025-10-19
상태 패턴디자인 패턴[디자인 패턴] 상태 패턴
상태 패턴(State Pattern) 상태 패턴을 구현해서 객체의 상태에 따라 다르게 동작하는 코드를 깔끔하게 관리하는 방법을 알려드려요. 이 패턴으로 복잡한 조건문 없이도 상태별로 다른 행동을 쉽게 구현할 수 있어요. 상태 패턴이 왜 필요한가요? 실무에서 이런 상황을 자주 마주칠 수 있어요. 커머스 플랫폼에서 주문 상태를 관리하는데, 주문 상태에 따라 할 수 있는 행동이 달라요. 예를 들어 배송 중인 주문은 취소할 수 없지만, 배송 준비 중인 주문은 취소할 수 있죠. 조건문으로 상태 관리하는 코드 class Order { constructor(orderId) { this.orderId = orderId; this.state = 'ORDERED'; // 주문 완료 } cancel() { if (this.state === 'ORDERED') { console.log('주문이 취소되었습니다.'); this.state = 'CANCELLED'; } else if (this.state === 'PREPARING') { console.log('배송 준비 중인 주문이 취소되었습니다.'); this.state = 'CANCELLED'; } else if (this.state === 'SHIPPING') { console.log('배송 중인 주문은 취소할 수 없습니다.'); } else if (this.state === 'DELIVERED') { console.log('배송 완료된 주문은 취소할 수 없...2025-10-10
Composite 패턴[디자인 패턴] Composite 패턴
Composite 패턴 Composite 패턴을 구현해서 개별 객체와 객체 그룹(부분-전체 계층구조)를 동일한 방식으로 다루는 방법을 알려드려요. 이 패턴으로 트리 구조의 복잡한 계층을 단순하게 처리하고, 부분과 전체를 구별하지 않고 일관된 코드를 작성할 수 있어요. Composite 패턴이 왜 필요한가요? 실무에서는 보통 카테고리같은 기능을 구현하는데 자주 마주치는 문제에요. 만약 파일 시스템을 만든다고 예를 들어봐요. 파일 시스템을 만드는데 파일과 폴더를 따로 처리해야 해요. 폴더는 파일을 담을 수 있고, 폴더 안에 또 폴더가 들어갈 수 있죠. 그런데 용량을 계산하거나 출력할 때마다 파일인지 폴더인지 확인하는 코드를 작성해야 해요. // Composite 패턴 없이 구현한 파일 시스템 class File { constructor(name, size) { this.name = name; this.size = size; } getSize() { return this.size; } } class Folder { constructor(name) { this.name = name; this.children = []; } add(item) { this.children.push(item); } getSize() { let totalSize = 0; for (const child of this.children) { // 파일인지 폴더인지 매번 확인해야 함 if (child instanceof F...2025-10-03
Iterator 패턴[디자인 패턴] Iterator 패턴
Iterator 패턴 Iterator 패턴을 구현해서 서로 다른 자료구조를 동일한 방식으로 순회하는 방법을 알려드려요. 이 패턴으로 자료구조가 달라도 클라이언트 코드를 수정하지 않고 일관된 방식으로 데이터에 접근할 수 있어요. Iterator 패턴이 왜 필요한가요? 실무에서 이런 상황을 자주 마주칠 수 있어요. 두 개발팀이 비슷한 기능을 각각 개발했는데, 한 팀은 배열을 사용하고 다른 팀은 연결 리스트를 사용했어요. 이제 두 데이터를 합쳐서 보여줘야 하는데 문제가 생겨요. A팀 B팀 class ArrayInventory { constructor() { this.items = []; } addItem(item) { this.items.push(item); } getItems() { return this.items; } } class Node { constructor(data) { this.data = data; this.next = null; } } class LinkedListInventory { constructor() { this.head = null; } addItem(item) { const newNode = new Node(item); if (!this.head) { this.head = newNode; return; } let current = this.head; while (current.next) { current = curre...2025-10-03
템플릿 메서드[디자인 패턴] 템플릿 메서드 패턴
Template Method 패턴 정복하기 Template Method 패턴은 알고리즘의 구조는 그대로 두면서, 특정 단계만 다르게 구현할 수 있게 해주는 디자인 패턴이에요. 이 튜토리얼을 따라하면 Template Method 패턴의 핵심 개념을 이해하고, 실제 프로젝트에서 활용할 수 있게 됩니다. 학습목표 Template Method 패턴의 동작 원리를 이해한다 간단한 예제를 구현해본다 Template Method 패턴은 다음과 같이 추상 클래스와 구현 클래스로 이루어지는 상속을 이용하는 패턴이에요. Abstract Class (추상 클래스) 템플릿 메서드를 정의하여 알고리즘의 전체 구조를 제공 (메서드 => 알고리즘 실행 뼈대) 각 단계를 나타내는 추상 메서드들을 선언 공통 로직을 구현하는 구체적인 메서드들도 포함 가능 Concrete Class (구현 클래스) 추상 클래스를 상속받아 추상 메서드들을 구현 알고리즘의 특정 단계들을 자신만의 방식으로 정의 위 구조에 후크라 불리는 메서드를 추상 클래스에 선언하여 사용하기도 해요. 후크는 기본적인 내용만 구현되어 있거나, 아무 코드도 들어있지 않은 메소드에요. 보통 서브클래스에서 알고리즘에 끼어드는데 많이 사용되요. 이제 위 구조에 따라 커피와 차를 구현하는데 Template Method를 사용해 보아요. 왜 위 구조로 Coffee와 Tea를 구현했는지 배경을 설명해 볼게요. Coffee와 Tea라는 객체를 만들었는데, 물을 끓이고, 원재료를 넣어 추출하고, 컵에 붓는 과정이 거의 비슷해요. 그래서 이 과정을 공통화 해서 추상화(캡슐화)할 수 있다고 판단할 수...2025-09-26
Adapter pattern[디자인 패턴] 어댑터 패턴
어댑터 패턴(Adapter pattern) 어댑터 패턴은 호환되지 않는 인터페이스를 가진 클래스들이 함께 작동할 수 있도록 해주는 구조적 디자인 패턴이다. 실생활에서 전원 어댑터가 서로 다른 플러그 규격을 연결해주는 것처럼, 소프트웨어에서도 서로 다른 인터페이스를 가진 객체들을 연결해주는 역할을 한다. 어댑터 패턴은 주로 다음과 같은 경우 유용하다. 기존 코드를 수정할 수 없는 상황에서 새로운 라이브러리나 API를 사용해야 할 때 서드파티 라이브러리의 인터페이스가 기존 시스템과 맞지 않을 때 레거시 시스템과 새로운 시스템을 통합해야 할 때 데이터 형식이나 메서드 시그니처가 다른 클래스들을 통합해야 할 때 Target: 클라이언트가 사용하는 인터페이스 Adapter: Target 인터페이스를 구현하고 Adaptee를 감싸는 클래스 Adaptee: 어댑터가 감싸는 기존 클래스 (호환되지 않는 인터페이스를 가짐) Client: Target 인터페이스를 통해 객체와 협력하는 클래스 MediaPlayer 예시 Target: MediaPlayer Adapter: MediaAdapter Adaptee: AdvancedMediaPlayer Client: AudioPlayer // Target 인터페이스 interface MediaPlayer { void play(String audioType, String fileName); } // Adaptee class AdvancedMediaPlayer { void playVlc(String fileName) { System.out.println("P...2025-09-05

