ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java Design Pattern - 데커레이터 패턴(Decorator Pattern)
    Language/Java Design Pattern 2022. 11. 21. 17:22

    데커레이터 패턴(Decorator Pattern)

    데커레이터 패턴이란?

    데커레이터 패턴은 어떤 기능에 추가적으로 기능을 덧붙이고 싶은 경우, 그 기능들을 Decorator로 만들어서 덧붙이는 방식이다.

    예를 들어, 서브웨이 샌드위치를 생각해 보겠다. 서브웨이를 주문하면 고객의 기호에 따라 채소를 선택할 수 있다.

    즉, 기본 빵 위에 채소와 토핑을 추가하여 샌드위치가 완성되는 것이다. 여기서 채소와 토핑(양상추, 피클, 양파, 치즈 등)들 각각이 데커레이터가 된다.

    데커레이터 패턴을 사용하면 기능이 딱 정해져 있는 객체가 아닌, 동적으로 기능을 조합하여 객체를 만드는 것이 가능해진다.

     

    데커레이터 패턴의 사용 이유

    샌드위치를 만들기 위해서는 기본적으로 빵(Bread)이 필요하다. 그리고 토핑으로 양상추(Lettuce), 피클(Pickle) 등이 있을 수 있다.

    여러 가지 재료를 가지고 아래와 같은 샌드위치를 만들어 보겠다.

     

    1. 그냥 빵

    2. 양상추가 있는 빵

    3. 피클이 있는 빵

     

    public class Sandwich {
        public String make() {
            return "빵";
        }
    }
    public class SandwichWithLettuce extends Sandwich {
        public String make() {
            return super.make() + addLettuce();
        }
        
        private String addLettuce() {
            return " + 양상추";
        }
    }
    public class SandwichWithPickle extends Sandwich {
        public String make() {
            return super.make() + addPickle();
        }
        
        private String addPickle() {
            return " + 피클";
        }
    }
    public class Client {
        public static void main(String[] args) {
            Sandwich sandwich = new Sandwich();
            System.out.println(sandwich.make());   // "빵" 출력
            System.out.println("==========");
            
            SandwichWithLettuce sandwichWithLettuce = new SandwichWithLettuce();
            System.out.println(sandwichWithLettuce.make());   // "빵 + 양상추" 출력
            System.out.println("==========");
            
            SandwichWithPickle sandwichWithPickle = new SandwichWithPickle();
            System.out.println(sandwichWithPickle.make());   // "빵 + 피클" 출력
        }
    }

     

    그런데 양상추와 피클이 모두 들어가 있는 샌드위치를 만들려면 어떻게 해야 할까? 아마도 아래와 같은 SandwichWithLettuceAndPickle 클래스를 만들어야 할 것이다.

    또한, 치즈 같은 토핑을 추가하고자 한다면 SandwichWithCheese 클래스를 만들어야 할 것이고, 여러 토핑을 조합해야 한다면 SandwichWithLettuceAndCheese, SandwichWithPickleAndCheese 등과 같은 클래스가 추가될 수 있다.

    야채가 10가지가 넘어가면, 무수히 많은 조합의 클래스가 있어야 한다. 이는 좋은 방법이 아니다.

    따라서, 서브 클래스를 만드는 방식이 아닌, 데커레이터 패턴을 적용하여 이러한 문제점을 해결해 보도록 하겠다.


    데커레이터 패턴의 적용

     

    public abstract class Sandwich {
        public abstract void make();
    }

    우선, 추상 클래스 Sandwich를 정의한다. 양상추 샌드위치, 피클 샌드위치 등 여러 샌드위치를 만들기 위해 캡슐화한 것이다.

     

    public class ToppingDecorator extends Sandwich {
        private Sandwich sandwich;
        
        public ToppingDecorator(Sandwich sandwich) {
            this.sandwich = sandwich;
        }
        
        public void make() {
            sandwich.make();
        }
    }

    다음으로 토핑을 추가하는 ToppingDecorator 클래스를 정의한다.

    ToppingDecorator 클래스는 샌드위치를 토핑 하는 것이므로, Sandwich 클래스를 상속받는다.

     

    public class Bread extends Sandwich {
        public void make() {
            System.out.println("빵 추가");
        }
    }

    다음으로, 빵을 추가하기 위해 Bread 클래스를 정의한다. 빵은 데코레이터가 아닌, 기본적으로 있어야 하는 것이므로 데커레이터로 정의하지 않았다.

     

    public class LettuceDecorator extends ToppingDecorator {
        public LettuceDecorator(Sandwich sandwich) {
            super(sandwich);
        }
        
        public void make() {
            super.make();
            addLettuce();
        }
        
        private void addLettuce() {
            System.out.println("+ 양상추");
        }
    }
    public class PickleDecorator extends ToppingDecorator {
        public PickleDecorator(Sandwich sandwich) {
            super(sandwich);
        }
        
        public void make() {
            super.make();
            addPickle();
        }
        
        private void addPickle() {
            System.out.println("+ 피클");
        }
    }

    다음으로 양상추, 피클을 토핑으로 추가하기 위해 LettuceDecorator, PickleDecorator 클래스를 정의한다.

     

    public class Client {
        public static void main(String[] args) {
           /** 양상추 샌드위치 */
           Sandwich sandwichWithLettuce - new LettuceDecorator(new Bread());
           sandwichWithLettuce.make();
           System.out.println("==========");
           
           /** 양상추 + 피클 샌드위치 */
           Sandwich sandwichWithLettuceAndPickle = new PickDecorator(new LettuceDecorator(new Bread()));
           snadwichWithLettuceAndPickle.make();
        }
    }

    마지막으로, 샌드위치를 만드는 Client 클래스를 구현한다.

    데커레이터 객체를 생성할 때, 생성자로 다시 데커레이터를 생성하고, 최종적으로 Bread 객체를 생성한다. 토핑이 더 늘어나도 이와 같이 계속 데커레이터 객체를 생성함으로써 샌드위치를 만들 수 있다.


    출처

    https://victorydntmd.tistory.com/297

     

    728x90

    댓글

Designed by Tistory.