본문 바로가기
Archive/Java 풀스택 아카데미

[TIL] 9. 9월 데코레이터 패턴, 정적 팩토리 메서드 패턴

by Lseing 2025. 9. 8.
coffee manager라는 프로그램을 만들면서 사용된 디자인 패턴 중 사용된 데코레이터 패턴
그리고 정적 팩토리 메서드에 대해 정리하려고 한다

 

🧐데코레이터 패턴이란?

문제점(상속으로 기능을 확장할 때의 한계)

클래스 폭발 예시

수업중 여러 언어로 영수증을 번역하는 기능을 만들었는데 상속으로 구현한다면 영어 번역 기능을 위한 UsaPayment extends Payment, 일본어 번역을 위한 JapanPayment extends Payment 클래스가 만들어질 것이다. 하지만 영어와 일본어 번역이 모두 필요하다면? UsaJapanPayment extends Payment 라는 또 다른 클래스가 필요할 것이다. 이렇게 되면 언어가 늘어날 수록 클래스는 기하급수적으로 늘어날 것이다(클래스 폭발).

 

이런 문제를 해결하기 위해 객체 지향 설계에서는 상속보다는 조합을 사용하라고 말하고 있다.

- 상속(is-a): 소나타는 자동차다. 강한 결합

- 조합(has-a): 자동차는 엔진을 가지고 있다. 느슨한 결합, 부품 교체가 용이

 

데코레이터 패턴은 바로 이 조합(Composition)을 활용하여, 객체에 새로운 책임(기능)을 유연하게 덧붙히는 디자인 패턴이다. 기능 확장이 필요할 때 서브클래싱 대신 쓸 수 있는 유연한 대안이 될 수 있는 패턴이다.

 

✅예시

대표적인 예시로는 커피에 토핑을 추가하는 것이 있다. 원두(Component)에 우유(Decorator)를 추가하여 라떼를 만들거나, 휘핑크림(Decorator)을 추가하여 휘핑크림 라떼를 만드는 것처럼, 원래 객체에 추가적인 기능을 런타임에 부여할 수 있다. 

 

수업에서는 번역 기능에 데코레이터 패턴을 사용했다. 해당 기능에 데코레이터 패턴을 사용하지 않는다면 효율적이지 못한 코드들로 구성이 될 것이다.

 

구조는 이러하다

여기서 Component는 공통적인 기능을 말함

  • Translateble 인터페이스는 가장 기본이 되는 설계도다, 앞으로 장식될 원본 객체와
    장식할 개체 모두 따라야 할 공통 규칙이다.
  • Payment 클래스는 장식을 당하는 원본 객체이다. 기본적으로는 한국어로 된 영수증을 출력한다
  • PaymentDecorator 클래스는 장식 클래스들이 따라야 할 공통된 틀을 제공한다
  • UsaDecorator 클래스는 실제로 장식을 추가해줄 클래스이다. UsaDecorator, JapanDecorator등은 모두 PaymentDecorator를 상속받아 target의 translate()를 먼저 호출한 뒤에 자신만의 번역문을 덧붙히는 방식으로 동작한다.

여기서 target은 현재 장식(Decorator)이 감싸고 있는 바로 안쪽 객체를 의미한다. 이 안쪽 객체는 원본 객체일 수도 있고 장식일 수 도있다(커피에 우유넣고 휘핑크림 추가할 때와 같이 또 다른 장식이 존재 할 수 있기 때문)

SpainDecorator의 translate() 코드인데 이때 상위를 가리키는 target의 translate를 먼저 호출하고 번역을 진행한다

그래서 target.translate()를 호출하는 연쇄작용 덕분에 기능을 겹겹이 쌓아 올리는 것처럼 동적으로 확장할 수 있게된다.

❇️데코레이터 패턴의 특징

데코레이터 패턴을 사용한다면 어떤 이점을 얻을 수 있을까?

이 패턴의 핵심은 상속이 아니라 조합(Composition)을 사용하여, 필요한 기능들을 레고처럼 유연하게 조립하는데 있다.

  • 유연한 기능 확장: '영어 번역' 레고 블록이 필요하면 가져다 붙히고 추가적으로 필요하면 블록을 붙이기만 하면 그만이다. 그래서 기능을 추가하거나 제거할 때 원본객체의 코드를 수정할 필요가 없다.
  • 개방-폐쇄 원칙(OCP)준수: 새로운 번역 기능(SpainDecorator)을 추가할 때 기존의 코드(Payment, UsaDecorator)는 건드리지 않고(수정에는 닫혀있음 Close) 추가(Open)하기만 하면 된다.
  • 책임 분리: 원본 객체인 Payment 객체는 자신의 역할에만 집중하면 된다.

최종적으로는 이렇게 동작하는 모습을 확인할 수 있다.

🧐정적 팩토리 메서드 패턴

정적 팩토리 메서드는 객체를 생성할 때 new 키워드를 사용하는 생성자 대신, 객체를 생성하는 책임을 가지는 별도의 static 메서드를 제공하는 기법이다.

❇️기존 생성자와의 차이점

요리로 예시를 들어보자

- 생성자(new) : 내가 직접 재료(파라미터)를 가지고 요리(객체 생성)를 만드는 것과 같다,

재료를 빠뜨리거나 실수하면 망한 음식이 된다(불완전한 객체)

- 정적 팩토리 메서드 : 오므라이스 주세요(Order.createOrder()) 라고 주문만 하면, 요리사(팩토리 메서드)가 알아서 복잡한 과정을 거친 뒤 나에게 완전히 요리된 완제품을 내어주는 것과 같다.