Post

โ›“๏ธ Java Design-Pattern โ…ฉโ…ข - Decorator

โ›“๏ธ Java Design-Pattern โ…ฉโ…ข - Decorator

๐Ÿ“— ใ€ŽJAVA ์–ธ์–ด๋กœ ๋ฐฐ์šฐ๋Š” ๋””์ž์ธ ํŒจํ„ด : ์‰ฝ๊ฒŒ ๋ฐฐ์šฐ๋Š” GoF์˜ 23๊ฐ€์ง€ ๋””์ž์ธ ํŒจํ„ดใ€๋ฅผ ์ฝ๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

Decorator ํŒจํ„ด์ด๋ž€?

  • ๊ฐ์ฒด์— ์ ์  ์žฅ์‹์„ ๋”ํ•ด ๊ฐ€๋Š” ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค.

์˜ˆ์ œ ํ”„๋กœ๊ทธ๋žจ

  • ๋ฌธ์ž์—ด ์ฃผ์œ„์— ์žฅ์‹ํ‹€์„ ๋ถ™์—ฌ ์ถœ๋ ฅํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

Displayย ํด๋ž˜์Šค

1
2
3
4
5
6
7
8
9
10
11
public abstract class Display {
	public abstract int getColumns();
    public abstract int getRows();
    public abstract String getRowText(int row);
    
    public void show() {
    	for (int i = 0; i < getRows(); i++) {
        	System.out.println(getRowText(i));
        }
    }
}
  • ์—ฌ๋Ÿฌ ํ–‰์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฌธ์ž์—ด์„ ํ‘œ์‹œํ•˜๋Š” ์ถ”์ƒ ํด๋ž˜์Šค์ด๋‹ค.
  • getColumns,ย getRows๋Š” ๊ฐ๊ฐ ๋ฌธ์ž์—ด์˜ ํ–‰๋ ฌ ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ถ”์ƒ ๋ฉ”์†Œ๋“œ์ด๋‹ค.
  • getRowText๋Š” ์ง€์ •ํ•œ ํ–‰์˜ ๋ฌธ์ž์—ด์„ ๊ฐ€์ ธ์˜ค๋Š” ์ถ”์ƒ ๋ฉ”์†Œ๋“œ์ด๋‹ค.
  • show๋Š” ๋ชจ๋“  ํ–‰์„ ํ‘œ์‹œํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ,ย getRows์™€ย getRow-Text๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œย Template Methodย ํŒจํ„ด์œผ๋กœ ๋˜์–ด ์žˆ๋‹ค.

StringDisplayย ํด๋ž˜์Šค

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
public class StringDisplay extends Display {
	private String string;
    
    public StringDisplay(String string) {
    	this.string = string;
    }
    
    @Override
    public int getColumns() {
    	return string.length();
    }
    
    @Override
    public int getRows() {
    	return 1;
    }
    
    @Override
    public String getRowText(int row) {
    	if (row != 0) {
        	throw new IndexOutOfBoundsException();
        }
        return string;
    }
}
  • Displayย ํด๋ž˜์Šค์˜ ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ํ•˜์œ„ ํด๋ž˜์Šค์ด๋‹ค.
  • stringย ํ•„๋“œ๋Š” ํ‘œ์‹œํ•  ๋ฌธ์ž์—ด ํ•œ ์ค„์„ ๋ณด๊ด€ํ•˜๋ฉฐ,ย getColumns๋Š” ๋ฌธ์ž์—ด ๊ธธ์ด๋ฅผ,ย getRows๋Š” 1์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Borderย ํด๋ž˜์Šค

1
2
3
4
5
6
7
public abstract class Border extends Display {
	protected Display display;
    
    protected Border(Display display) {
    	this.display = display;
    }
}
  • displayย ํ•„๋“œ๋Š” ์ด ์žฅ์‹ํ‹€์ด ๊ฐ์‹ธ๋Š” ๋‚ด์šฉ๋ฌผ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ๋‚ด์šฉ๋ฌผ์€ย Displayย ํด๋ž˜์Šค์˜ ํ•˜์œ„ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.

SideBorderย ํด๋ž˜์Šค

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class sideBorder extends Border {
	private char borderChar;
    
    public sideBorder(Display display, char ch) {
    	super(display);
        this.borderChar = ch;
    }
    
    @Override
    public int getColumns() {
    	return 1 + display.getColumns() + 1;
    }
    
    @Override
    public int getRows() {
    	return display.getRows();
    }
    
    @Override
    public String getRowText(int row) {
    	return borderChar + display.getRowText(row) + borderChar;
    }
}
  • SideBorderย ํด๋ž˜์Šค๋Š”ย Borderย ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ, ๋ฌธ์ž์—ด ์–‘์˜†์—ย borderChar๋กœ ์žฅ์‹ํ•œ๋‹ค.
  • displayย ํ•„๋“œ๋Š”ย Borderย ํด๋ž˜์Šค์—์„œย protected๋กœ ์„ ์–ธ ๋์œผ๋ฏ€๋กœ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

FullBorderย ํด๋ž˜์Šค

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
27
28
29
30
31
32
33
34
35
public class FullBorder extends Border {
	public FullBorder(Display display) {
    	super(display);
    }
    
    @Override
    public int getColumns() {
    	return 1 + display.getColumns() + 1;
    }
    
    @Override
    public int getRows() {
    	return 1 + display.getRows() + 1;
    }
    
    @Override
    public String getRowText(int row) {
    	if (row == 0) {
        	return "+" + makeLine('-', display.getColumns()) + "+";
        } else if (row == display.getRows() + 1) {
        	return "+" + makeLine('-', display.getColumns()) + "+";
        } else {
        	return "|" + display.getRowText(row - 1) + "|";
        }
    }
    
    private String makeLine(char ch, int count) {
    	StringBuilder line = new StringBuilder();
        
        for (int i = 0; i < count; i++) {
        	line.append(ch);
        }
        return line.toString();
    }
}
  • SideBorderย ํด๋ž˜์Šค์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœย Border์˜ ํ•˜์œ„ ํด๋ž˜์Šค ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ, ๊ณ ์ •๋œ ์žฅ์‹ ๋ฌธ์ž๋กœ ์ƒํ•˜์ขŒ์šฐ๋ฅผ ์žฅ์‹ํ•œ๋‹ค.
  • makeLine์€ ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋„๋กย private๋กœ ๋˜์–ด ์žˆ๋‹ค.

Mainย ํด๋ž˜์Šค

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
public class Main {
	public static void main(String[] args) {
		Display d1 = new StringDisplay("Hello, world.");
        Display d2 = new SideBorder(d1, '#');
        Display d3 = new StringDisplay(d2);
        
        d1.show();
        d2.show();
        d3.show();
        
        Display d4 = new SideBorder(
        	new FullBorder(
            	new FullBorder(
                	new SideBorder(
                    	new FullBorder(
                        	new StringDisplay("Hello, world.")
                        ), '*'
                    )
                )
            ), '/'
        );
        
        d4.show();
	}
}
  • ๋™์ž‘ ํ…Œ์ŠคํŠธ์šฉย Mainย ํด๋ž˜์Šค์ด๋‹ค.

Decoratorย ํŒจํ„ด์˜ ๋“ฑ์žฅ์ธ๋ฌผ

Displayย ํด๋ž˜์Šค

  • ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ํ•ต์‹ฌ์ด ๋˜๋Š”ย Componentย ์—ญํ• ์ด๋‹ค.
  • ์žฅ์‹ํ•˜๊ธฐ ์ „์˜ ์ธํ„ฐํŽ˜์ด์Šคย API์— ํ•ด๋‹นํ•œ๋‹ค.

StringDisplayย ํด๋ž˜์Šค

  • Component์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”ย Concrete Componentย ์—ญํ• ์— ํ•ด๋‹นํ•œ๋‹ค.

Borderย ํด๋ž˜์Šค

  • Component์™€ ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ง€๋ฉฐ ์žฅ์‹์žย Decoratorย ์—ญํ• ์„ ํ•œ๋‹ค.
  • ๋˜ํ•œย Component๋ฅผ ํ•„๋“œ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ,ย ์ž์‹ ์ด ์žฅ์‹ํ•  ๋Œ€์ƒ์„ ์•„๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.

SideBorder,ย FullBorderย ํด๋ž˜์Šค

  • ๊ตฌ์ฒด์ ์ธ ์žฅ์‹์žย ConcreteDecoratorย ์—ญํ• ์„ ๋งก์•˜๋‹ค.

์ฑ…์—์„œ ์ œ์‹œํ•˜๋Š” ํžŒํŠธ

ํˆฌ๊ณผ์  ์ธํ„ฐํŽ˜์ด์Šคย API

  • ํ•ด๋‹น ํŒจํ„ด์—์„œ๋Š” ์žฅ์‹ํ‹€๊ณผ ๋‚ด์šฉ๋ฌผ์„ ๋™์ผ์‹œ ํ•œ๋‹ค.ย 
  • Borderย ํด๋ž˜์Šค๊ฐ€ย Displayย ํด๋ž˜์Šค์˜ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ๋˜์–ด ์žˆ๋Š” ๋ถ€๋ถ„์—์„œ ๊ทธ ๋™์ผ์‹œ๊ฐ€ ํ‘œํ˜„๋˜์–ด ์žˆ๋‹ค.
  • ์ฆ‰ย Borderย ํด๋ž˜์Šค ๋ฐ ๊ทธ ํ•˜์œ„ ํด๋ž˜์Šค๋“ค์€ย Displayย ํด๋ž˜์Šค์™€ ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • ์ด ๋•Œ ์žฅ์‹ํ‹€์„ ์‚ฌ์šฉํ•ด ๋‚ด์šฉ๋ฌผ์„ ๊ฐ์‹ธ๊ณ  ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ „ํ˜€ ๊ฐ€๋ ค์ง€์ง€ ์•Š๋Š”๋‹ค.ย 
  • getColumns,ย getRows,ย getRowText,ย showย ๋ฉ”์†Œ๋“œ๋Š” ๊ฐ€๋ ค์ง€์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ํด๋ž˜์Šค์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์œ„์ž„์„ ์‚ฌ์šฉํ•œ๋‹ค.

  • ์žฅ์‹ํ‹€์— ๋Œ€ํ•œ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ์€ ๊ทธ ๋‚ด์šฉ๋ฌผ๋กœ ์œ„์ž„๋œ๋‹ค.
  • ์˜ˆ์ œ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š”ย SideBorder์˜ย getColumnsย ๋ฉ”์†Œ๋“œ์—์„œย display.getColumns๋ฅผ ํ˜ธ์ถœํ•˜๊ณ ,ย getRowsย ๋ฉ”์†Œ๋“œ์—์„œย display.getRows๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  • ์ฆ‰ ๋‚ด์šฉ๋ฌผ์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
  • ๋˜ํ•œ ์œ„์ž„์„ ํ†ตํ•ด ํด๋ž˜์Šค ์‚ฌ์ด๋ฅผ ๋™์ ์œผ๋กœ ๊ฒฐํ•ฉํ•˜๋Š”๋ฐ, ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์†Œ์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด์˜ ๊ด€๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

java.ioย ํŒจํ‚ค์ง€์™€ย Decoratorย ํŒจํ„ด

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
// 1. ํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด ๋“ค์ž„
Reader reader = new FileReader("datafile.txt");

// 2. ํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด ๋“ค์ผ ๋•Œ ๋ฒ„ํผ๋ง
Reader reader = new BufferedReader(
	new FileReader("datafile.txt")
);

// 3. 2๋ฒˆ์— ํ–‰ ๋ฒˆํ˜ธ ๊ด€๋ฆฌ๋ฅผ ์ถ”๊ฐ€
Reader reader = new LineNumberReader(	
	new BufferedReader(
		new FileReader("datafile.txt")
	)
);

// 4. 3๋ฒˆ์— ํŒŒ์ผ์„ ์ฝ์–ด ๋“ค์ด๋Š” ๋Œ€์‹  ๋„คํŠธ์›Œํฌ๋กœ๋ถ€ํ„ฐ ์ฝ์–ด ๋“ค์ž„
Socket socket = new Socket(hostName, portNumber);

Reader reader = new LineNumberReader(	
	new BufferedReader(
		new InputStreamReader(
        	socket.getInputStream();
        )
	)
);
  • java.ioย ์™ธ์—๋„ย java.swing.borderย ํŒจํ‚ค์ง€์—์„œ๋„ย Decoratorย ํŒจํ„ด์ด ๋“ฑ์žฅํ•œ๋‹ค.

java.nio.file.Files

  • java.ioย ํŒจํ‚ค์ง€์—์„œ ํ•ด๋‹น ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์€ ์ผ์ผ์ด ์—ฌ๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ์กฐํ•ฉํ•˜์ง€ ์•Š์•„๋„ ๊ด€๋ จ ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

์ƒ์†๊ณผ ์œ„์ž„์˜ ๋™์ผ์‹œ

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/* 1-1. ์ƒ์† - ํ•˜์œ„ ํด๋ž˜์Šค์™€ ์ƒ์œ„ ํด๋ž˜์Šค ๋™์ผ์‹œ */
class Parent {
	void parentMethod() {
    	// ...
    }
}

class Child extends Parent {
	// ...
    
    void childMethod() {
    	// ...
    }
}

/* 1-2. ์ƒ์† - ํด๋ž˜์Šค๊ฐ„ ๋Œ€์ž… */
Parent obj = new Child();
obj.parentMethod(); // ์บ์ŠคํŠธ ์—†์ด ๋Œ€์ž… ๊ฐ€๋Šฅ

Parent obj = new Child();
((Child) obj).childMethod(); // ์บ์ŠคํŠธ ํ•„์š”

/* 2-1. ์œ„์ž„ - ์•ฝํ•œ ์—ฐ๊ฒฐ */
class Rose {
	Violet obj = /* ... */;
    
    void method() {
    	obj.method();
    }
}

class Violet {
	void method() {
    	// ... 
    }
}

/* 2-2-1. ์œ„์ž„ - ์ถ”์ƒ ํด๋ž˜์Šค ๊ฐ•ํ•œ ์—ฐ๊ฒฐ */
abstract class Flower {
	abstract void method();
}

class Rose extends Flower {
	Violet obj = /* ... */;
    
    @Override
    void method() {
    	obj.method();
    }
}

class Violet extends Flower {
	@Override
    void method() {
    	// ... 
    }
}

/* 2-2-2. ์œ„์ž„ - ์ธํ„ฐํŽ˜์ด์Šค ๊ฐ•ํ•œ ์—ฐ๊ฒฐ */
interface Flower {
	abstract void method();
}

class Rose implements Flower {
	Violet obj = /* ... */;
    
    @Override
    void method() {
    	obj.method();
    }
}

class Violet implements Flower() {
	@Override
    void method() {
    	// ... 
    }
}
  • ํ•˜์œ„ ํด๋ž˜์Šค๋Š” ์ƒ์œ„ ํด๋ž˜์Šค ๋ณ€์ˆ˜์— ๋ฐ”๋กœ ๋Œ€์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฐ˜๋ฉด ์ƒ์œ„ ํด๋ž˜์Šค๋ฅผ ํ•˜์œ„ ํด๋ž˜์Šค์— ๋Œ€์ž…ํ•˜๋ ค๋ฉด ์บ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • ์œ„์ž„์„ ์‚ฌ์šฉํ•ด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํˆฌ๊ณผ์ ์œผ๋กœ ๋˜์–ด ์žˆ์„ ๋•Œ๋Š” ์ž์‹ ๊ณผ ์œ„์ž„ํ•œ ๊ณณ์„ ๋™์ผ์‹œ ํ•  ์ˆ˜ ์žˆ๋‹ค.
This post is licensed under CC BY 4.0 by the author.