From ee37613afde7047f7f04393c1aa4f1aa2445197f Mon Sep 17 00:00:00 2001 From: haeguri Date: Wed, 11 Aug 2021 10:25:16 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=8D=B0=EC=BD=94=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=ED=8C=A8=ED=84=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/design-pattern/catalogs/decorator.md | 129 +++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 study/design-pattern/catalogs/decorator.md diff --git a/study/design-pattern/catalogs/decorator.md b/study/design-pattern/catalogs/decorator.md new file mode 100644 index 0000000..778d683 --- /dev/null +++ b/study/design-pattern/catalogs/decorator.md @@ -0,0 +1,129 @@ +# Decorator + +a.k.a. **Wrapper** + +## **πŸ’‘Β μ±…μ—μ„œ μ„€λͺ…ν•˜λŠ” μ˜λ„** + +"객체에 λ™μ μœΌλ‘œ μƒˆλ‘œμš΄ μ±…μž„μ„ μΆ”κ°€ν•  수 있게 ν•©λ‹ˆλ‹€. κΈ°λŠ₯을 μΆ”κ°€ν•˜λ €λ©΄, μ„œλΈŒν΄λž˜μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 것보닀 μœ΅ν†΅μ„± μžˆλŠ” 방법을 μ œκ³΅ν•©λ‹ˆλ‹€." + +## **🧐 우리 상황에 맞게 ν’€μ–΄ μ“΄ 동기** + +```tsx +class OrdersStore { + public async searchUsingService() { + // API 호좜 + } +} + +class PartnersStore { + public async searchUsingService() { + // API 호좜 + } +} +``` + +`OrdersStore`, `PartnersStore` μ—μ„œ μ˜€λ”, ν˜Ήμ€ 지점 λͺ©λ‘μ„ μ‘°νšŒν•  λ•Œ Spinnerλ₯Ό μ—΄κ³  λ‹«μ•„μ•Ό ν•˜λŠ” μš”κ΅¬μ‚¬ν•­μ΄ λ“€μ–΄μ™”μŠ΅λ‹ˆλ‹€. 두 개의 ν΄λž˜μŠ€μ— Spinnerλ₯Ό μ—΄κ³  λ‹«λŠ” λ‘œμ§μ„ ν•˜λ“œμ½”λ”©ν•˜μ—¬ μž‘μ„±ν•  μˆ˜λ„ μžˆμ§€λ§Œ, μ½”λ“œμ˜ μž¬μ‚¬μš©μ„±μ΄ λ–¨μ–΄μ§‘λ‹ˆλ‹€. + +κ·Έλž˜μ„œ 상속을 μ΄μš©ν•˜κΈ°λ‘œ ν•˜κ³ , `Spinner`λΌλŠ” 클래슀λ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€. `Spinner`λŠ” λ‹€μŒκ³Ό 같이 μž‘μ„±ν•©λ‹ˆλ‹€. + +```tsx +class Spinner { + public async search () { + this.openSpinner(); + + await this.searchUsingService(); + + this.closeSpinner(); + } +} +``` + +λ‹€μŒμœΌλ‘œ `OrdersStore` κ°€ `Spinner` λ₯Ό 상속받도둝 ν•©λ‹ˆλ‹€. 클래슀의 이름은 `OrdersStoreWithSpinner` 으둜 ν•©λ‹ˆλ‹€. + +```tsx +class OrdersStoreWithSpinner extends Spinner { + public async searchUsingService() { + // API 호좜 + } +} + +// μ‚¬μš©ν•  λ•Œ +await ordersStoreWithSpinner.search(); +``` + + `PartnersStore` ν΄λž˜μŠ€λ„ Spinnerκ°€ ν•„μš”ν•˜λ‹ˆ `PartnersStoreSpinner` λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•©λ‹ˆλ‹€. 이외에도 Spinnerκ°€ ν•„μš”ν•œ ν΄λž˜μŠ€λ“€μ€ λͺ¨λ‘ `Spinner` 클래슀λ₯Ό μƒμ†ν•˜μ—¬ μ„œλΈŒ ν΄λž˜μŠ€λ“€μ„ 찍어내야 ν•©λ‹ˆλ‹€. + +## **πŸ› Β ν™œμš©μ„±: 이럴 λ•Œ μ”λ‹ˆλ‹€** + +- 동적이고, 투λͺ…ν•˜κ²Œ(transparent), λ‹€μ‹œ λ§ν•΄μ„œ λ‹€λ₯Έ 객체에 영ν–₯을 μ£Όμ§€ μ•Šκ³ , 개개의 객체에 μƒˆλ‘œμš΄ μ±…μž„μ„ μΆ”κ°€ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•©λ‹ˆλ‹€. +- 제거될 수 μžˆλŠ” μ±…μž„μ— λŒ€ν•΄ μ‚¬μš©ν•©λ‹ˆλ‹€. +- μ‹€μ œ μƒμ†μœΌλ‘œ μ„œλΈŒ 클래슀λ₯Ό 계속 λ§Œλ“œλŠ” 방법이 μ‹€μ§ˆμ μ΄μ§€ λͺ»ν•  λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€. λ„ˆλ¬΄ λ§Žμ€ 수의 λ…λ¦½λœ ν™•μž₯이 κ°€λŠ₯ν•  λ•Œ λͺ¨λ“  쑰합을 μ§€μ›ν•˜κΈ° μœ„ν•΄ 이λ₯Ό μƒμ†μœΌλ‘œ ν•΄κ²°ν•˜λ©΄ 클래슀 μˆ˜κ°€ 폭발적으둜 λ§Žμ•„μ§€κ²Œ λ©λ‹ˆλ‹€. μ•„λ‹ˆλ©΄, 클래슀 μ •μ˜κ°€ μˆ¨κ²¨μ§€λ“ κ°€, κ·Έλ ‡μ§€ μ•Šλ”λΌλ„ μ„œλΈŒν΄λž˜μ‹±ν•  수 μ—†κ²Œ λ©λ‹ˆλ‹€. + +## **🎁 결과** + +이점 + +- λ‹¨μˆœν•œ 상속보닀 μ„€κ³„μ˜ μœ΅ν†΅μ„±μ„ 더 많이 μ¦λŒ€μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€. +- 클래슀 κ³„ν†΅μ˜ 상뢀츑 ν΄λž˜μŠ€μ— λ§Žμ€ κΈ°λŠ₯이 λˆ„μ λ˜λŠ” 상황을 ν”Όν•  수 μžˆμŠ΅λ‹ˆλ‹€. +- μž₯μ‹μžμ™€ ν•΄λ‹Ή κ·Έ μž₯μ‹μžμ˜ κ΅¬μ„±μš”μ†Œκ°€ λ™μΌν•œ 것은 μ•„λ‹™λ‹ˆλ‹€. + +λΆ€λ‹΄ + +- μž₯μ‹μžλ₯Ό μ‚¬μš©ν•¨μœΌλ‘œμ¨ μž‘μ€ 규λͺ¨μ˜ 객체듀이 많이 μƒκΉλ‹ˆλ‹€. + +## **πŸ—ΊΒ κ΅¬ν˜„ 방법** + +### κ΅¬ν˜„ κ³Όμ • + +`Decorator` 역할을 ν•˜λŠ” ν΄λž˜μŠ€λŠ” 콘크리트 클래슀(`OrdersStore`) 와 λ™μΌν•œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ°€μ Έμ•Ό ν•©λ‹ˆλ‹€. λ”°λΌμ„œ `Decorator` 와 `OrdersStore` κ°€ λ™μΌν•œ λΆ€λͺ¨λ₯Ό μƒμ†λ°›κ²Œ ν•©λ‹ˆλ‹€. + +```tsx +abstract class ListStore { + public async search() { + await this.searchUsingService(); + } + + protected abstract searchUsingService(): Promise +} + +class SpinnerDecorator extends ListStore { + private listStore: ListStore; + + constructor(listStore: ListStore) { + super(); + this.listStore = listStore; + } + + protected async searchUsingService() { + this.openSpinner(); + + await this.listStore.search(); + + this.closeSpinner(); + } + + public openSpinner() { /* μƒλž΅ */ } + public closeSpinner() { /* μƒλž΅ */ } +} + +class OrdersStore extends ListStore { + protected async searchUsingService() { + // μ‹€μ œ API 호좜 + } +} +``` + +μ‹€μ œλ‘œ `OrderseStore` λ₯Ό `SpinnerDecorator` 둜 κ°μ‹Έκ²Œ λœλ‹€λ©΄, μ•„λž˜μ™€ 같이 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€. + +```tsx +const ordersStore = new OrdersStore(); +const ordersStoreWithSpinner = new SpinnerDecorator(ordersStore); + +ordersStoreWithSpinner.search(); +``` + +λ§Œμ•½ `OrdersStore` κ°€ μ•„λ‹ˆλΌ `PartnersStore` μ—μ„œ Spinnerκ°€ ν•„μš”ν•΄λ„ λ™μΌν•œ λ°©λ²•μœΌλ‘œ `OrdersStore` 에 μƒˆλ‘œμš΄ 역할을 μΆ”κ°€ν•  μˆ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€. + +## **πŸ”™Β μš°λ¦¬κ°€ μ‚¬μš©ν•œ μ˜ˆμ‹œ (λ˜λŠ” μš°λ¦¬κ°€ μ‚¬μš©ν–ˆλ‹€λ©΄...)** + +- [https://www.mobxjs.com/best/decorators.html](https://www.mobxjs.com/best/decorators.html) \ No newline at end of file