JAVA/JAVA Design Pattern

JAVA 데코레이터(Decorator) 패턴

임베디드 친구 2024. 12. 25. 10:08
반응형

데코레이터 패턴은 객체에 동적으로 새로운 기능을 추가할 수 있는 구조적 디자인 패턴입니다. 이 패턴은 상속을 사용하지 않고도 객체의 행동을 확장할 수 있기 때문에 유연하고 확장성 있는 코드를 작성할 수 있습니다.


1. 데코레이터 패턴이란?

  • 동적으로 객체에 새로운 기능을 추가하는 방법을 제공하는 디자인 패턴입니다.
  • 클래스 상속 대신 조합(Composition)을 사용하여 객체의 기능을 확장합니다.
  • 기능 추가 시 코드 재사용성과 유연성이 높아집니다.

2. 데코레이터 패턴의 구조

데코레이터 패턴의 주요 구성 요소는 다음과 같습니다:

  1. Component: 기본 인터페이스나 추상 클래스입니다.
  2. ConcreteComponent: 기본 기능을 구현한 구체 클래스입니다.
  3. Decorator: Component를 구현하는 추상 클래스이며, 기능을 확장하는 데 사용됩니다.
  4. ConcreteDecorator: 기능을 추가하는 구체 데코레이터 클래스입니다.

클래스 다이어그램

                +------------------+
                |   Component      |
                |------------------|
                | + operation()    |
                +------------------+
                          ^
                          |
                +------------------+
                | ConcreteComponent|
                |------------------|
                | + operation()    |
                +------------------+
                          ^
                          |
                +------------------+
                |   Decorator      |
                |------------------|
                | - component      |
                | + operation()    |
                +------------------+
                          ^
                          |
               +-------------------+
               | ConcreteDecorator |
               |-------------------|
               | + operation()     |
               +-------------------+

3. 데코레이터 패턴 예제 코드

아래는 Java를 사용해 데코레이터 패턴을 구현한 예제입니다.

예제 설명

  • Component: 기본 인터페이스로 Coffee를 정의합니다.
  • ConcreteComponent: 기본 커피인 SimpleCoffee를 정의합니다.
  • Decorator: 커피에 추가적인 기능(설탕, 우유 등)을 더할 수 있는 데코레이터입니다.
  • ConcreteDecorator: 기능을 추가하는 구체 클래스입니다 (설탕 추가, 우유 추가 등).

코드

// Component: 기본 인터페이스
interface Coffee {
    String getDescription();
    double getCost();
}

// ConcreteComponent: 기본 커피
class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Simple Coffee";
    }

    @Override
    public double getCost() {
        return 5.0;
    }
}

// Decorator: 데코레이터 추상 클래스
abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription();
    }

    @Override
    public double getCost() {
        return coffee.getCost();
    }
}

// ConcreteDecorator: 우유 추가 기능
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }

    @Override
    public double getCost() {
        return coffee.getCost() + 1.5;
    }
}

// ConcreteDecorator: 설탕 추가 기능
class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }

    @Override
    public double getCost() {
        return coffee.getCost() + 0.5;
    }
}

// 클라이언트 코드
public class DecoratorPatternExample {
    public static void main(String[] args) {
        Coffee simpleCoffee = new SimpleCoffee();
        System.out.println(simpleCoffee.getDescription() + " | Cost: $" + simpleCoffee.getCost());

        // 우유 추가
        Coffee milkCoffee = new MilkDecorator(simpleCoffee);
        System.out.println(milkCoffee.getDescription() + " | Cost: $" + milkCoffee.getCost());

        // 설탕 추가
        Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
        System.out.println(sugarMilkCoffee.getDescription() + " | Cost: $" + sugarMilkCoffee.getCost());
    }
}

출력 결과

Simple Coffee | Cost: $5.0
Simple Coffee, Milk | Cost: $6.5
Simple Coffee, Milk, Sugar | Cost: $7.0

4. 데코레이터 패턴의 사용 사례

  1. Java I/O 라이브러리
    • InputStream, BufferedInputStream, DataInputStream 등에서 데코레이터 패턴이 사용됩니다.
  2. GUI 프레임워크
    • 사용자 인터페이스 구성 시 여러 컴포넌트에 기능을 동적으로 추가할 때 활용됩니다.
  3. 기능 확장이 필요한 객체
    • 객체를 수정하지 않고 기능을 추가하거나 변경해야 할 때 유용합니다.

5. 결론

데코레이터 패턴은 상속 대신 조합을 사용해 기능을 확장하는 패턴으로, 객체에 동적으로 새로운 기능을 추가할 수 있습니다. 이를 통해 코드의 유연성과 확장성이 높아지며, Java I/O와 같은 다양한 실무 사례에서도 널리 사용되고 있습니다.


함께 보면 좋은 내용


이번 포스팅이 데코레이터 패턴을 이해하는 데 도움이 되었기를 바랍니다!

반응형