๐จ 03. ๋ฐ์ฝ๋ ์ดํฐ ํจํด
โย ์ด๋ํ ์ปคํผ ์ ๋ฌธ์ , ์คํ๋ฒ์ฆ
๋จ๊ธฐ๊ฐ์ ํญ๋ฐ์ ์ผ๋ก ์ฑ์ฅํ ์คํ๋ฒ์ฆ ์นดํ๋ ๋ค์ํ ์๋ฃ๋ฅผ ๋ชจ๋ ํฌ๊ดํ๋ ์ฃผ๋ฌธ ์์คํ ์ ๊ฐ์ถ์ง ๋ชปํ๋ค. ์ฌ์ ์ด ์์ ํ๋ ์ง๊ธ์์์ผ ์ฃผ๋ฌธ ์์คํ ์ ๊ฐ์ ํ๋ ค๊ณ ๋ ธ๋ ฅํ๋ ์ค์ธ๋ฐ, ์ฌ์ ์ ์์ํ ๋ฌด๋ ต ๋ง๋ค์ด์ง ์ฃผ๋ฌธ ์์คํ ํด๋์ค๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑ๋์๋ค.
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
// ์๋ฃ๋ฅผ ๋ํ๋ด๋ ์ถ์ ํด๋์ค
abstract class Beverage {
protected description: string = "์ ์ ์๋ ์๋ฃ";
getDescription(): string {
return this.description;
}
// cost()๋ ์๋ธํด๋์ค์์ ๋ฐ๋์ ๊ตฌํํด์ผ ํ๋ ์ถ์ ๋ฉ์๋
abstract cost(): number;
}
// ๋คํฌ ๋ก์คํธ ์ปคํผ ์๋ธํด๋์ค
class DarkRoast extends Beverage {
constructor() {
super();
this.description = "๊ฐ์ฅ ํ๋ฅญํ ๋คํฌ ๋ก์คํธ ์ปคํผ";
}
cost(): number {
return 2.99;
}
}
// ํ์ฐ์ค ๋ธ๋ ๋ ์ปคํผ ์๋ธํด๋์ค
class HouseBlend extends Beverage {
constructor() {
super();
this.description = "๋ถ๋๋ฌ์ด ํ์ฐ์ค ๋ธ๋ ๋ ์ปคํผ";
}
cost(): number {
return 2.49;
}
}
// ์ฌ์ฉ ์์
const myCoffee: Beverage = new DarkRoast();
console.log(myCoffee.getDescription()); // ๊ฐ์ฅ ํ๋ฅญํ ๋คํฌ ๋ก์คํธ ์ปคํผ
console.log(`๊ฐ๊ฒฉ: $${myCoffee.cost()}`); // ๊ฐ๊ฒฉ: $2.99
Beverage๋ ์๋ฃ๋ฅผ ๋ํ๋ด๋ ์ถ์ ํด๋์ค์ด๋ฉฐ ๋งค์ฅ์์ ํ๋งค๋๋ ๋ชจ๋ ์๋ฃ๋ ํด๋น ํด๋์ค์ ์๋ธํด๋์ค๊ฐ ๋จ.description์ด๋ผ๋ ์ธ์คํด์ค ๋ณ์๋ ๊ฐ ์๋ธํด๋์ค์์ ์ค์ ๋๋ฉฐ, ๋ณ์์ ์ ์ฅ๋ ๋ด์ฉ์getDescription()๋ฉ์๋๋ฅผ ํธ์ถํด์ ํ์ธํ ์ ์์.cost()๋ฉ์๋๋ ์ถ์ ๋ฉ์๋๋ก, ๋ชจ๋ ์๋ธํด๋์ค์์ ์๋ฃ์ ๊ฐ๊ฒฉ์ ๋ฆฌํดํ๋cost()๋ฉ์๋๋ฅผ ๊ตฌํํ์ฌ ์๋ก ์ ์ํด์ผ ํจ.
๊ณ ๊ฐ์ ์ปคํผ๋ฅผ ์ฃผ๋ฌธํ ๋ ์ฐ์ ๋ ๋์ , ๋ชจ์นด๋ฅผ ์ถ๊ฐํ๊ณ ๊ทธ ์์ ํํํฌ๋ฆผ์ ์น๊ธฐ๋ ํ๋ค. ๊ฐ๊ฐ์ ์ถ๊ฐํ ๋๋ง๋ค ์ปคํผ ๊ฐ๊ฒฉ์ด ์ฌ๋ผ๊ฐ์ผ ํ๊ธฐ์ ์ฃผ๋ฌธ ์์คํ ์ ๊ตฌํํ ๋ ์ด๋ฐ ์ ์ ๋ชจ๋ ๊ณ ๋ คํด์ผ ํ๋ค.
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
class DarkRoast {
description: string = "๊ฐ์ฅ ํ๋ฅญํ ๋คํฌ ๋ก์คํธ ์ปคํผ";
cost(): number {
return 2.99;
}
}
class HouseBlend {
description: string = "๋ถ๋๋ฌ์ด ํ์ฐ์ค ๋ธ๋ ๋ ์ปคํผ";
cost(): number {
return 2.49;
}
}
// ๐ฅ: ์กฐํฉ๋ณ๋ก ์๋ก์ด ํด๋์ค๋ฅผ ์ถ๊ฐํด์ผ ํจ
class DarkRoastWithMilk {
description: string = "๊ฐ์ฅ ํ๋ฅญํ ๋คํฌ ๋ก์คํธ ์ปคํผ + ์ฐ์ ";
cost(): number {
return 2.99 + 0.50;
}
}
class DarkRoastWithMilkAndWhip {
description: string = "๊ฐ์ฅ ํ๋ฅญํ ๋คํฌ ๋ก์คํธ ์ปคํผ + ์ฐ์ + ํํํฌ๋ฆผ";
cost(): number {
return 2.99 + 0.50 + 0.60;
}
}
class HouseBlendWithMocha {
description: string = "๋ถ๋๋ฌ์ด ํ์ฐ์ค ๋ธ๋ ๋ ์ปคํผ + ์ด์ฝ๋ฆฟ";
cost(): number {
return 2.49 + 0.70;
}
}
.
.
.
โ ์ง๊ธ๊น์ง ๋ฐฐ์ด ๋์์ธ ์์น ์ค ๋ฌด์์ ์งํค์ง ์๊ณ ์์๊น?
๐ก ๋์์ธ ์์น 1: ๋ณํ๋ ๋ถ๋ถ์ ์บก์ํํ๋ผ
- ์ฐ์ ๊ฐ๊ฒฉ, ์ถ๊ฐ ์ต์
(ํํํฌ๋ฆผ, ์ด์ฝ๋ฆฟ ๋ฑ)์ ๋ณํ๋ ์์์ธ๋ฐ, ์ด๊ฑธ
cost()๋ฉ์๋ ์์์ ์ง์ ํ๋์ฝ๋ฉํ๊ณ ์์.
๐ก ๋์์ธ ์์น 2: ์์๋ณด๋ค๋ ๊ตฌ์ฑ(Composition)์ ํ์ฉํ๋ผ
- ํ์ฌ ๊ตฌ์กฐ๋
DarkRoastWithMilkAndCaramel๊ฐ์ ํด๋์ค๋ฅผ ๊ณ์ ์์ํด์ ๋ง๋ค๊ณ ์์.
๐ก ๋์์ธ ์์น 3: ํด๋์ค๋ ํ์ฅ์๋ ์ด๋ ค ์์ด์ผ ํ์ง๋ง, ๋ณ๊ฒฝ์๋ ๋ซํ ์์ด์ผ ํ๋ค. (OCP - ๊ฐ๋ฐฉ/ํ์ ์์น)
- ์ฐ์ ๊ฐ๊ฒฉ์ด ๋ฐ๋๊ฑฐ๋, ์๋ก์ด ์ฌ๋ฃ(์บ๋ฌ๋ฉ ๋ฑ)๊ฐ ์ถ๊ฐ๋ ๋,๊ธฐ์กด ์ฝ๋๋ฅผ ์์ ํด์ผ ํ๋ ๊ตฌ์กฐ์ด๋ฏ๋ก OCP ์์น์ ์ด๊ธฐ๊ณ ์์.
์ธ์คํด์ ๋ณ์์ ์ํผํด๋์ค ์์์ ์จ์ ์ฒจ๊ฐ๋ฌผ์ ๊ด๋ฆฌํ๋ฉด ๋์ง ์์๊น?
๐ย Beverage ํด๋์ค (์๋ฃ ๊ธฐ๋ณธ ํด๋์ค)
description: ์๋ฃ ์ค๋ช ์ ์ ์ฅํ๋ ๋ณ์ (์: โ๊ฐ์ฅ ํ๋ฅญํ ๋คํฌ ๋ก์คํธ ์ปคํผโ)hasMilk,hasSoy,hasMocha,hasWhip: ์ฒจ๊ฐ๋ฌผ์ด ์ถ๊ฐ๋์๋์ง ์ฌ๋ถ๋ฅผ ์ ์ฅํ๋ ๋ถ๋ฆฌ์ธ ๊ฐsetMilk(),setSoy(),setMocha(),setWhip(): ์ฒจ๊ฐ๋ฌผ์ ์ถ๊ฐํ๋ ๋ฉ์๋cost(): ์๋ธํด๋์ค์์ ์ด ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ถ๊ฐ ๋น์ฉ์ ๋ํ ์ ์์
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
class Beverage {
description: string = "์ ์ ์๋ ์๋ฃ";
hasMilk: boolean = false;
hasSoy: boolean = false;
hasMocha: boolean = false;
hasWhip: boolean = false;
getDescription(): string {
return this.description;
}
setMilk(): void {
this.hasMilk = true;
}
setSoy(): void {
this.hasSoy = true;
}
setMocha(): void {
this.hasMocha = true;
}
setWhip(): void {
this.hasWhip = true;
}
cost(): number {
let totalCost = 0;
// ์๋ฃ ๊ธฐ๋ณธ ๊ฐ๊ฒฉ (์๋ธํด๋์ค์์ ์ค์ )
totalCost += this.getBaseCost();
// ์ฒจ๊ฐ๋ฌผ ๊ฐ๊ฒฉ ์ถ๊ฐ
if (this.hasMilk) totalCost += 0.50;
if (this.hasSoy) totalCost += 0.60;
if (this.hasMocha) totalCost += 0.70;
if (this.hasWhip) totalCost += 0.60;
return totalCost;
}
}
๐ DarkRoast & HouseBlend ํด๋์ค (์๋ฃ ์ข
๋ฅ๋ณ ํด๋์ค)
DarkRoast์HouseBlendํด๋์ค๋Beverageํด๋์ค๋ฅผ ์์๋ฐ์.Beverageํด๋์ค์์cost()๋ฅผ ๊ธฐ๋ณธ ๊ตฌํ (์ฒจ๊ฐ๋ฌผ ๊ฐ๊ฒฉ๋ง ๊ณ์ฐ)- ์๋ธํด๋์ค(
DarkRoast,HouseBlend)์์๋ ๊ธฐ๋ณธ ๊ฐ๊ฒฉ๋ง ์ค์ ํ๊ณ ,super.cost()ํธ์ถ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class DarkRoast extends Beverage {
constructor() {
super();
this.description = "๊ฐ์ฅ ํ๋ฅญํ ๋คํฌ ๋ก์คํธ ์ปคํผ";
}
cost(): number {
return 2.99 + super.cost(); // ๊ธฐ๋ณธ ๊ฐ๊ฒฉ + ์ฒจ๊ฐ๋ฌผ ๊ฐ๊ฒฉ
}
}
class HouseBlend extends Beverage {
constructor() {
super();
this.description = "๋ถ๋๋ฌ์ด ํ์ฐ์ค ๋ธ๋ ๋ ์ปคํผ";
}
cost(): number {
return 2.49 + super.cost(); // ๊ธฐ๋ณธ ๊ฐ๊ฒฉ + ์ฒจ๊ฐ๋ฌผ ๊ฐ๊ฒฉ
}
}
์ด ํ๋ก์ ํธ์์ ๋ณ๊ฒฝ๋์์ ๋ ๋์์ธ์ ์ํฅ์ ๋ฏธ์น ๋งํ ์์๋ฅผ ์ ์ด๋ณด์.
- ์ฒจ๊ฐ๋ฌผ ๊ฐ๊ฒฉ์ด ๋ฐ๋ ๋๋ง๋ค ๊ธฐ์กด ์ฝ๋๋ฅผ ์์ ํด์ผ ํ๋ค.
- ์ฒจ๊ฐ๋ฌผ ๊ฐ๊ฒฉ์ด ๋ฐ๋๋ฉด
Beverageํด๋์ค์cost()๋ฉ์๋์์ ์ง์ ์์ ํด์ผ ํจ. - ํ์ฅ์ฑ์ด ๋จ์ด์ง. ์๋ก ์ถ๊ฐ๋ ๊ฐ๊ฒฉ ๋ณํ๊ฐ ์์ ๋๋ง๋ค ๋ชจ๋ ์๋ธํด๋์ค๋ฅผ ์์ ํด์ผ ํ ์ ์์.
- ์ฒจ๊ฐ๋ฌผ ๊ฐ๊ฒฉ์ด ๋ฐ๋๋ฉด
- ์ฒจ๊ฐ๋ฌผ์ ์ข
๋ฅ๊ฐ ๋ง์์ง๋ฉด ์๋ก์ด ๋ฉ์๋๋ฅผ ์ถ๊ฐํด์ผ ํ๊ณ , ์ํผํด๋์ค์
cost()๋ฉ์๋๋ ๊ณ ์ณ์ผ ํ๋ค.- ์๋ก์ด ์ฒจ๊ฐ๋ฌผ์ด ์ถ๊ฐ๋๋ฉด
setMilk(),setSoy()๊ฐ์ ๋ฉ์๋๋ฅผ ํ๋์ฉ ์ถ๊ฐํด์ผ ํ๋ฏ๋ก ์ ์ง๋ณด์๊ฐ ์ด๋ ค์์ง. - ์ฒจ๊ฐ๋ฌผ ์ข
๋ฅ๊ฐ ๋ง์์ง์๋ก ์ํผํด๋์ค
cost()๋ฉ์๋๊ฐ ๋ณต์กํด์ง.
- ์๋ก์ด ์ฒจ๊ฐ๋ฌผ์ด ์ถ๊ฐ๋๋ฉด
- ์๋ก์ด ์๋ฃ๊ฐ ์ถ์๋ ์๋ ์๋ค. ํน์ ์ฒจ๊ฐ๋ฌผ์ด ๋ค์ด๊ฐ๋ฉด ์ ๋๋ ์๋ฃ๋ ์์ ๊ฒ์ด๋ค.
- ์๋ฃ ๋ณ๋ก ์ฒจ๊ฐ๋ฌผ์ด ์ ํ๋ ์ ์์. ์๋ฅผ ๋ค์ด, ์ด๋ค ์๋ฃ๋ ์ฐ์ ๋ ๋์ ๋ฅผ ๋ฃ์ ์ ์์ ์ ์์.
Beverageํด๋์ค์ ๊ตฌํ์ ์์ ํด์ผ ํ๋๋ฐ, ์ ์ฝ์ด ๋ง์์ง๋ฉด ์ ์ง๋ณด์๊ฐ ํ๋ค์ด์ง.
- ๊ณ ๊ฐ์ด ๋๋ธ ๋ชจ์นด๋ฅผ ์ฃผ๋ฌธํ๋ฉด ์ด๋ป๊ฒ ํด์ผ ๋ ๊น?
- ๋๋ธ ๋ชจ์นด๋ ๋ชจ์นด๋ฅผ ๋ ๋ฒ ๋ฃ๋ ์ต์
์ด๋ฏ๋ก, ์ด๋ฅผ ๊ตฌํํ๋ ค๋ฉด
cost()๋ฉ์๋๊ฐ ํ์ฅ๋ ํ์ ์์. - ๋ง์ฝ ๋ชจ์นด ์ถ๊ฐ๊ฐ ๋ ๋ฒ ์ด์ ๊ฐ๋ฅํ๋ค๋ฉด,
setMocha()๋ฉ์๋๋ฅผ ์ถ๊ฐํ๊ฑฐ๋cost()๋ฉ์๋๋ฅผ ๋ ๋ณต์กํ๊ฒ ์์ฑํด์ผ ํจ.
- ๋๋ธ ๋ชจ์นด๋ ๋ชจ์นด๋ฅผ ๋ ๋ฒ ๋ฃ๋ ์ต์
์ด๋ฏ๋ก, ์ด๋ฅผ ๊ตฌํํ๋ ค๋ฉด
- ์๋ก์ด ์ฒจ๊ฐ๋ฌผ ์ต์
์ ๋์
ํด์ผ ํ ๋๋ง๋ค, ๋ชจ๋ ์๋ฃ ํด๋์ค๋ฅผ ์์ ํด์ผ ํ๋ค.
- ์๋ฅผ ๋ค์ด, ์บ๋ฌ๋ฉ์ด๋ ์๋ฝ ๊ฐ์ ์๋ก์ด ์ฒจ๊ฐ๋ฌผ์ด ์ถ๊ฐ๋ ๋๋ง๋ค, ๊ฐ ์๋ฃ ํด๋์ค์์ ์ด๋ฅผ ๋ค๋ฃจ๋ ๋ก์ง์ ์ถ๊ฐํด์ผ ํ๋ค.
- ์ด๋ก ์ธํด ๊ฐ์ฒด์งํฅ ์์น์ธ ๊ฐ๋ฐฉ-ํ์ ์์น(OCP)์ ์๋ฐํ๊ฒ ๋๋ฉฐ, ์์ ์ ๋ฒ์๊ฐ ์ปค์ง๋ฏ๋ก ๊ด๋ฆฌ๊ฐ ์ด๋ ค์์ง๋ค.
- ๊ธฐ๋ณธ ์๋ฃ ๊ฐ๊ฒฉ์ ๋ฐ๊พธ๊ฑฐ๋ ํ ์ธ ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํ ๋, ๋ชจ๋ ์๋ฃ ํด๋์ค๋ฅผ ์์ ํด์ผ ํ๋ค.
- ์๋ฃ์ ๊ธฐ๋ณธ ๊ฐ๊ฒฉ์ ๋ณ๋์ด ์๊ธฐ๋ฉด ๊ฐ ์๋ฃ ํด๋์ค์์ ๊ฐ๊ฒฉ์ ์์ ํด์ผ ํ๋๋ฐ, ์ค๋ณต ์ฝ๋๊ฐ ๋ง์ด ์๊ธฐ๊ธฐ ๋๋ฌธ์ ํจ์จ์ ์ด์ง ์์.
- ํ ์ธ์ด๋ ํ๋ก๋ชจ์ ๊ฐ๊ฒฉ์ ์ถ๊ฐํ๋ ค๋ฉด, ๊ฐ๊ฐ์ ์๋ฃ ํด๋์ค์์ ์ด๋ฅผ ์ ์ฉํ ๋ฐฉ๋ฒ์ ์ฐพ์์ผ ํ๋ฏ๋ก ์ ์ง๋ณด์๊ฐ ๋ฒ๊ฑฐ๋กญ๋ค.
- ์๋ฃ์ ์๊ฐ ์ฆ๊ฐํ๋ฉด
Beverageํด๋์ค๋ฅผ ํ์ฅํ๋ ์๋ธํด๋์ค๋ค์ด ๋ง์์ง๋ฏ๋ก ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ณ ๋ณต์กํด์ง๋ค.- ์๋ฃ ์ข
๋ฅ๊ฐ ๋ง์์ง๋ฉด
DarkRoast,HouseBlend๊ฐ์ ์๋ธํด๋์ค๊ฐ ๋ง์์ง๊ณ , ์ด๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ด๋ ค์์ง. - ์์ ๊ตฌ์กฐ๊ฐ ๊น์ด์ง๊ฑฐ๋ ๋ง์ ์๋ธํด๋์ค๋ฅผ ์ฒ๋ฆฌํ๋๋ฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์.
- ์๋ฃ ์ข
๋ฅ๊ฐ ๋ง์์ง๋ฉด
- ๊ฐ ์๋ฃ์ ๊ฐ๊ฒฉ ๊ณ์ฐ ๋ก์ง์ด ์ค๋ณต๋๋ค.
- ๊ฐ ์๋ธํด๋์ค์์
cost()๋ฉ์๋๋ฅผ ๊ตฌํํ ๋๋ง๋ค ๋น์ทํ ๋ฐฉ์์ผ๋ก ๊ฐ๊ฒฉ์ ๊ณ์ฐํ๊ฒ ๋๋ฏ๋ก, ์ค๋ณต ์ฝ๋๊ฐ ๋ฐ์. - ์ด๋ก ์ธํด ์๋ก์ด ์๋ฃ๋ ์ฒจ๊ฐ๋ฌผ์ด ์ถ๊ฐ๋ ๋๋ง๋ค ๊ฐ๊ฒฉ ๊ณ์ฐ ๋ก์ง์ ๋ฐ๋ณตํด์ผ ํ๋ค๋ ๋จ์ ์ด ์๊น.
- ๊ฐ ์๋ธํด๋์ค์์
โย OCP ์ดํด๋ณด๊ธฐ
OCP(OPEN-CLOSED PRINCIPLE)๋ ์ ๋ง ์ค์ํ ๋์์ธ ์์น ์ค ํ๋์ด๋ค.
ํด๋์ค๋ ํ์ฅ์๋ ์ด๋ ค ์์ด์ผ ํ์ง๋ง ๋ณ๊ฒฝ์๋ ๋ซํ ์์ด์ผ ํ๋ค.
์ฐ๋ฆฌ์ ๋ชฉํ๋ ๊ธฐ์กด ์ฝ๋๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๊ณ ํ์ฅ์ผ๋ก ์๋ก์ด ํ๋์ ์ถ๊ฐํ๋ ๊ฒ์ด๋ค. ์ด ๋ชฉํ๋ฅผ ๋ฌ์ฑํ์ ๋ ๋ฌด์์ ์ป์ ์ ์์๊น? ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ๋ ๊ธ๋ณํ๋ ์ฃผ๋ณ ํ๊ฒฝ์ ์ ์ ์ํ๋ ์ ์ฐํ๊ณ ํผํผํ ๋์์ธ์ ๋ง๋ค ์ ์๋ค!
โย ๋ฐ์ฝ๋ ์ดํฐ ํจํด ์ดํด๋ณด๊ธฐ
๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก, ์ผ๋จ ํน์ ์๋ฃ์์ ์์ํด์ ์ฒจ๊ฐ๋ฌผ๋ก ๊ทธ ์๋ฃ๋ฅผ ์ฅ์(decorate)ํ๋ค๊ณ ์๊ฐํด ๋ณด์. ์๋ฅผ ๋ค์ด ์ด๋ค ๊ณ ๊ฐ์ด ๋ชจ์นด์ ํํํฌ๋ฆผ์ ์ถ๊ฐํ ๋คํฌ ๋ก์คํธ ์ปคํผ๋ฅผ ์ฃผ๋ฌธํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ฅ์ํ ์ ์๋ค.
- DarkRoast ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์จ๋ค.
- Mocha ๊ฐ์ฒด๋ก ์ฅ์ํ๋ค.
- Whip ๊ฐ์ฒด๋ก ์ฅ์ํ๋ค.
- cost() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค. ์ด๋ ์ฒจ๊ฐ๋ฌผ์ ๊ฐ๊ฒฉ์ ๊ณ์ฐํ๋ ์ผ์ ํด๋น ๊ฐ์ฒด์๊ฒ ์์ํ๋ค.
์ฌ๊ธฐ์ ๊ฐ์ฒด๋ฅผ ์ด๋ป๊ฒ ์ฅ์ํ ์ ์์๊น? ๊ทธ๋ฆฌ๊ณ ์ด ๊ณผ์ ์์ ์ด๋ค ์์ผ๋ก ์์ํ ์ ์์๊น?
โย ์ฃผ๋ฌธ ์์คํ ์ ๋ฐ์ฝ๋ ์ดํฐ ํจํด ์ ์ฉํ๊ธฐ
- DarkRoast๋ Beverage๋ก๋ถํฐ ์์๋ฐ์ผ๋ฏ๋ก ์๋ฃ์ ๊ฐ๊ฒฉ์ ๊ณ์ฐํ๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
- ๊ณ ๊ฐ์ด ๋ชจ์นด๋ฅผ ์ฃผ๋ฌธํ์ผ๋ฏ๋ก Mocha ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ๊ทธ ๊ฐ์ฒด๋ก DarkRoast๋ฅผ ๊ฐ์ผ๋ค.
- Mocha ๊ฐ์ฒด๋ ๋ฐ์ฝ๋ ์ดํฐ์ด๋ค. ๊ฐ์ฒด์ ํ์์ ๊ฐ์ฒด๊ฐ ์ฅ์ํ๊ณ ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐ์ํ๋๋ฐ(์ฌ๊ธฐ์๋ Beverage), ์ฌ๊ธฐ์ ๋ฐ์ํ๋ค๋ ๊ฒ์ โ๊ฐ์ ํ์์ ๊ฐ๋๋ค.โ ๋ผ๋ ๋ป์ผ๋ก ์ดํดํ๋ฉด ๋๋ค.
- ๋ฐ๋ผ์ Mocha์๋ cost() ๋ฉ์๋๊ฐ ์๊ณ , Mocha๊ฐ ๊ฐ์ธ๊ณ ์๋ ๊ฒ๋ Beverage ๊ฐ์ฒด๋ก ๊ฐ์ฃผํ ์ ์๋ค. Mocha๋ Beverage์ ์๋ธํด๋์ค ํ์์ด๊ธฐ ๋๋ฌธ์ด๋ค.
- ๊ณ ๊ฐ์ด ํํํฌ๋ฆผ๋ ์ถ๊ฐํ์ผ๋๊น Whip ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง๋ค์ด Mocha๋ฅผ ๊ฐ์ผ๋ค.
- Whip๋ ๋ฐ์ฝ๋ ์ดํฐ๋ผ์ DarkRoast์ ํ์์ ๋ฐ์ํ๋ฉฐ, cost() ๋ฉ์๋๋ฅผ ๊ฐ์ง๋ค.
- Mocha์ Whip์ ์ธ์ฌ ์๋ DarkRoast๋ ์ฌ์ ํ Beverage ๊ฐ์ฒด์ด๊ธฐ์ cost() ๋ฉ์๋ ํธ์ถ์ ๋น๋กฏํ DarkRoast์ ๊ดํ ์ผ์ด๋ผ๋ฉด ๋ฌด์์ด๋ ํ ์ ์๋ค.
- ๊ฐ๊ฒฉ์ ๊ตฌํ ๋๋ ๊ฐ์ฅ ๋ฐ๊นฅ์ชฝ์ ์๋ ๋ฐ์ฝ๋ ์ดํฐ์ธ Whip์ cost()๋ฅผ ํธ์ถํ๋ฉด ๋๋ค. ๊ทธ๋ฌ๋ฉด Whip์ ๊ทธ ๊ฐ์ฒด๊ฐ ์ฅ์ํ๊ณ ์๋ ๊ฐ์ฒด์๊ฒ ๊ฐ๊ฒฉ ๊ณ์ฐ์ ์์ํ๋ค. ๊ฐ๊ฒฉ์ด ๊ตฌํด์ง๊ณ ๋๋ฉด, ๊ณ์ฐ๋ ๊ฐ๊ฒฉ์ ํํํฌ๋ฆผ์ ๊ฐ๊ฒฉ์ ๋ํ ๋ค์ ๊ทธ ๊ฒฐ๊ณผ๊ฐ์ ๋ฆฌํดํ๋ค.
โ์ ๋ฆฌ
- ๋ฐ์ฝ๋ ์ดํฐ์ ์ํผํด๋์ค๋ ์์ ์ด ์ฅ์ํ๊ณ ์๋ ๊ฐ์ฒด์ ์ํผํด๋์ค์ ๊ฐ๋ค.
- ํ ๊ฐ์ฒด๋ฅผ ์ฌ๋ฌ ๊ฐ์ ๋ฐ์ฝ๋ ์ดํฐ๋ก ๊ฐ์ ์ ์๋ค.
- ๋ฐ์ฝ๋ ์ดํฐ๋ ์์ ์ด ๊ฐ์ธ๊ณ ์๋ ๊ฐ์ฒด์ ๊ฐ์ ์ํผํด๋์ค๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ์ ์๋ ๊ฐ์ฒด(์ธ์ฌ ์๋ ๊ฐ์ฒด)๊ฐ ๋ค์ด๊ฐ ์๋ฆฌ์ ๋ฐ์ฝ๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ฃ์ด๋ ์๊ด์๋ค.
- ๋ฐ์ฝ๋ ์ดํฐ๋ ์์ ์ด ์ฅ์ํ๊ณ ์๋ ๊ฐ์ฒด์๊ฒ ์ด๋ค ํ๋์ ์์ํ๋ ์ผ ๋ง๊ณ ๋ ์ถ๊ฐ ์์ ์ ์ํํ ์ ์๋ค.
- ๊ฐ์ฒด๋ ์ธ์ ๋ ์ง ๊ฐ์ ์ ์์ผ๋ฏ๋ก ์คํ ์ค์ ํ์ํ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง์๋๋ก ์ ์ฉํ ์ ์๋ค.
โย ๋ฐ์ฝ๋ ์ดํฐ ํจํด์ ์ ์
๋ฐ์ฝ๋ ์ดํฐ ํจํด(Decorator Pattern)์ผ๋ก ๊ฐ์ฒด์ ์ถ๊ฐ ์์๋ฅผ ๋์ ์ผ๋ก ๋ํ ์ ์๋ค. ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ธํด๋์ค๋ฅผ ๋ง๋ค ๋๋ณด๋ค ํจ์ฌ ์ ์ฐํ๊ฒ ๊ธฐ๋ฅ์ ํ์ฅํ ์ ์๋ค.
- ๊ฐ ๊ตฌ์ฑ ์์๋ ์ง์ ์ฐ์ผ ์๋ ์๊ณ ๋ฐ์ฝ๋ ์ดํฐ์ ๊ฐ์ธ์ฌ ์ฐ์ผ ์๋ ์๋ค.
- ๊ฐ ๋ฐ์ฝ๋ ์ดํฐ ์์๋ Component ๊ฐ์ฒด๊ฐ ๋ค์ด์๋ค. ์ฆ, ๋ฐ์ฝ๋ ์ดํฐ์๋ ๊ตฌ์ฑ ์์์ ๋ ํผ๋ฐ์ค๋ฅผ ํฌํจํ ์ธ์คํด์ค ๋ณ์๊ฐ ์๋ค.
- Decorator๋ ์์ ์ด ์ฅ์ํ ๊ตฌ์ฑ ์์์ ๊ฐ์ ์ธํฐํ์ด์ค ๋๋ ์ถ์ ํด๋์ค๋ฅผ ๊ตฌํํ๋ค.
- Decorator๋ Component์ ์ํ๋ฅผ ํ์ฅํ ์ ์๋ค.
- ConcreteDecorator์๋ ๋ฐ์ฝ๋ ์ดํฐ๊ฐ ๊ฐ์ธ๊ณ ์๋ Component ๊ฐ์ฒด์ฉ ์ธ์คํด์ค ๋ณ์๊ฐ ์๋ค.
- ๋ฐ์ฝ๋ ์ดํฐ๊ฐ ์๋ก์ด ๋ฉ์๋๋ฅผ ์ถ๊ฐํ ์๋ ์๋ค. ํ์ง๋ง ์ผ๋ฐ์ ์ผ๋ก ์๋ก์ด ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ ๋์ Component์ ์๋ ์๋ ๋ฉ์๋๋ฅผ(ํธ์ถ ์ ์ด๋ ํธ์ถํ ํ์) ๋ณ๋์ ์์ ์ผ๋ก ์ฒ๋ฆฌํด์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ค.
โย Beverage ํด๋์ค ์ฅ์ํ๊ธฐ
HouseBlend,Espresso,DarkRoast,Decaf: ์ปคํผ ์ข ๋ฅ๋ง๋ค ๊ตฌ์ฑ ์์๋ฅผ ๋ํ๋ด๋ ๊ตฌ์ ํด๋์ค๋ฅผ ํ๋์ฉ ๋ง๋ค์๋ค.Milk,Mocha,Soy,Whip: ๊ฐ๊ฐ์ ์ฒจ๊ฐ๋ฌผ์ ๋ํ๋ด๋ ๋ฐ์ฝ๋ ์ดํฐ. cost()์ getDescription()๋ ๊ตฌํํด์ผ ํ๋ค.
์ด ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ๋ณด๋ฉด CondimentDecorator์์ Beverage ํด๋์ค๋ฅผ ํ์ฅํ๊ณ ์๋ค. ๊ทธ๋ฌ๋ฉด ์์ ์๋๊น? ์์์ด๋ค. ๋ฐ์ฝ๋ ์ดํฐ ํจํด์์๋ ์์์ ์ฌ์ฉํด์ ํ์์ ๋ง์ถ๋ ๊ฒ์ด์ง, ์์์ผ๋ก ํ๋์ ๋ฌผ๋ ค๋ฐ๋ ๊ฒ์ด ์๋๋ค. ์๋ ์๋ ๊ตฌ์ฑ ์์๊ฐ ๋ค์ด๊ฐ ์๋ฆฌ์ ์๊ธฐ๊ฐ ๋ค์ด๊ฐ ์ ์์ด์ผ ํ๋๊น ๋ฐ์ฝ๋ ์ดํฐ ๊ฐ์ฒด๋ ์์ ์ด ๊ฐ์ธ๊ณ ์๋ ๊ฐ์ฒด์ ๊ฐ์ ์ธํฐํ์ด์ค๋ฅผ ๊ฐ์ ธ์ผ ํ๋ค.
๊ทธ๋ ๋ค๋ฉด ํ๋์ ์ด๋์ ์ฌ๊น?
์ด๋ค ๊ตฌ์ฑ ์์๋ฅผ ๊ฐ์ง๊ณ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง๋ค ๋ ์๋ก์ด ํ๋์ ์ถ๊ฐํ๋ค. ์๋ก์ด ํ๋์ ์ํผํด๋์ค๋ก๋ถํฐ ํ๋์ ์์๋ฐ๋ ๊ฒ์ด ์๋๋ผ ๊ฐ์ฒด๋ฅผ _๊ตฌ์ฑ_ํด์ ์ป๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ์๋ฃ์ ์ฒจ๊ฐ๋ฌผ์ ๋ค์ํ๊ฒ ์ถ๊ฐํด๋ ์ ์ฐ์ฑ์ ์์ง ์์ ์ ์๋ค.
๊ตฌ์ฑ ์์์ ํ์๋ง ์์ํ๋ฉด ๋๋ ๊ฑฐ๋ผ๋ฉด Beverage ํด๋์ค๋ฅผ ์ ์ธํฐํ์ด์ค๋ก ๋ง๋ค์ง ์๊ณ ์ถ์ ํด๋์ค๋ก ๋ง๋ค์์๊น?
์๋ ๋ฐ์ฝ๋ ์ดํฐ ํจํด์์๋ ํน์ ํ ์ถ์ ๊ตฌ์ฑ ์์๋ฅผ ์ง์ ํ ํ์๊ฐ ์์ง๋ง, ๊ธฐ์กด ์ฝ๋๋ฅผ ๊ณ ์น๋ ์ผ์ ๋ ์ ์์ผ๋ฉด ํผํ๋ ๊ฒ์ด ์ข๋ค. ๊ธฐ์กด ์ฝ๋์์ ์ถ์ ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ณ ์์์ผ๋ฏ๋ก, ์ถ์ ํด๋์ค๋ฅผ ์จ๋ ๋๋ ์ํฉ์ด๋ผ๋ฉด ๊ทธ๋ฅ ์ถ์ ํด๋์ค๋ง ๊ฐ์ง๊ณ ์์ ์ ํ๋ ๊ฒ ๋์ ์๋ ์๋ค.
โย ๋ฐ์ฝ๋ ์ดํฐ ํจํด ์ ์ฉ ์ฐ์ต
โ๋์ ๋ฅผ ์ถ๊ฐํ๊ณ ํํํฌ๋ฆผ์ ์น์ ๋๋ธ ๋ชจ์นด ํ ์ ์ฃผ์ธ์!โ
์ด๋ป๊ฒ ํ๋ฉด ์ข์์ง ๊ทธ๋ ค ๋ณด์.
- ์ ์ผ ๋จผ์ Whip์ cost() ํธ์ถ
- Whip์์ Mocha์ ์๋ cost() ํธ์ถ
- Mocha์์ ๊ทธ ์์ชฝ์ ์๋ ๋ค๋ฅธ Mocha์ cost() ํธ์ถ
- Mocha์์ Soy์ ์๋ cost() ํธ์ถ
- ๋ง์ง๋ง ๋ฐ์ฝ๋ ์ดํฐ์ธ Soy์์ DarkRoast์ cost() ํธ์ถ
- DarkRoast์ cost()์์ 89์ผํธ ๋ฆฌํด. โ cost() ๋ฉ์๋๋ ์คํ์์ ์ ๊ฑฐ๋จ.
- Soy์ cost()์์ 89์ผํธ + 15์ผํธ ๋ฆฌํด. โ cost() ๋ฉ์๋๋ ์คํ์์ ์ ๊ฑฐ๋จ.
- Mocha์ cost()์์ 89์ผํธ + 15์ผํธ + 20์ผํธ ๋ฆฌํด. โ cost() ๋ฉ์๋๋ ์คํ์์ ์ ๊ฑฐ๋จ.
- Mocha์ cost()์์ 89์ผํธ + 15์ผํธ + 20์ผํธ + 20์ผํธ ๋ฆฌํด. โ cost() ๋ฉ์๋๋ ์คํ์์ ์ ๊ฑฐ๋จ.
- Whip์ cost()์์ 89์ผํธ + 15์ผํธ + 20์ผํธ + 20์ผํธ + 10์ผํธ ๋ฆฌํด. โ cost() ๋ฉ์๋๋ ์คํ์์ ์ ๊ฑฐ๋จ.
โย ์ปคํผ ์ฃผ๋ฌธ ์์คํ ์ฝ๋ ๋ง๋ค๊ธฐ
โ ย ๋ฒ ์ด์ค ํด๋์ค ์ค๋น
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1๏ธโฃ ์๋ฃ์ ๊ธฐ๋ณธ ํด๋์ค (์ถ์ ํด๋์ค)
abstract class Beverage {
protected description: string = "์ ์ ์๋ ์๋ฃ";
getDescription(): string {
return this.description;
}
abstract cost(): number;
}
// 2๏ธโฃ ๋ฐ์ฝ๋ ์ดํฐ ๊ธฐ๋ณธ ํด๋์ค (Beverage๋ฅผ ํ์ฅํ๋๋ฐ, ์๋ฃ๋ฅผ ๊ฐ์ ์ ์๋๋ก ๋ง๋ฆ)
abstract class CondimentDecorator extends Beverage {
abstract getDescription(): string;
}
โ ย ์๋ฃ ์ฝ๋ ๊ตฌํ
- ์๋ฃ๋ฅผ ์ค๋ช ํ๋ ๋ฌธ์์ด์ ์ค์ ํ๊ณ cost() ๋ฉ์๋๋ฅผ ๊ผญ! ๊ตฌํํด์ผ ํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 3๏ธโฃ ์ค์ ์๋ฃ ์๋ธํด๋์ค (๋คํฌ ๋ก์คํธ, ํ์ฐ์ค ๋ธ๋ ๋)
class Espresso extends Beverage {
constructor() {
super();
this.description = "์์คํ๋ ์";
}
cost(): number {
return 1.99;
}
}
class HouseBlend extends Beverage {
constructor() {
super();
this.description = "ํ์ฐ์ค ๋ธ๋ ๋ ์ปคํผ";
}
cost(): number {
return 0.89;
}
}
โ ย ์ฒจ๊ฐ๋ฌผ ์ฝ๋ ๊ตฌํํ๊ธฐ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 4๏ธโฃ ๊ตฌ์ฒด์ ์ธ ์ถ๊ฐ ๊ธฐ๋ฅ (ํํํฌ๋ฆผ, ์ฐ์ , ์ท ์ถ๊ฐ ๋ฑ)
class Mocha extends CondimentDecorator {
constructor(private beverage: Beverage) {
super();
}
getDescription(): string {
return this.beverage.getDescription() + ", ๋ชจ์นด";
}
cost(): number {
return this.beverage.cost() + 0.20;
}
}
โ ย ์ปคํผ ์ฃผ๋ฌธ ์์คํ ์ฝ๋ ํ ์คํธ
1
2
3
4
5
6
7
8
9
10
// 5๏ธโฃ ์ฌ์ฉ ์์
let myCoffee: Beverage = new Espresso(); // ์์คํ๋ ์ ์ฃผ๋ฌธ
console.log(myCoffee.getDescription() + `: $${myCoffee.cost()}`);
// "์์คํ๋ ์: $1.99"
myCoffee = new Mocha(myCoffee); // Mocha๋ก ๊ฐ์ธ๊ธฐ
myCoffee = new Mocha(myCoffee); // Mocha ์ท ์ถ๊ฐ
myCoffee = new Whip(myCoffee); // Whip์ผ๋ก ๊ฐ์ธ๊ธฐ
console.log(myCoffee.getDescription() + `: $${myCoffee.cost()}`);
// "์์คํ๋ ์, ๋ชจ์นด, ๋ชจ์นด, ํํํฌ๋ฆผ: $4.29"





