[Design Patten] 데코레이터(Decorator) 패턴이란?
Design Pattern

[Design Patten] 데코레이터(Decorator) 패턴이란?

728x90

 

 

데코레이터 패턴(Decorator pattern)이란 주어진 상황 및 용도에 따라 어떤 객체에 책임을 덧붙이는 패턴으로, 기본 기능에 추가할 수 있는 기능의 종류가 많은 경우에 각 추가 기능을 Decorator 클래스로 정의한 후 필요한 Decorator 객체를 조합함으로써 추가 기능을 조합하는 설계 방식이다.

 

예를 들어 네비게이션 SW에서 도로를 표시하는 기능을 생각해보자. 네비게이션은 기본 도로를 간단한 선으로 표시하는 기본 기능에 차선 표시, 교통량 표시, 교차로 표시, 단속 카메라 표시의 4가지 추가 기능이 있을 수 있다.

데커레이터 패턴을 사용하면 개별 추가 기능에 해당하는 Decorator 클래스 4개만 구현하고 개별 추가 기능을 객체의 형태로 조합함으로써 추가 기능의 조합을 구현할 수 있다. 또한 프로그램을 실행하는 중에도 Decorator 객체의 조합이 가능하므로 필요한 추가 기능의 조합을 동적으로 생성하는 것도 가능하다.

아래의 그림은 기본 기능과 추가 기능인 차선 표시와 교통량 표시를 나타내는 다이어그램이다.

 

1. Display

public abstract class Display {
    public abstract void draw();
}

 

2. RoadDisplay

  • 기본 도로 표시 기능을 제공하는 RoadDisplay 클래스
public class RoadDisplay extends Display {
    public void draw() {
        System.out.println("기본 도로 표시");
    }
}

 

3. DisplayDecorator

  • 추가 기능을 사용하고 싶다면 DisplayDecorator 클래스를 상속받아 구현할 수 있다.
  • 아래의 LaneDecorator 클래스와 TrafficDecorator 클래스가 DisplayDecorator 클래스를 상속받고 있다.
public abstract class DisplayDecorator extends Display {
    private Display decoratedDisplay;
  
    public DisplayDecorator(Display decoratedDisplay) {
        this.decoratedDisplay = decoratedDisplay;
    }
  
    public void draw() {
        decoratedDisplay.draw();
    }
}

 

4. LaneDecorator

  • LaneDecorator 클래스에서는 차선 표시 기능만 직접 제공하고 도로 표시 기능은 RoadDisplay 클래스의 draw 메서드를 호출하는 방식으로 구현한다.
  • RoadDisplay 객체에 대한 참조는 DisplayDecorator 클래스에서 Display 클래스로의 composition 관계를 통해 표현되고 있다.
  • 기본 도로 표시 + 차선 표시 기능을 한다.
public class LaneDecorator extends DisplayDecorator {
    public LaneDecorator(Display decoratedDisplay) {
        super(decoratedDisplay);
    }
  
    public void draw() {
        super.draw();
        drawLane();
    }
		
    public void drawLane() {
        System.out.println("차선 표시");
    }
}

 

5. TrafficDecorator

  • LaneDecorator 클래스와 마찬가지로 DisplayDecorator 클래스를 상속받아 표현하고 있다.
  • 기본 도로 표시 + 교통량 표시 기능을 한다.
public class TrafficDecorator extends DisplayDecorator {
    public TrafficDecorator(Display decoratedDisplay) {
        super(decoratedDisplay);
    }
  
    public void draw() {
        super.draw();
        drawTraffic();
    }
		
    public void drawTraffic() {
        System.out.println("교통량 표시");
    }
}

 

 

 

다음은 3가지 유형의 도로 표시 객체를 생성한 Client 클래스의 코드다.

public class Client {
    public static void main(String[] args) {
        Display road = new RoadDisplay();
        road.draw(); // 기본 도로 표시
      
        Display roadWithLane = new LaneDecorator(new RoadDisplay());
        roadWithLane.draw(); // 기본 도로 + 차선 표시
      
        Display roadWithTraffic = new TrafficDecorator(new RoadDisplay());
        roadWithTraffic.draw(); // 기본 도로 + 교통량 표시
    }
}

 

주목할 점은 road, roadWithLane, roadWithTraffic 객체의 접근이 모두 Display 클래스를 통해 이루어진다는 것이다. 즉, 표시하고자 하는 기능에 관계없이 Client 클래스는 동일한 Display 클래스만을 통해 일관성 있는 방식으로 도로 정보를 표시할 수 있다.

roadWithLane 객체에 draw 메서드가 호출되면 먼저 RoadDisplay 객체의 draw 메서드를 호출한다. 그리고 이어서 LaneDecorator 객체의 drawLane 메서드를 호출한다.

이러한 방식의 설계를 이용하면 추가 기능 조합별로 별도의 클래스를 구현하는 대신 각 추가 기능에 해당하는 클래스의 객체를 조합해 추가 기능의 조합을 구현할 수가 있다.

예를 들어 기본 도로, 차선, 교통량 모두 표시해주고 싶다면 아래의 코드와 같이 표현해주면 된다.

public class Client {
    public static void main(String[] args) {
        Display roadWithLaneAndTraffic = 
            new TrafficDecorator(new LaneDecorator(new RoadDisplay()));
        roadWithLaneAndTraffic.draw();
    }
}

 

데코레이터 패턴은 기본 기능에 추가할 수 있는 많은 종류의 부가 기능에서 파양되는 다양한 조합을 동적으로 구현할 수 있는 패턴이다. 아래의 코드는 프로그램 인자를 통해 명시된 추가 기능을 동적으로 생성한 예제다.

public class Client {
    public static void main(String[] args) {
        Display road = new RoadDisplay();
        
        for(String decoratorName : args) {
            if(decoratorName.equalsIgnoreCase("Lane")) {
                road = new LaneDecorator(road); // 차선 표시 기능 추가
            }
            if(decoratorName.equalsIgnoreCase("Traffic")) {
                road = new TrafficDecorator(road); // 교통량 표시 기능 추가
            }
            if(decoratorName.equalsIgnoreCase("Crossing")) {
                road = new CrossingDecorator(road); // 교차로 표시 기능 추가
            }
        }
      
        road.draw();
    }
}

 

 

출처 : JAVA 객체 지향 디자인 패턴 / 정인상, 채홍석

728x90