티스토리 뷰

728x90
반응형

데코레이터 패턴


  • 데코레이터패턴은 객체의 결합을 통하여 기능을 동적으로 확장할 수 있도록 해주는 패턴입니다.
  • 기본 기능에 추가할 수 있는 기능의 종류가 많은 경우 각 추가 기능을 Decorator 클래스로 정의한 후 필요한 Decorator 객체를 조합함으로써 추가 기능을 조합하는 설계 방식입니다.

 

클래스 다이어 그램


 

Component
  • 기본 기능을 의미하는 ConcreteComponent와 추가 기능을 의미하는 Decorator의 공통 기능을 정의합니다.
  • 클라이언트는 Component를 통해 실제 객체를 사용합니다.
ConcreteComponent
  • 기본 기능을 구현하는 클래스
Decorator

 

  • 다양한 추가 기능에 대한 공통 클래스를 정의합니다.

 

ConcreteDecorator
  • Decorator 클래스의 하위 클래스로써 기본 기능에 추가되는 개별적인 기능을 의미합니다.
  • ConcreteDecorator 클래스는 ConcreteComponent 객체에 대한 참조가 필요한데, 이는 Decorator 클래스에서 Component 클래스로의 합성 관계를 통해 표현됩니다.

 

예시


다양한 종류의 자동차 만들기

 

기본 기능을 하는 클래스
public class Car {

    public void start() {
        System.out.println("앞으로 출발합니다.");
    }

    public void stop() {
        System.out.println("멈춥니다.");
    }

    public void back() {
        System.out.println("후진합니다.");
    }
}

 

추가 기능이 포함되어 있는 클래스
public class BusCar extends Car{

    @Override
    public void start() {
        super.start();
    }

    @Override
    public void stop() {
        super.stop();
        onTheBus();
    }

    @Override
    public void back() {
        super.back();
    }

    private void onTheBus() {
        System.out.println("사람들이 버스에 탑승합니다.");
    }
}

 

클라이언트
public class Client {
    public static void main(String[] args) {
        Car car = new Car();
        car.start(); // 앞으로 출발합니다.

        Car bus = new BusCar();
        bus.stop(); // 멈춥니다. + 사람들이 버스에 탑승합니다.
    }
}

 

상황 : 여기서 다른 차종이 추가된다면?
  • 다른 차종과 각 차종마다 기능이 다른 경우라면?

또하나의 추가 기능이 포함되어있는 클래스
public class SportCar extends Car{

    @Override
    public void start() {
        super.start();
        speed();
    }

    @Override
    public void stop() {
        super.stop();
    }

    @Override
    public void back() {
        super.back();
    }

    public void speed() {
        System.out.println("속도를 높인다!");
    }
}

 

클라이언트
public class Client {
    public static void main(String[] args) {
        Car car = new Car();
        car.start(); // 앞으로 출발합니다.

        Car bus = new BusCar();
        bus.stop(); // 멈춥니다. + 사람들이 버스에 탑승합니다.

        Car sportCar = new SportCar();
        sportCar.start(); // 앞으로 출발합니다. + 속도를 높인다!
    }
}

 

문제점
  • 각 기능의 종류와 추가 기능이 많아질 수록 클래스는 많아지게 됩니다.

 

해결책
  • 해당 문제를 해결하기 위해서는 각 추가 기능별로 개별적인 클래스를 설계하고 기능을 조합할 때 각 클래스의 객체 조합을 이용합니다.

 

Component에 해당하는 클래스
  • 공통 기능을 정의합니다.
public abstract class Component {

    public abstract void start();
    public abstract void stop();
    public abstract void back();
}

 

ConcreteComponent
  • 기본 기능을 구현하는 클래스를 정의합니다.
public class Car extends Component{

    @Override
    public void start() {
        System.out.println("앞으로 출발합니다.");
    }

    @Override
    public void stop() {
        System.out.println("멈춥니다.");
    }

    @Override
    public void back() {
        System.out.println("후진합니다.");
    }
}

 

Decorator
  • 다양한 추가 기능에 대한 공통 클래스를 정의합니다.
public class CarDecorator extends Component{

    private Component component;

    public CarDecorator(Component component) {
        this.component = component;
    }

    @Override
    public void start() {
        component.start();
    }

    @Override
    public void stop() {
        component.stop();
    }

    @Override
    public void back() {
        component.back();
    }
}

 

ConcreteDecorator
  • 개별 기능에 대한 클래스를 정의합니다.
// 버스
public class BusCar extends CarDecorator{

    public BusCar(Component component) {
        super(component);
    }

    @Override
    public void start() {
        super.start();
    }

    @Override
    public void stop() {
        super.stop();
        onTheBus();
    }

    @Override
    public void back() {
        super.back();
    }

    private void onTheBus() {
        System.out.println("사람들이 버스에 탑승합니다.");
    }
}

// 스포츠카
public class SportCar extends CarDecorator{

    public SportCar(Component component) {
        super(component);
    }

    @Override
    public void start() {
        super.start();
        speed();
    }

    @Override
    public void stop() {
        super.stop();
    }

    @Override
    public void back() {
        super.back();
    }

    public void speed() {
        System.out.println("속도를 높입니다.");
    }
}

// 트럭
public class TruckCar extends CarDecorator{

    public TruckCar(Component component) {
        super(component);
    }

    @Override
    public void start() {
        super.start();
    }

    @Override
    public void stop() {
        super.stop();
        load();
    }

    @Override
    public void back() {
        super.back();
    }

    private void load() {
        System.out.println("트럭에 짐을 실습니다.");
    }
}

 

클라이언트
  • 각 객체의 접근은 Component 클래스를 통해 이루어집니다. 
  • Component 클래스를 통해 이루어 진다면 어떤 기능을 추가하느냐에 관계없이 Client는 동일한 Component 클래스만을 통해 일관성 있는 방식으로 자동차에 대한 정보를 노출할 수 있습니다.
  • Decorator 패턴을 사용한다면 각 기능별로 클래스를 구현할 필요가 없고 공통적인 부분을 도출하여 객체를 조합하게 된다면 효과적으로 설계를 할 수 있습니다.
public class Client {
    public static void main(String[] args) {
        Component car = new Car();
        car.stop(); // 멈춥니다.

        Component busCar = new BusCar(new Car());
        busCar.stop(); // 멈춥니다. + 사람들이 버스에 탑승합니다.

        Component truckCar = new TruckCar(new Car());
        truckCar.stop(); // 멈춥니다. + 트럭에 짐을 실습니다.

        Component sportCar = new SportCar(new Car());
        sportCar.start(); // 앞으로 출발합니다. + 속도를 높입니다.
    }
}

 

 

참고

https://gmlwjd9405.github.io/2018/07/09/decorator-pattern.html

https://readystory.tistory.com/195

 

728x90
반응형

'JAVA > Design_Pattern' 카테고리의 다른 글

[Design_Pattern] 프록시 패턴  (0) 2022.03.23
[Design_Pattern] 파사드 패턴  (1) 2022.03.13
[Design_Pattern] 컴포지트 패턴  (0) 2022.03.07
[Design_Pattern] 어댑터 패턴  (0) 2022.03.05
[Design_Pattern] 싱글톤패턴  (0) 2022.03.01