본문 바로가기

코딩/Software Architecture

[GoF Design Pattern] Decorator

* Decorator Pattern

Decorator : 장식하는 사람이라는 뜻. 기능을 마치 장식처럼 계속 추가할 수 있는 패턴. 또 기능을 실행 중에 동적으로 변경, 확장할 수 있는 패턴. SW의 확장성이 매우 높아짐.

Strings: 문자열을 여러 개 가지고 있음. 장식할 대상. 장식이 없는 내용물.

Decorator: Strings의 장식들을 나타내는 클래스.

3개의 Decorator를 상속하는 클래스 : 구체적인 장식을 구현한 클래스

Item : Strings 와 Decorator가 상속하는 클래스. 두 개의 서로 다른 개념을 하나의 개념으로 다룰 수 있는 장치. 내용물과 장식에 대한 구분 없이 둘을 동일한 개념으로 다룰 수 있음.

장식 필요한 기본 Strings 와 장식 하는 객체 Decorator 를 하나의 개념으로 다루기 위한 추상 클래스 Item  

아래 예제는 기본 Strings 에 장식을 다는 예로, Item 클래스에선 기본적으로 출력하는 메서드가 있다.

public abstract class Item {
    public abstract int getLinesCount(); // 문자열의 개수 (라인 수) 반환
    public abstract int getMaxLength(); // 문자열 중 가장 긴 문자열 길이 반환
    public abstract int getLength(int index); // 지정된 index의 문자열 길이 반환
    public abstract String getString(int index); // 지정된 index의 문자열 반환
    
    public void print() {
    	int cntLines = getLinesCount();
        for(int i=0; i<cntLines; i++) {
        	String string = getString(i);
            System.out.println(string);
        }
    }
}

장식이 없는 상태 Strings

public class Strings extends Item {
    private ArrayList<String> strings = new ArrayList<>();
    
    public void add(String item) {
    	strings.add(item);
    }
    
    @Override
    public int getLinesCount() {
        return strings.size();
    }
    
    @Override
    public int getMaxLength() {
        Iterator<String> iter = strings.iterator();
        int maxWidth = 0;
        
        while(iter.hasNext()) {
            String string = iter.next();
            int width = string.length();
            
            if(width > maxWidth) maxWidth = width;
        }
        return maxWidth;
    }
    
    @Override
    public int getLength(int index) {
    	String string = strings.get(index);
        return string.length();
    }
    
    @Override
    public String getString(int index) {
        return strings.get(index);
    }
    
}

장식을 위해 Item 객체를 필드에 갖는 Decorator 추상 클래스.

public abstract class Decorator extends Item {
    protected Item item;
    
    public Decorator(Item item) {
    	this.item = item;
    }
    
}

Item의 좌, 우에 ch를 추가하는 SideDecorator

public class SideDecorator extends Decorator {
    private Chractor ch;
    
    public SideDecorator(Item item, Charactor ch) {
    	super(item);
        this.ch = ch;
    }
    
    @Override
    public int getLinesCount() {
        return item.getLinesCount();
    }
    
    @Override
    public int getMaxLength() {
        return item.getMaxLength() + 2;
    }
    
    @Override
    public int getLength(int index) {
    	return item.getLength(index) + 2;
    }
    
    @Override
    public String getString(int index) {
        return ch + item.getString(index) + ch;
    }    
}

Strings를 박스로 감싸는 BoxDecorator 

public class BoxDecorator extends Decorator {
    public BoxDecorator(Item item) {
        super(item);
    }
    
    @Override
    public int getLinesCount() {
        return item.getLinesCount() + 2;
    }
    
    @Override
    public int getMaxLength() {
        return item.getMaxLength() + 2;
    }
    
    @Override
    public int getLength(int index) {
    	return item.getLength(index) + 2;
    }
    
    @Override
    public String getString(int index) {
        int maxWidth = this.getMaxLength();
        if(index == 0 || index == getLineCount()-1) {
            StringBuilder sb = new StringBuilder();
            sb.append('+');
            for(int i=0; i<maxWidth-2; i++) {
                sb;append('-');
            }
            sb.append('+');
            return sb.toString();
        } else {
            return '|' + item.getString(index-1)
                + makeTailString(maxWidth - getLength(index -1));
        }
    }
    
    private String makeTailString(int count) {
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<count; i++) {
            sb.append(' ');
        }
        sb.append('|')l
        
        return sb.toString();
    }
}

구현한 클래스를 main 에서 사용해본다.

public static void main(String[] args) {
    Strings strings = new Strings();
    
    strings.add("Hello");
    strings.add("My name is Choi");
    strings.add("I am a JAVA Developer.");
    strings.add("Design-Pattern is powerful tool.");
    
    Item decorator = new SideDecorator(strings, '\"');
    decorator = new BoxDecorator(decorator);
    
    decorator.print();

'코딩 > Software Architecture' 카테고리의 다른 글

[GoF Design Pattern] Chain of Responsibility  (0) 2022.12.06
[GoF Design Pattern] Mediator  (0) 2022.12.06
[GoF Design Pattern] Memento  (0) 2022.12.05
[GoF Design Pattern] Builder  (0) 2022.12.04
[GoF Design Pattern] Facade  (0) 2022.12.04