Skip to content

Commit 1d9fdca

Browse files
author
changwan
committed
7-2 우창완
1 parent 582b55c commit 1d9fdca

File tree

1 file changed

+367
-0
lines changed

1 file changed

+367
-0
lines changed

챕터_7/우창완.md

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
# 7. 자바스크립트 디자인패턴 (1/3)
2+
3+
4+
5+
### 생성패턴
6+
7+
* 생성자 패턴
8+
* 모듈 패턴
9+
* 노출 모듈 패턴
10+
* 싱글톤 패턴
11+
* 프로토타입 패턴
12+
* 팩토리 패턴
13+
14+
15+
16+
### 7.2 생성자 패턴
17+
18+
19+
20+
#### 7.2.1 객체 생성
21+
22+
```js
23+
// <= es5
24+
25+
const newObject = {}
26+
27+
Object.defineProperty(newObject, "name", {
28+
value: "Foo",
29+
writable: true,
30+
enumerable: true,
31+
configurable: true
32+
})
33+
34+
//이렇게도 할당 가능
35+
newObject.name = "Bar"
36+
console.log(newObject)
37+
```
38+
39+
40+
41+
#### 7.2.2 생성자의 기본 특징
42+
43+
es6에서 도입된 class를 통해 객체를 생성하고 초기화할 수 있다.
44+
45+
```js
46+
class Person {
47+
constructor(name) {
48+
this.name = name
49+
}
50+
}
51+
52+
const bun = new Person("FooBar")
53+
console.log(bun)
54+
```
55+
56+
57+
58+
### 7.3 모듈 패턴
59+
60+
모듈 패턴을 잘 알지 못하고 처음보았지만, es module을 native하게 지원하고 사용할 수 있는 환경에서 유용성이 큰가? 에 대해아직 물음표인 것 같다.
61+
62+
es module은 그 자체로 모듈로서 동작하는데, 왜 모듈 래퍼를 하나 더 씌우는 건지 궁금하다.
63+
64+
65+
66+
모듈 그 자체로의 장점은 단일 인스턴스를 보장한다는 점인 것 같다. 객체를 만들려면 singleton으로 몸 비틀기를 해야하는 Java에 비해 단일 인스턴스가 필요한 상황이면 모듈을 이용하는 것으로 충분해 보인다.
67+
68+
69+
70+
71+
72+
### 7.3.4 WeakMap을 사용하는 최신 모듈 패턴
73+
74+
WeakMap을 통한 접근제한 필요할 때가 있을 것 같지만, class의 instance로 관리하는 것과 유사해보인다.
75+
76+
1. 먼저, 모듈 변수를 이용한 패턴을 살펴보면, 두 가지 문제점을 볼 수 있다. (WeakMap ❌)
77+
78+
* 모듈 내의 변수를 공유하게 된다. 즉, 인스턴스 간의 독립적인 상태를 갖지 못한다.
79+
* 동일 모듈에서 모듈 변수들에게 자유롭게 접근이 가능하다.
80+
81+
```js
82+
let counter = 0;
83+
let action;
84+
85+
class Countdown {
86+
constructor(initialCounter, initialAction) {
87+
counter = initialCounter; // 모듈 스코프의 counter 변경
88+
action = initialAction; // 모듈 스코프의 action 변경
89+
}
90+
91+
dec() {
92+
if (counter < 1) return;
93+
94+
counter--; // 모듈 스코프의 counter 감소
95+
96+
if (counter === 0) {
97+
action(); // 모듈 스코프의 action 호출
98+
}
99+
}
100+
}
101+
```
102+
103+
104+
105+
2. 클래스 내의 멤버 변수로 선언할 경우.
106+
107+
* 자바스크립트는 비공개 필드를 선언할 수 없었다.
108+
109+
```js
110+
class Countdown {
111+
counter;
112+
action;
113+
114+
constructor(counter, action) {
115+
this.counter = counter;
116+
this.action = action;
117+
}
118+
119+
dec() {
120+
if (this.counter < 1) return;
121+
122+
this.counter--; // 프라이빗 필드 값 감소
123+
124+
if (this.counter === 0) {
125+
this.action(); // 프라이빗 필드로 접근
126+
}
127+
}
128+
}
129+
const c = new Countdown(2, () => console.log('DONE'));
130+
console.log(c.counter); //1
131+
c.counter = -1;
132+
console.log(c.counter); // -1
133+
```
134+
135+
136+
137+
es2019에 추가된 private class member(`#`)가 도입되었다. 사실 private class member는 트랜스파일링 시, weakMap으로 트랜스파일링 된다.
138+
139+
```js
140+
class A {
141+
#privateFieldA = 1;
142+
}
143+
144+
// 트랜스파일링
145+
var _privateFieldA = /*#__PURE__*/new WeakMap();
146+
147+
class A {
148+
constructor() {
149+
_privateFieldA.set(this, {
150+
writable: true,
151+
value: 1
152+
});
153+
}
154+
}
155+
156+
```
157+
158+
159+
160+
161+
162+
#### 7.4 노출 모듈 패턴
163+
164+
export로 비공개/공개 요소를 지정하는 것보다 포인터 객체를 만드는 것이 어떤 이점이 있는지 잘 모르겠다..
165+
166+
167+
168+
#### 7.5 싱글톤 패턴
169+
170+
Java의 싱글톤 패턴을 자바스크립트에서 사용하면 문제가 있는지 의심해봐야한다.
171+
172+
173+
174+
#### 7.7 팩토리 패턴
175+
176+
싱글 팩토리 패턴
177+
178+
```js
179+
function createVechicle(data) {
180+
switch(data.type) {
181+
case "car":
182+
return new Car({...});
183+
case "truck":
184+
return new Truck({...});
185+
default:
186+
throw new Error("일체하는 type이 없습니다.")
187+
}
188+
}
189+
```
190+
191+
192+
193+
위의 싱글 팩토리 패턴은 srp, ocp 위반이다. 그래서 나온 것이 추상 팩토리 메서드 패턴이다.
194+
195+
잘 동의가 안 되는게, 추상 팩토리를 만든다고 하더라도 진입점에서는 결국 분기처리 해주어야 하는 것이 아닌가? 결국 if,else 분기문의 위치만 달라진다고 느껴진다.
196+
197+
그러면, 인터페이스 복잡도, 추상도만 올라가는 것 같은데.. 어떤 이점이 있는지 잘 모르겠다. 유용함을 깨달으면 수정해놓겠지.
198+
199+
200+
201+
### 7.8 구조 패턴
202+
203+
구조 패턴은 클래스와 객체를 체계적으로 구성하는 방법에 관한 것
204+
205+
206+
207+
### 7.10 퍼사드 패턴
208+
209+
퍼사드란, 내부의 복잡한 로직을 외부에 편리한 높은 수준의 인터페이스를 제공하는 패턴.
210+
211+
이름을 적절히 추상화해서 외부에 노출하는 것이 중요하는 것이 중요하다.
212+
213+
214+
215+
### 7.10 믹스인 패턴
216+
217+
믹스인은 서브클래스가 쉽게 상속받아 기능을 재사용할 수 있도록 하는 클래스
218+
219+
220+
221+
### 7.11 서브 클래싱 패턴
222+
223+
부모 클래스 생성자를 호출(super())하는 것
224+
225+
```js
226+
class SuperHero extends Person {
227+
constructor(firstName, lastName, powers) {
228+
super(firstName, lastName)
229+
this.powers = powers;
230+
}
231+
}
232+
```
233+
234+
235+
236+
### 7.12 믹스인
237+
238+
자바스크립트에서 다중 상속을 지원하지 않기 때문에, mixin 패턴을 통해 상속을 흉내낼 수 있다.
239+
240+
```js
241+
function LoggingMixin<T extends { new(...args: any[]): {} }>(Base: T) {
242+
return class extends Base {
243+
log(message: string) {
244+
console.log(`[LOG]: ${message}`);
245+
}
246+
};
247+
}
248+
class Product {
249+
name: string;
250+
price: number;
251+
constructor(name: string, price: number) {
252+
this.name = name;
253+
this.price = price;
254+
}
255+
}
256+
// Mixins을 통해 기능 추가
257+
const LoggingProduct = LoggingMixin(Product)
258+
const product1 = new LoggingProduct("Laptop", 1500)
259+
product1.log("Hello")
260+
```
261+
262+
263+
264+
React의 HOC와도 비슷해보인다.
265+
266+
```js
267+
import React from "react";
268+
269+
function withLogging(WrappedComponent) {
270+
return class extends React.Component {
271+
log(message) {
272+
console.log(`[LOG]: ${message}`);
273+
}
274+
275+
render() {
276+
// HOC가 props를 WrappedComponent에 전달
277+
return <WrappedComponent {...this.props} log={this.log} />;
278+
}
279+
};
280+
}
281+
282+
// 기본 컴포넌트
283+
function Product({ name, price, log }) {
284+
return (
285+
<div>
286+
<h1>{name}</h1>
287+
<p>Price: {price}</p>
288+
<button onClick={() => log("Product clicked!")}>Log</button>
289+
</div>
290+
);
291+
}
292+
293+
// HOC를 통해 기능 추가
294+
const LoggingProduct = withLogging(Product);
295+
296+
```
297+
298+
299+
300+
HOC는 이러한 간단한 예시에서는 적절한 추상화를 제공하고, 문제를 우아하게 해결하는 것처럼 보인다. 하지만, 경험적으로 HOC가 많아질수록, 복잡성과 유지보수를 어렵게 만든다.
301+
302+
303+
304+
### 7.13 데코레이터 패턴
305+
306+
객체에 동적으로 기능을 추가, 확장할 수 있는 디자인 패턴
307+
308+
상속이 컴파일 타임에 확정되는 데 비해, 데코레이터 패턴은 동적으로 추가할 수 있다.
309+
310+
311+
312+
```js
313+
class Coffee {
314+
getCost() {
315+
return 5; // 기본 커피 가격
316+
}
317+
318+
getDescription() {
319+
return "Basic Coffee";
320+
}
321+
}
322+
323+
324+
class MilkDecorator {
325+
constructor(coffee) {
326+
this.coffee = coffee;
327+
}
328+
329+
getCost() {
330+
return this.coffee.getCost() + 2; // 우유 추가 가격
331+
}
332+
333+
getDescription() {
334+
return this.coffee.getDescription() + ", Milk";
335+
}
336+
}
337+
338+
339+
//개발자의 인자부하를 올리지는 않을까? 어떤 클래스의 데코레이터인지 파악하기 어려울 것 같다는 생각도 든다
340+
const coffee = new Coffee();
341+
const milkCoffee = new MilkDecorator(coffee);
342+
```
343+
344+
345+
346+
347+
348+
349+
350+
### 7.14 의사 클래스 데코레이터
351+
352+
`Interface.ensureImplements`까지 하는 것은 투머치.. 타입스크립트를 사용하자
353+
354+
355+
356+
357+
358+
359+
360+
361+
362+
363+
364+
365+
366+
367+

0 commit comments

Comments
 (0)