JUINTINATION

데커레이터(Decorator) 패턴 본문

JAVA객체지향디자인패턴

데커레이터(Decorator) 패턴

DEOKJAE KWON 2023. 7. 9. 16:35
반응형

데커레이터 패턴이란?

기본 기능에 추가할 수 있는 기능의 종류가 많은 경우 기본 기능에 추가될 수 있는 많은 수의 부가 기능에 대해서 다양한 조합을 동적으로 구현할 수 있는 패턴이다.

다음과 같이 도로를 여러 가지 표시하는 프로그램이 있다고 하자.

public class Client {
    public static void main(String[] args) {
        RoadDisplay roadDisplay = new RoadDisplay();
        roadDisplay.draw();

        RoadDisplayWithLane roadDisplayWithLane = new RoadDisplayWithLane();
        roadDisplayWithLane.draw();
    }
}

class RoadDisplay {
    public void draw() {
        System.out.println("기본 도로 표시");
    }
}

class RoadDisplayWithLane extends RoadDisplay {
    @Override
    public void draw() {
        super.draw();
        drawLane();
    }
    private void drawLane() {
        System.out.println("차선 표시");
    }
}
  • 위 코드의 문제점
    • 여러 가지 추가 기능을 조합하여 도로를 표시하는 방법을 바꾸고 싶다면 각 기능을 중복되게 작성하여 각각의 클래스를 만들어야 한다.
경우 기본 기능 도로 표시 추가 기능 클래스 이름
차선 표시 교통량 표시 교차로 표시
1 O       RoadDisplay
2 O O     RoadDisplayWithLane
3 O   O   RoadDisplayWithTraffic
4 O     O RoadDisplayWithCrossing
5 O O O   RoadDisplayWithLaneTraffic
6 O O   O RoadDisplayWithLaneCrossing
7 O   O O RoadDisplayWithTrafficCrossing
8 O O O O RoadDisplayWithLaneTrafficCrossing

이를 해결하기 위해 다음과 같이 추가 기능별로 개별적인 클래스를 설계하고 이를 조합한다.

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

abstract class Display {
    abstract void draw();
}

class RoadDisplay extends Display {
    @Override
    void draw() {
        System.out.println("기본 도로 표시");
    }
}

abstract class DisplayDecorator extends Display {
    private Display decoratedDisplay;

    public DisplayDecorator(Display decoratedDisplay) {
        this.decoratedDisplay = decoratedDisplay;
    }

    @Override
    void draw() {
        decoratedDisplay.draw();
    }
}

class LaneDecorator extends DisplayDecorator {
    public LaneDecorator(Display decoratedDisplay) {
        super(decoratedDisplay);
    }

    public void draw() {
        super.draw();
        drawLane();
    }

    private void drawLane() {
        System.out.println("차선 표시");
    }
}

class TrafficDecorator extends DisplayDecorator {
    public TrafficDecorator(Display decoratedDisplay) {
        super(decoratedDisplay);
    }

    public void draw() {
        super.draw();
        drawTraffic();
    }

    private void drawTraffic() {
        System.out.println("교통량 표시");
    }
}

class CrossingDecorator extends DisplayDecorator {
    public CrossingDecorator(Display decoratedDisplay) {
        super(decoratedDisplay);
    }

    public void draw() {
        super.draw();
        drawCrossing();
    }

    private void drawCrossing() {
        System.out.println("교차로 표시");
    }
}

데커레이터 패턴 컬레보레이션

 

Component : 기본 기능을 뜻하는 ConcreteComponent와 추가 기능을 뜻하는 Decorator의 공통 기능을 정의한 추상 클래스

ConcreteComponent : 기본 기능을 구현하는 클래스

Decorator : 추가 기능의 공통 기능을 정의한 추상 클래스

ConcreteDecorator : 기본 기능의 추가되는 개별적인 기능을 정의한 Decorator의 하위 클래스

 

 

 

 


데커레이터 패턴을 이용한 간단한 예제

다음과 같은 이메일 내용과 관련된 기능을 구현한 프로그램 코드와 클래스 다이어그램이 있을 때 데커레이터 패턴을 적용하여 프로그램 기능을 개선하라.

class BasicEMailContent {
    private String content;
    public BasicEMailContent(String content) {
        this.content = content;
    }
    public String getContent() {
        return content;
    }
}

class ExternalEMailContent extends BasicEMailContent {
    public ExternalEMailContent(String content) {
        super(content);
    }
    @Override
    public String getContent() {
        return addDisclaimer(super.getContent());
    }
    private String addDisclaimer(String content) {
        return content + " Company Disclaimer";
    }
}

class SecureEMailContent extends BasicEMailContent {
    public SecureEMailContent(String content) {
        super(content);
    }
    @Override
    public String getContent() {
        return encrypt(super.getContent());
    }
    private String encrypt(String content) {
        return content + " Encrypted";
    }
}
  • 위 코드의 문제점
    • ExternalEMailContent와 SecureEMailContent의 조합을 추가하기 위해 각 기능을 중복되게 작성하여 새로운 클래스를 만들어야 한다.

이 문제를 해결하기 위해 다음과 같이 코드와 클래스 다이어그램을 수정해야 한다.

abstract class EMailContent {
    public abstract String getContent();
}

class BasicEMailContent extends EMailContent {
    private String content;
    public BasicEMailContent(String content) {
        this.content = content;
    }
    @Override
    public String getContent() {
        return content;
    }
}

abstract class ContentDecorator extends EMailContent {
    private EMailContent decoratedContent;
    public ContentDecorator(EMailContent decoratedContent) {
        this.decoratedContent = decoratedContent;
    }
    @Override
    public String getContent() {
        return decoratedContent.getContent();
    }
}

class ExternalDecorator extends ContentDecorator {
    public ExternalDecorator(EMailContent decoratedContent) {
        super(decoratedContent);
    }
    @Override
    public String getContent() {
        return addDisclaimer(super.getContent());
    }
    private String addDisclaimer(String content) {
        return content + " Company Disclaimer";
    }
}

class SecureDecorator extends ContentDecorator {
    public SecureDecorator(EMailContent decoratedContent) {
        super(decoratedContent);
    }
    @Override
    public String getContent() {
        return encrypt(super.getContent());
    }
    private String encrypt(String content) {
        return content + " Encrypted";
    }
}

728x90
Comments