[ Programming ]
Design Pattern
- 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 - Command Pattern
[디자인 패턴] 커맨드 패턴
[디자인 패턴] 커맨드 패턴 이번 글에서는 커맨드 패턴에 대해 설명하겠습니다. 커맨드 패턴은 요청(행위, 행동)을 객체로 캡슐화해서 요청을 매개변수화하는 패턴이다. (행동 패턴) 주로 요청을 보낸 객체와 요청을 수행하는 객체를 분리하고 싶을 때 사용한다. 에디터의 실행 기록을 저장하며 [redo/undo]를 구현하거나, 작업 큐를 구현하는데 많이 사용된다. 커맨드 패턴은 다음과 같은 요소들로 이루어져 있다고 보면 된다. 커맨드 객체 : 실제 실행될 동작을 구현한 클래스로 "리시버"의 메서드를 실행하는 객체이다. 리시버 객체 : 실제로 작업을 수행하는 객체이다. 인보커 객체 : 커맨드를 실행하는 주체이다. 클라이언트 : 커맨드 객체를 생성하여 인보커에 할당한다. 그리고 그 상관관계를 그림으로 나타내 아래와 같다. 커맨드 패턴을 설명만 들어서는 감이 안올 것 같다. 그래서 아래 간단한 요구사항을 커맨드 패턴으로 구현해보자. 요구사항 스위치 전원을 on/off하여 전등을 끄고 킬 수 있다. // Receiver: 실제 동작을 수행하는 객체 class Light { on() { console.log("💡 불이 켜졌습니다."); } off() { console.log(" 불이 꺼졌습니다."); } } // Command 인터페이스 (Invoker는 인터페이스에 의존하여 Command 객체 구현은 모름) interface Command { execute(): void; } // Concrete Command: 불 켜기 class LightOnCommand implements Comm...2025-08-29 - 디자인 패턴싱글턴 패턴
[디자인 패턴] 싱글턴 패턴
[디자인 패턴] 싱글턴 패턴 싱글턴 패턴은 디자인패턴의 생성패턴의 한 종류다. 개념은 엄청 간단하게 특정 클래스의 인스턴스가 오직 하나만 생성되도록 만드는 패턴이다. 핵심은 인스턴스를 여러개 생성하려고해도 오직 1개의 인스턴스만 만들어 지고 사용되도록 보장되어야 한다. 싱글톤 패턴은 보통 리소스를 많이 차지하는 역할을 하는 클래스에 적용한다. 예시로는 스레드풀, DB 연결 모듈과 같은 객체들이 한번 생성하고 계속 사용하는 객체인 싱글톤 객체로 만들어진다. 개념은 매우 간단하지만 실제 적용하기에는 고려할 것이 많은 패턴이다. "어떻게 1개만 생성될 수 있도록 만들것인가?", "언제 인스턴스가 생성되도록 할 것인가?", "멀티 쓰레딩 언어에서는 고려할 것이 없을까?", "그냥 전역 변수로 쓰면 안돼?"와 같은 의문들을 가져야한다. 또한 인터페이스에 맞춰 구현하는 것이 아니라, 정적 메서드와 정적으로 생성된 객체를 할당하면서 결합도가 높아져 SOLID 원칙에 위배되기도 한다. 싱글톤 패턴을 만드는 방법은 다양하다. 그리고 각 방법마다 "객체 생성 시기", "멀티 스레딩 가능 여부"와 같은 것들이 다르다. 이 방법중에서 사용이 권장되는 방법은 1.6과 1.7 방식이다. 중요해서 안전하게 사용하고 싶으면 enum을 활용하는 1.7 방식을 사용하고 유연하게 사용하고 싶으면 1.6방식을 사용하면 된다. 1.1 Eager Initialization(이른 초기화) Eager Initialization은 클래스 로딩시 인스턴스를 미리 만드는 방법으로 2가지 특징이 있다. 클래스가 로딩될 때 바로 인스턴스를 생성되어 사용하지 않...2025-08-21 - 팩토리 패턴디자인 패턴
[디자인 패턴] 팩토리 패턴
[디자인 패턴] 팩토리 패턴 팩토리 패턴은 생성 패턴의 한 종류다. 생성 패턴은 객체의 생성 방식을 결정하는 패턴으로 객체 생성을 추상화하는 패턴이다. 팩토리 패턴은 크게 2가지로 나뉘어진다. 팩토리 메서드 패턴과 추상 팩토리 패턴이다. 팩토리 메서드 패턴은 객체 생성을 구상 클래스의 메서드로 처리하는 것으로 객체 생성을 하는 인터페이스를 만들고 구현하는 패턴이다. 이 때 만들어지는 객체의 인터페이스를 제품이라고 표현하고 객체를 만드는 인터페이스를 생산자라고 표현한다. 추상 팩토리 패턴은 연관 및 의존하는 객체로 이루어진 하나의 객체를 생성하기 위한 인터페이스를 제공하는 패턴이다. 위 두 패턴은 모두 SOLID 원칙의 D(의존성 역전 원칙)과 깊은 관련이 있다. 왜냐하면 제품을 구상하는 제품 구상 클래스와 제품을 만드는 생산자 구상 클래스가 모두 구상 클래스를 의존하지 않고 제품 인터페이스를 통해 연결되기 때문이다. 간단한 팩토리 패턴을 설명하기 위해 요구사항을 만들고 이를 구현하겠다. 피자가게 요구사항 피자 주문을 받으면 피자 종류에 따라 type을 받는다. type에 맞는 피자를 만들고 가공한다. 피자 가게마다 만드는 똑같은 피자도 만드는 방식이 다르거나, 만드는 피자 종류가 다를 수 있다. 위 요구 사항 그대로 생각 없이 구현하면 아래와 같이 나올 거다. interface PizzaStore { Pizza orderPizza(String type); } interface Pizza { void prepare(); void bake(); void cut(); ... } ...2025-08-14 - Decorator Pattern
[디자인 패턴] Decorator 패턴
[디자인 패턴] Decorator 패턴 Decorator 패턴은 디자인 패턴에서 구조 패턴에 해당한다. 구조 패턴은 클래스나 객체를 조합하여 더 크고 복잡한 구조를 만들거나 기존 구조를 확장하는데 사용한다. 그리고 데코레이터 패턴은 클래스의 기능을 추가하기 위해서 다른 객체를 덧붙이는 패턴으로, 객체의 결합을 통해 동적으로 유연하게 확장할 수 있는 패턴이다. 데코레이터 패턴은 기존에 구현되어있는 클래스를 수정하지 않고, 기능을 추가할 수 있는 설계 패턴(OCP)으로 기능 확장이 필요할 때 동적인 기능이 필요할 때 subclass로의 상속 대안으로 사용할 수 있는 패턴이다. 이번엔 Decorator 패턴을 토핑추가가 가능하며, 토핑별로 가격이 달라지는 요구사항을 구현하는 것을 바탕으로 설명하겠습니다. 요구 사항 음료는 에스프레소, 블랙 커피, 밀크 커피가 있다. 토핑은 두유, 우유, 휘핑크림이 있다. 토핑 추가시 가격도 추가이 추가된다. 1.1 Decorator 패턴 없이 구현 Beverage Class public class Beverage { private Milk milk; private Soy soy; ... public String getDescription() {} public Integer cost() {} public void setMilk() {} public Boolean hasMilk() {} public Boolean hasSoy() {} public Boolean hasWhip() {} ... } Beverage 상속...2025-08-01 - Observer PatternReact Query
[디자인 패턴] Observer 패턴(feat. React Query)
옵저버 패턴 옵저버 패턴은 책임 분산을 위한 행위 패턴의 한 종류이고, 주로 분산 이벤트 처리 시스템을 구현하는데 사용한다. 주로 어떤 Subject의 상태 변화에 따라 Observer가 행위를 취하는 패턴을 구현하는데 사용된다 그래서 관찰 당하는 subject와 다수의 관찰하는 observer로 구성된다.(1:n 관계) 즉, 단일 피관찰자(subject)의 상태 변화에 따라 다수의 관찰자(observer)가 액션(행동, 행위)가 요구될 때 사용하는 패턴이다. 그리고 이 옵저버 패턴(Observer Pattern)을 확장한 디자인 패턴으로 발행-구독 패턴(Pub-Sub Pattern)이 있다. 옵저버 패턴이 오늘의 주인공이기 때문에 간단한 차이를 설명하면 pub-sub 패턴은 별도의 이벤트 채널로 publisher가 발행을 하면 subscriber가 구독 상태일때 처리하지만, observer 패턴은 별도의 이벤트 채널(중간 매개) 없이 발행자(Publisher)가 발행(or 상태 변화)를 하면 바로 구독자(Observer, Subscriber)가 처리한다는 것이다. 이제 본격적으로 옵저버 패턴에 대해 알아보자. 옵저버 패턴을 설명하려면 먼저 옵저버 패턴 적용 전 구조와 적용 후 구조를 보고 뭐가 달라졌는지 비교하고 확인해야한다. 위 그림은 홈페이지의 언어 설정을 변경했을때, 가격 출력기로 언어에 맞는 국가의 화폐단위와 소수점 처리 방식, 환율을 적용한 가격을 출력해주는 코드의 다이어그램이다. 그래서 이 기능 구현을 위해 홈페이지 언어 관리 객체에서 언어가 변경될 때 가격 계산기와 가격 형식 관리기의 상태를 변...2025-07-17