데코레이터 Decorator
🙉

데코레이터 Decorator

Created
Apr 23, 2024 04:31 AM
Last edited time
Last updated April 23, 2024
Tags
Language
URL

Intro::

디자인 패턴 중 구조 패턴인 데코레이터에 대해 알아봅시다.
 

데코레이터란?

💡
데코레이터 패턴은 구조적 디자인 패턴의 하나로, 객체에 동적으로 새로운 책임을 추가할 수 있도록 해줍니다. 이 패턴을 사용하면 서브클래싱을 통한 확장 대신에, 객체의 기능을 확장하거나 수정할 수 있습니다. 데코레이터 패턴은 기존 코드를 변경하지 않고도 객체에 새로운 기능을 추가할 수 있기 때문에, 코드의 유연성과 재사용성을 높여줍니다.
 

구성 요소

  1. 컴포넌트(Component): 기본 기능을 정의하는 인터페이스나 추상 클래스입니다. 데코레이터와 구체적 컴포넌트 모두 이 인터페이스를 구현합니다.
  1. 구체적 컴포넌트(Concrete Component): 컴포넌트 인터페이스를 구현하는 클래스로, 기본 기능을 제공합니다.
  1. 데코레이터(Decorator): 컴포넌트 인터페이스를 구현하면서 추가적인 책임(기능)을 추가할 수 있는 클래스입니다. 데코레이터는 내부에 컴포넌트 타입의 객체를 가지고 있으며, 이 객체를 통해 기본 기능을 확장합니다.
  1. 구체적 데코레이터(Concrete Decorator): 데코레이터 클래스를 상속받아 특정 기능을 추가하는 클래스들입니다.

장점

  • 확장성: 객체의 기능을 실행 시간에 동적으로 추가하거나 변경할 수 있어 매우 유연합니다.
  • 서브클래싱 감소: 기능 확장을 위해 서브클래스를 만드는 것보다 데코레이터를 사용하여 기능을 추가하므로, 클래스 계층이 과도하게 커지는 것을 방지할 수 있습니다.
  • 기능의 조합: 데코레이터를 중첩하여 사용함으로써 다양한 기능의 조합을 쉽게 생성할 수 있습니다.
 

단점

  • 복잡성 증가: 데코레이터 패턴을 사용하면 작은 단위의 클래스가 많이 생성됩니다. 각각의 데코레이터가 고유의 기능을 추가하기 때문에, 전체적인 시스템의 구조가 복잡해질 수 있습니다. 이로 인해 코드를 이해하고 관리하기 어려워질 수 있습니다.
  • 구성 오류: 데코레이터의 사용은 실행 시점에 구성되는 경우가 많기 때문에, 잘못된 순서나 조합으로 데코레이터를 적용하면 예상치 못한 버그가 발생할 수 있습니다. 예를 들어, 특정 데코레이터가 다른 하나 이상의 데코레이터의 결과에 의존하는 경우, 그 순서가 잘못되면 시스템이 제대로 작동하지 않을 수 있습니다.
  • 성능 문제: 각 데코레이터는 내부적으로 다른 컴포넌트를 참조하고, 이 참조를 통해 메서드 호출을 위임합니다. 이렇게 여러 레이어를 거치면서 메서드 호출이 중첩되는 경우, 성능 오버헤드가 발생할 수 있습니다. 따라서 많은 수의 데코레이터가 중첩되는 경우, 시스템의 성능이 저하될 수 있습니다.
  • 디버깅 어려움: 데코레이터 패턴을 사용하면, 실행 시간에 동적으로 객체의 행위가 결정됩니다. 이로 인해 디버깅이 어려워지고, 어떤 객체가 실제로 어떤 데코레이터에 의해 영향을 받는지 파악하기가 복잡해질 수 있습니다.
 

코드 예시

// 컴포넌트 인터페이스 interface Coffee { String getDescription(); double getCost(); } // 구체적 컴포넌트 class SimpleCoffee implements Coffee { public String getDescription() { return "Simple Coffee"; } public double getCost() { return 2.0; } } // 데코레이터 추상 클래스 abstract class CoffeeDecorator implements Coffee { protected Coffee decoratedCoffee; public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee = coffee; } public String getDescription() { return decoratedCoffee.getDescription(); } public double getCost() { return decoratedCoffee.getCost(); } } // 구체적 데코레이터 class MilkDecorator extends CoffeeDecorator { public MilkDecorator(Coffee coffee) { super(coffee); } public String getDescription() { return decoratedCoffee.getDescription() + ", milk"; } public double getCost() { return decoratedCoffee.getCost() + 0.5; } } class MochaDecorator extends CoffeeDecorator { public MochaDecorator(Coffee coffee) { super(coffee); } public String getDescription() { return decoratedCoffee.getDescription() + ", mocha"; } public double getCost() { return decoratedCoffee.getCost() + 0.7; } } // 사용 예 public class Main { public static void main(String[] args) { Coffee myCoffee = new SimpleCoffee(); System.out.println(myCoffee.getDescription() + ": $" + myCoffee.getCost()); myCoffee = new MilkDecorator(myCoffee); System.out.println(myCoffee.getDescription() + ": $" + myCoffee.getCost()); myCoffee = new MochaDecorator(myCoffee); System.out.println(myCoffee.getDescription() + ": $" + myCoffee.getCost()); } }
 

References::

Loading Comments...