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
2721Object .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
4335es6에서 도입된 class를 통해 객체를 생성하고 초기화할 수 있다.
4436
4537``` js
4638class 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
6252es module은 그 자체로 모듈로서 동작하는데, 왜 모듈 래퍼를 하나 더 씌우는 건지 궁금하다.
6353
64-
65-
6654모듈 그 자체로의 장점은 단일 인스턴스를 보장한다는 점인 것 같다. 객체를 만들려면 singleton으로 몸 비틀기를 해야하는 Java에 비해 단일 인스턴스가 필요한 상황이면 모듈을 이용하는 것으로 충분해 보인다.
6755
68-
69-
70-
71-
7256### 7.3.4 WeakMap을 사용하는 최신 모듈 패턴
7357
7458WeakMap을 통한 접근제한 필요할 때가 있을 것 같지만, class의 instance로 관리하는 것과 유사해보인다.
7559
76601 . 먼저, 모듈 변수를 이용한 패턴을 살펴보면, 두 가지 문제점을 볼 수 있다. (WeakMap ❌)
7761
78- * 모듈 내의 변수를 공유하게 된다. 즉, 인스턴스 간의 독립적인 상태를 갖지 못한다.
79- * 동일 모듈에서 모듈 변수들에게 자유롭게 접근이 가능하다.
62+ - 모듈 내의 변수를 공유하게 된다. 즉, 인스턴스 간의 독립적인 상태를 갖지 못한다.
63+ - 동일 모듈에서 모듈 변수들에게 자유롭게 접근이 가능하다.
8064
8165``` js
8266let counter = 0 ;
8367let action;
8468
8569class 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-
105872 . 클래스 내의 멤버 변수로 선언할 경우.
10688
107- * 자바스크립트는 비공개 필드를 선언할 수 없었다.
89+ - 자바스크립트는 비공개 필드를 선언할 수 없었다.
10890
10991``` js
11092class 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
131113c .counter = - 1 ;
132114console .log (c .counter ); // -1
133115```
134116
135-
136-
137117es2019에 추가된 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
147127class 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
164139export로 비공개/공개 요소를 지정하는 것보다 포인터 객체를 만드는 것이 어떤 이점이 있는지 잘 모르겠다..
165140
166-
167-
168141#### 7.5 싱글톤 패턴
169142
170143Java의 싱글톤 패턴을 자바스크립트에서 사용하면 문제가 있는지 의심해봐야한다.
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