자바/자바 자료실

[디자인패턴] 03. 데코레이터 패턴 (Decorator Pattern)

Chipmunks 2018. 10. 22.
728x90


데코레이터 패턴 (Decorator Pattern)

객체에 추가 요소를 동적으로 더할 수 있다. 데코레이터를 사용하면 서브 클래스를 만드는 것보다 훨씬 유연하게 기능을 확장할 수 있다.

객체지향 원칙

OCP (Open-Closed Principle)

클래스는 확장에 대해서는 열려 있지만, 변경에 대해서는 닫혀 있어야 한다.

장점과 단점

장점

  1. 데코레이터를 끼워도 클라이언트 쪽에서 데코레이터를 사용하고 있다는 것을 전혀 알지 못한다.

단점

  1. 자잘한 클래스들이 많이 추가된다. 남들이 보기에 한 눈에 이해하기 어려울 수 있다.
  2. 특정 형식에 의존하는 코드에 데코레이터를 적용하면, 원래 의도와 맞지 않는다.
  3. 구성 요소를 초기화하는 데 필요한 코드가 훨씬 복잡해진다.

다이어그램


Java.IO 클래스 다이어그램



FilterInputStream 클래스가 InputStream 클래스를 구성요소로 갖고있는 데코레이터 클래스다.


예제 코드

- Beverages/Beverage.java

1
2
3
4
5
6
7
8
9
10
11
12
package Beverages;
 
public abstract class Beverage {
    String description = "제목 없음";
    
    public String getDescription() {
        return description;
    }
    
    public abstract double cost();
}
 
cs


- Beverages/CondimentDecorator.java


1
2
3
4
5
6
package Beverages;
 
public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}
 
cs


- Beverages/Espresso.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
package Beverages;
 
public class Espresso extends Beverage {
 
    public Espresso() {
        description = "에스프레소";
    }
    
    public double cost() {
        return 1.99;
    }
 
}
 
cs


- Beverages/DarkLoast.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
package Beverages;
 
public class DarkRoast extends Beverage {
 
    public DarkRoast() {
        description = "다크 로스트 커피";
    }
    
    public double cost() {
        return .99;
    }
 
}
 
cs


- Beverages/HouseBlend.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
package Beverages;
 
public class HouseBlend extends Beverage {
 
    public HouseBlend() {
        description = "하우스 블렌드 커피";
    }
    
    public double cost() {
    return .89;
    }
 
}
 

cs


- Beverages/DeCaffeine.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
package Beverages;
 
public class DeCaffeine extends Beverage {
 
    public DeCaffeine() {
        description = "디카페인";
    }
    
    public double cost() {
        return 1.05;
    }
 
}
 
cs


- Beverages/Mocha.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package Beverages;
 
public class Mocha extends CondimentDecorator {
    Beverage beverage;
    
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    
    public String getDescription() {
        return beverage.getDescription() + ", 모카";
    }
 
    public double cost() {
        return .20 + beverage.cost();
    }
 
}
 
cs


- Beverages/SoybeanMilk.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package Beverages;
 
public class SoybeanMilk extends CondimentDecorator {
    Beverage beverage;
    
    public SoybeanMilk(Beverage beverage) {
        this.beverage = beverage;
    }
    
    public String getDescription() {
        return beverage.getDescription() + ", 두유";
    }
 
    public double cost() {
        return .15 + beverage.cost();
    }
 
}
 
cs


- Beverages/SteamMilk.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package Beverages;
 
public class SteamMilk extends CondimentDecorator {
    Beverage beverage;
    
    public SteamMilk(Beverage beverage) {
        this.beverage = beverage;
    }
    
    public String getDescription() {
        return beverage.getDescription() + ", 스팀밀크";
    }
 
    public double cost() {
        return .10 + beverage.cost();
    }
 
}
 
cs


- Beverages/WhippingCream.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package Beverages;
 
public class WhippingCream extends CondimentDecorator {
    Beverage beverage;
    
    public WhippingCream(Beverage beverage) {
        this.beverage = beverage;
    }
    
    public String getDescription() {
        return beverage.getDescription() + ", 휘핑크림";
    }
 
    public double cost() {
        return .10 + beverage.cost();
    }
 
}
 
cs


- Beverages/StarbuzzCoffee.java



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package Beverages;
 
public class StarbuzzCoffee {
 
    public static void main(String[] args) {
        Beverage beverage = new Espresso();
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
        
        Beverage beverage2 = new DarkRoast();
        beverage2 = new Mocha(beverage2);
        beverage2 = new Mocha(beverage2);
        beverage2 = new WhippingCream(beverage2);
        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
        
        Beverage beverage3 = new HouseBlend();
        beverage3 = new SoybeanMilk(beverage3);
        beverage3 = new Mocha(beverage3);
        beverage3 = new WhippingCream(beverage3);
        System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
    }
 
}
 
cs


- IODecorator/LowerCaseInputStream.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package IODecorator;
 
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
 
public class LowerCaseInputStream extends FilterInputStream {
    public LowerCaseInputStream(InputStream in) {
        super(in);
    }
    
    public int read() throws IOException {
        int c = super.read();
        return (c == -1 ? c : Character.toLowerCase((char)c));
    }
    
    public int read(byte[] b, int off, int len) throws IOException {
        int result = super.read(b, off, len);
        for (int i = off; i < off + result; i++) {
            b[i] = (byte)Character.toLowerCase((char)b[i]);
        }
        return result;
    }
}
 
cs


- IODecorator/InputTest.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package IODecorator;
 
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
 
public class InputTest {
 
    public static void main(String[] args) {
        int c;
        try {
            InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
            
            while ((c=in.read()) >= 0) {
                System.out.print((char)c);
            }
            
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
}
 
cs


댓글