CS/디자인패턴

[디자인패턴] Decorator 패턴 ( 꾸미기 패턴, 장식 패턴)

mabb 2023. 6. 19. 15:44
반응형

▶디자인 패턴 ( Design Pattern)
:프로그램 개발 시 문제 해결을 위하여 빈번히 사용되는 개발자들의 경험, 내적인 축적에 대하여,
GoF(Gang of Four) 라 불리는 4인의 개발자들이 각각을 패턴으로 정의하고 이름을 붙였다.
이를 디자인 패턴 (Design Pattern) 이라고 한다.
 23개의 디자인 패턴을
『Elements of Reusable Object-Oriented Software』
라는 책으로 발간하였다.

Gang of Four 분들은 모두 안경을 썼다.

 
▷디자인 패턴의 용어를 빌리면 서로의 아이디어를 보다 용이하게 비교, 논의할 수 있게 된다.
▷재사용과 기능확장이 쉬운 소프트웨어를 만들기 위한 유익한 기법이 바로 디자인 패턴이다.
 
---------------------------------------------------------
1. Iterator
2. Adapter
3. Template Method
4. Factory Method
5. Singleton
6. Prototype
7. Builder
8. Abstract Factory
9. Bridge
10. Strategy
11. Composite
12. Decorator
13. Visitor
14. Chain of Responsibility
15. Facade
16. Mediator
17. Observer
18. Memento
19. State
20. Flyweight
21. Proxy
22. Command
23. Interpreter
---------------------------------------------------------

▶Decorator 패턴

"내용물과 장식을 동일시"
"장식에 둘러싸인 내용물 자체를 또다시 내용물로 사용"
"FileReader를 BufferedFileReader , LineNumberReader 등으로 꾸미는 것과 같다"


-왜 사용하는가
-클래스다이어그램
-각 클래스(인터페이스)의 역할
-Java소스


▶Decorator 패턴에 대한 이해

-기본 오브젝트(객체)를 목적에 맞게 꾸며나가는 패턴이다.   

-decorate는 꾸미다, 장식이라는 뜻

-장식과 내용물을 동일시한다.

-장식과 내용물이 동일한 메소드를 가진다.

-같은 메소드를 가진다는 것은 인터페이스(API)적으로 동일시할 수 있다는 의미이다.

-데코레이터는 장식과 내용물을 동일시한다.

-장식에 둘러싸인 내용물이 내용물 그 자체가 될 수 있다.

-꾸민 내용물 그 자체를 또 내용물로 사용할 수 있다.

-재귀적 구조를 취하는 점이 Composite패턴과 유사하지만 Decorator패턴은 기능을 추가해 가는 것에 주안점을 둔다.

-java.io패키지에서 데코레이터 패턴을 사용하고 있다. LineNumberReader, BufferedReader등 보조스트림이 그렇다.

-유사한 성질의 작은 클래스가 많이 만들어진다는 단점이 있다.
-입력 받은 문자열을 콘솔 창에 읽어주는 예제를 만들어 보았다.
메인에서는 사용자 입력을 받고 기본 Reader 객체를 다양한 조합으로 꾸며본다.
기본 Reader를 데코레이터 하여 느리게 읽도록 꾸미거나 예쁘게 읽도록 꾸미거나 느리고 예쁘게 읽도록 꾸미는 등 다양하게 기본 객체를 목적에 맞게 꾸밀 수 있다.

2행과 4행은 한 글자 씩 느리게 읽는다.




 

▶왜 사용하는가

기본 오브젝트를 점점 꾸며나가며 기능을 발전시켜 나갈 때 사용한다. 기본 객체 (내용물, 기본형태의 객체)와 장식을 한 기본 객체를 동일 시하여 객체를 용도에 맞게 점점 꾸며나가기 위해 사용한다. 재귀적 구조라는 점에서 Composite패턴과 유사하지만 기본 객체를 용도에 맞게 점점 꾸며 나가는 것이 Decorator패턴의 주목적이라고 할 수 있다.

Reader reader = new FileReader("abc.txt"); // 기본 파일리더를
BufferedReader bufferedReader = new BufferedReader(reader); // 버퍼 리더로 꾸밈
LineNumberReader lineNumberReader = new LineNumberReader(bufferedReader) // 꾸민 것을 또 꾸밈

 

▶클래스다이어그램

 

▶각 클래스(인터페이스)의 역할

▷Main 역할

: 내용물(기본객체)를 용도에 맞게 꾸며서 사용하는 역할

▷Component 역할

: 내용물과 장식(Decorator)를 동일시할 수 있도록 해주는 역할

▷기본 객체 역할

: 목적에 맞도록 다양하게 꾸며서 사용할 수 있는 기본이 되는 객체

▷Decorator 역할

:  Component를 갖고, 구체적인 Decorator 들이 Component에게 위임하여 재귀적으로 기능을 수행할 수 있도록 하는 역할

▷구체적인 Decorator 역할

: 기본 객체를 구체적으로 꾸며주는 역할
 

▶Java 소스

*java1.8 이전 버전을 사용하는 교재를 참고 하였습니다.
Java API 문서 등을 참조하여 제네릭을 적용하는 등 소스를 개선할 필요가 있습니다.
(https://docs.oracle.com/en/java/javase/20/docs/api/)

▷Main.java

package main.java.designpattern.decorator2;

import java.util.*;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        System.out.println("문자열을 입력해주세요");
        String input = sc.nextLine();

        Component basic = new Reader(input);
        Component slow = new SlowReader(basic);
        Component beautiful = new BeautifulReader(basic);
        Component slowAndBeautiful = new BeautifulReader(slow);

        basic.read();
        slow.read();
        beautiful.read();
        slowAndBeautiful.read();

    }
}

 

▷Component.java -동일시 역할

package main.java.designpattern.decorator2;

public abstract class Component {
    protected void read(){
        for(String s:getStr().split("")){
            System.out.print(s);
            excute();
        }
        System.out.println();
    }
    protected abstract String getStr();
    protected abstract void excute();
}

 

▷Reader.java - 기본 객체

package main.java.designpattern.decorator2;

public class Reader extends Component{
    String str;
    public Reader(String str){
        this.str = str;
    }
    @Override
    protected String getStr() {
        return str;
    }
    @Override
    protected void excute() {
    }
}

 

▷Decorator.java -데코레이터 역할

package main.java.designpattern.decorator2;

public abstract class Decorator extends Component{
    protected Component component;
    protected Decorator(Component component){
        this.component = component;
    }
}

 

▷BeautifulReader.java -꾸미기 구현

package main.java.designpattern.decorator2;

public class BeautifulReader extends Decorator{
    protected BeautifulReader(Component component) {
        super(component);
    }
    @Override
    protected String getStr() {
        return component.getStr();
    }
    @Override
    protected void excute() {
        component.excute();
        System.out.print("★");
    }
}

 

▷SlowReader.java -꾸미기 구현

package main.java.designpattern.decorator2;

public class SlowReader extends Decorator{
    protected SlowReader(Component component) {
        super(component);
    }
    @Override
    protected String getStr() {
        return component.getStr();
    }
    @Override
    protected void excute() {
        try {
            component.excute();
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 
---------------------------------------------------------
※참고자료
-Java언어로 배우는 디자인 패턴 입문
-Headfirst Design Pattern
-나무위키, 위키백과, 네이버백과
-리팩토링구루(https://refactoring.guru/ko)

반응형