Skip to content

Commit a61ed94

Browse files
WooWanchangwan
andauthored
7-2 우창완 (#54)
Co-authored-by: changwan <changwan@toss.im>
1 parent cb59424 commit a61ed94

File tree

1 file changed

+152
-80
lines changed

1 file changed

+152
-80
lines changed

챕터_7/우창완.md

Lines changed: 152 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,119 @@
11
# 7. 자바스크립트 디자인패턴 (1/3)
22

3-
4-
53
### 생성패턴
64

7-
* 생성자 패턴
8-
* 모듈 패턴
9-
* 노출 모듈 패턴
10-
* 싱글톤 패턴
11-
* 프로토타입 패턴
12-
* 팩토리 패턴
13-
14-
5+
- 생성자 패턴
6+
- 모듈 패턴
7+
- 노출 모듈 패턴
8+
- 싱글톤 패턴
9+
- 프로토타입 패턴
10+
- 팩토리 패턴
1511

1612
### 7.2 생성자 패턴
1713

18-
19-
2014
#### 7.2.1 객체 생성
2115

2216
```js
23-
// <= es5
17+
// <= es5
2418

25-
const newObject = {}
19+
const newObject = {};
2620

2721
Object.defineProperty(newObject, "name", {
28-
value: "Foo",
29-
writable: true,
30-
enumerable: true,
31-
configurable: true
32-
})
22+
value: "Foo",
23+
writable: true,
24+
enumerable: true,
25+
configurable: true,
26+
});
3327

3428
//이렇게도 할당 가능
35-
newObject.name = "Bar"
36-
console.log(newObject)
29+
newObject.name = "Bar";
30+
console.log(newObject);
3731
```
3832

39-
40-
4133
#### 7.2.2 생성자의 기본 특징
4234

4335
es6에서 도입된 class를 통해 객체를 생성하고 초기화할 수 있다.
4436

4537
```js
4638
class Person {
47-
constructor(name) {
48-
this.name = name
49-
}
39+
constructor(name) {
40+
this.name = name;
41+
}
5042
}
5143

52-
const bun = new Person("FooBar")
53-
console.log(bun)
44+
const bun = new Person("FooBar");
45+
console.log(bun);
5446
```
5547

56-
57-
5848
### 7.3 모듈 패턴
5949

6050
모듈 패턴을 잘 알지 못하고 처음보았지만, es module을 native하게 지원하고 사용할 수 있는 환경에서 유용성이 큰가? 에 대해아직 물음표인 것 같다.
6151

6252
es module은 그 자체로 모듈로서 동작하는데, 왜 모듈 래퍼를 하나 더 씌우는 건지 궁금하다.
6353

64-
65-
6654
모듈 그 자체로의 장점은 단일 인스턴스를 보장한다는 점인 것 같다. 객체를 만들려면 singleton으로 몸 비틀기를 해야하는 Java에 비해 단일 인스턴스가 필요한 상황이면 모듈을 이용하는 것으로 충분해 보인다.
6755

68-
69-
70-
71-
7256
### 7.3.4 WeakMap을 사용하는 최신 모듈 패턴
7357

7458
WeakMap을 통한 접근제한 필요할 때가 있을 것 같지만, class의 instance로 관리하는 것과 유사해보인다.
7559

7660
1. 먼저, 모듈 변수를 이용한 패턴을 살펴보면, 두 가지 문제점을 볼 수 있다. (WeakMap ❌)
7761

78-
* 모듈 내의 변수를 공유하게 된다. 즉, 인스턴스 간의 독립적인 상태를 갖지 못한다.
79-
* 동일 모듈에서 모듈 변수들에게 자유롭게 접근이 가능하다.
62+
- 모듈 내의 변수를 공유하게 된다. 즉, 인스턴스 간의 독립적인 상태를 갖지 못한다.
63+
- 동일 모듈에서 모듈 변수들에게 자유롭게 접근이 가능하다.
8064

8165
```js
8266
let counter = 0;
8367
let action;
8468

8569
class Countdown {
86-
constructor(initialCounter, initialAction) {
87-
counter = initialCounter; // 모듈 스코프의 counter 변경
88-
action = initialAction; // 모듈 스코프의 action 변경
89-
}
70+
constructor(initialCounter, initialAction) {
71+
counter = initialCounter; // 모듈 스코프의 counter 변경
72+
action = initialAction; // 모듈 스코프의 action 변경
73+
}
9074

91-
dec() {
92-
if (counter < 1) return;
75+
dec() {
76+
if (counter < 1) return;
9377

94-
counter--; // 모듈 스코프의 counter 감소
78+
counter--; // 모듈 스코프의 counter 감소
9579

96-
if (counter === 0) {
97-
action(); // 모듈 스코프의 action 호출
98-
}
80+
if (counter === 0) {
81+
action(); // 모듈 스코프의 action 호출
9982
}
83+
}
10084
}
10185
```
10286

103-
104-
10587
2. 클래스 내의 멤버 변수로 선언할 경우.
10688

107-
* 자바스크립트는 비공개 필드를 선언할 수 없었다.
89+
- 자바스크립트는 비공개 필드를 선언할 수 없었다.
10890

10991
```js
11092
class Countdown {
111-
counter;
112-
action;
93+
counter;
94+
action;
11395

114-
constructor(counter, action) {
115-
this.counter = counter;
116-
this.action = action;
117-
}
96+
constructor(counter, action) {
97+
this.counter = counter;
98+
this.action = action;
99+
}
118100

119-
dec() {
120-
if (this.counter < 1) return;
101+
dec() {
102+
if (this.counter < 1) return;
121103

122-
this.counter--; // 프라이빗 필드 값 감소
104+
this.counter--; // 프라이빗 필드 값 감소
123105

124-
if (this.counter === 0) {
125-
this.action(); // 프라이빗 필드로 접근
126-
}
106+
if (this.counter === 0) {
107+
this.action(); // 프라이빗 필드로 접근
127108
}
109+
}
128110
}
129-
const c = new Countdown(2, () => console.log('DONE'));
130-
console.log(c.counter); //2
111+
const c = new Countdown(2, () => console.log("DONE"));
112+
console.log(c.counter); //1
131113
c.counter = -1;
132114
console.log(c.counter); // -1
133115
```
134116

135-
136-
137117
es2019에 추가된 private class member(`#`)가 도입되었다. 사실 private class member는 트랜스파일링 시, weakMap으로 트랜스파일링 된다.
138118

139119
```js
@@ -142,35 +122,26 @@ class A {
142122
}
143123

144124
// 트랜스파일링
145-
var _privateFieldA = /*#__PURE__*/new WeakMap();
125+
var _privateFieldA = /*#__PURE__*/ new WeakMap();
146126

147127
class A {
148128
constructor() {
149129
_privateFieldA.set(this, {
150130
writable: true,
151-
value: 1
131+
value: 1,
152132
});
153133
}
154134
}
155-
156135
```
157136

158-
159-
160-
161-
162137
#### 7.4 노출 모듈 패턴
163138

164139
export로 비공개/공개 요소를 지정하는 것보다 포인터 객체를 만드는 것이 어떤 이점이 있는지 잘 모르겠다..
165140

166-
167-
168141
#### 7.5 싱글톤 패턴
169142

170143
Java의 싱글톤 패턴을 자바스크립트에서 사용하면 문제가 있는지 의심해봐야한다.
171144

172-
173-
174145
#### 7.7 팩토리 패턴
175146

176147
싱글 팩토리 패턴
@@ -188,35 +159,136 @@ function createVechicle(data) {
188159
}
189160
```
190161

191-
192-
193162
위의 싱글 팩토리 패턴은 srp, ocp 위반이다. 그래서 나온 것이 추상 팩토리 메서드 패턴이다.
194163

195164
잘 동의가 안 되는게, 추상 팩토리를 만든다고 하더라도 진입점에서는 결국 분기처리 해주어야 하는 것이 아닌가? 결국 if,else 분기문의 위치만 달라진다고 느껴진다.
196165

197166
그러면, 인터페이스 복잡도, 추상도만 올라가는 것 같은데.. 어떤 이점이 있는지 잘 모르겠다. 유용함을 깨달으면 수정해놓겠지.
198167

168+
### 7.8 구조 패턴
169+
170+
구조 패턴은 클래스와 객체를 체계적으로 구성하는 방법에 관한 것
199171

172+
### 7.10 퍼사드 패턴
200173

174+
퍼사드란, 내부의 복잡한 로직을 외부에 편리한 높은 수준의 인터페이스를 제공하는 패턴.
201175

176+
이름을 적절히 추상화해서 외부에 노출하는 것이 중요하는 것이 중요하다.
202177

178+
### 7.10 믹스인 패턴
203179

180+
믹스인은 서브클래스가 쉽게 상속받아 기능을 재사용할 수 있도록 하는 클래스
204181

182+
### 7.11 서브 클래싱 패턴
183+
184+
부모 클래스 생성자를 호출(super())하는 것
185+
186+
```js
187+
class SuperHero extends Person {
188+
constructor(firstName, lastName, powers) {
189+
super(firstName, lastName);
190+
this.powers = powers;
191+
}
192+
}
193+
```
194+
195+
### 7.12 믹스인
196+
197+
자바스크립트에서 다중 상속을 지원하지 않기 때문에, mixin 패턴을 통해 상속을 흉내낼 수 있다.
198+
199+
```js
200+
function LoggingMixin<T extends { new(...args: any[]): {} }>(Base: T) {
201+
return class extends Base {
202+
log(message: string) {
203+
console.log(`[LOG]: ${message}`);
204+
}
205+
};
206+
}
207+
class Product {
208+
name: string;
209+
price: number;
210+
constructor(name: string, price: number) {
211+
this.name = name;
212+
this.price = price;
213+
}
214+
}
215+
// Mixins을 통해 기능 추가
216+
const LoggingProduct = LoggingMixin(Product)
217+
const product1 = new LoggingProduct("Laptop", 1500)
218+
product1.log("Hello")
219+
```
205220

221+
React의 HOC와도 비슷해보인다.
206222

223+
```js
224+
import React from "react";
207225

226+
function withLogging(WrappedComponent) {
227+
return class extends React.Component {
228+
log(message) {
229+
console.log(`[LOG]: ${message}`);
230+
}
208231

232+
render() {
233+
// HOC가 props를 WrappedComponent에 전달
234+
return <WrappedComponent {...this.props} log={this.log} />;
235+
}
236+
};
237+
}
209238

239+
// 기본 컴포넌트
240+
function Product({ name, price, log }) {
241+
return (
242+
<div>
243+
<h1>{name}</h1>
244+
<p>Price: {price}</p>
245+
<button onClick={() => log("Product clicked!")}>Log</button>
246+
</div>
247+
);
248+
}
210249

250+
// HOC를 통해 기능 추가
251+
const LoggingProduct = withLogging(Product);
252+
```
211253

254+
HOC는 이러한 간단한 예시에서는 적절한 추상화를 제공하고, 문제를 우아하게 해결하는 것처럼 보인다. 하지만, 경험적으로 HOC가 많아질수록, 복잡성과 유지보수를 어렵게 만든다.
212255

256+
### 7.13 데코레이터 패턴
213257

258+
객체에 동적으로 기능을 추가, 확장할 수 있는 디자인 패턴
214259

260+
상속이 컴파일 타임에 확정되는 데 비해, 데코레이터 패턴은 동적으로 추가할 수 있다.
215261

262+
```js
263+
class Coffee {
264+
getCost() {
265+
return 5; // 기본 커피 가격
266+
}
216267

268+
getDescription() {
269+
return "Basic Coffee";
270+
}
271+
}
217272

273+
class MilkDecorator {
274+
constructor(coffee) {
275+
this.coffee = coffee;
276+
}
218277

278+
getCost() {
279+
return this.coffee.getCost() + 2; // 우유 추가 가격
280+
}
219281

282+
getDescription() {
283+
return this.coffee.getDescription() + ", Milk";
284+
}
285+
}
220286

287+
//개발자의 인자부하를 올리지는 않을까? 어떤 클래스의 데코레이터인지 파악하기 어려울 것 같다는 생각도 든다
288+
const coffee = new Coffee();
289+
const milkCoffee = new MilkDecorator(coffee);
290+
```
221291

292+
### 7.14 의사 클래스 데코레이터
222293

294+
`Interface.ensureImplements`까지 하는 것은 투머치.. 타입스크립트를 사용하자

0 commit comments

Comments
 (0)