JavaScript

μ˜΅μ €λ²„ νŒ¨ν„΄κ³Ό 예제 μ½”λ“œ

kohi β˜• 2022. 12. 13. 22:35

πŸ‘½ Observer Pattern


μ˜΅μ €λ²„ νŒ¨ν„΄(Observer Pattern)은 μ–΄λ–€ μ΄λ²€νŠΈκ°€ μΌμ–΄λ‚˜λŠ” κ²ƒμ„ κ°μ‹œν•˜λŠ” νŒ¨ν„΄μ„ μ˜λ―Έν•œλ‹€. ν•¨μˆ˜λ‘œ μ§μ ‘ μš”μ²­ν•œ μ  μ—†μ§€λ§Œ μ‹œμŠ€ν…œμ— μ˜ν•΄ λ°œμƒν•˜λŠ” λ™μž‘듀을 μ΄λ²€νŠΈλΌ ν•˜λŠ”데, μ΄λŸ¬ν•œ μ΄λ²€νŠΈλ“€μ„ κ°μ‹œν•˜μ—¬ μ΄λ²€νŠΈκ°€ λ°œμƒν•  λ•Œλ§ˆλ‹€ λ―Έλ¦¬ μ •μ˜ν•΄ λ‘” μ–΄λ– ν•œ λ™μž‘을 μ¦‰κ° μˆ˜ν–‰ν•˜κ²Œ ν•΄ μ£ΌλŠ” ν”„λ‘œκ·Έλž˜λ° νŒ¨ν„΄μ„ μ˜΅μ €λ²„ νŒ¨ν„΄μ΄λΌ ν•œλ‹€. μ˜ˆμ‹œλ‘œ A λ²„νŠΌμ΄ ν΄λ¦­λ  λ•Œλ§ˆλ‹€ ν™”면에 'μ•ˆλ…•'을 μΆœλ ₯ν•˜λŠ” λ™μž‘을 λ“€ μˆ˜ μžˆλ‹€.

μ˜΅μ €λ²„ νŒ¨ν„΄μ„ ν™œμš©ν•˜λ©΄ λ‹€λ₯Έ κ°μ²΄μ˜ μƒνƒœ λ³€ν™”λ₯Ό λ³„λ„μ˜ ν•¨μˆ˜ ν˜ΈμΆœ μ—†μ΄ μ¦‰κ°μ μœΌλ‘œ μ•Œ μˆ˜ μžˆκΈ° λ•Œλ¬Έμ—, μ΄λ²€νŠΈμ— λŒ€ν•œ μ²˜λ¦¬λ₯Ό μžμ£Ό ν•΄μ•Ό ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ΄λΌλ©΄ λ§€μš° νš¨μœ¨μ μΈ ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•  μˆ˜ μžˆλ‹€.

 


Model의 μƒνƒœκ°€ λ³€κ²½λ˜λ©΄ μ΄λ₯Ό κ΅¬λ…ν•˜κ³  μžˆλŠ” View의 λ Œλ”링 ν•¨μˆ˜(or λ“±λ‘ν•΄ λ†“은 ν•¨μˆ˜)κ°€ μ‹€ν–‰λœλ‹€. μƒνƒœκ°€ λ³€κ²½λ¨μ— λ”°λΌ ViewλŠ” μžλ™μœΌλ‘œ λ Œλ”링이 λ˜λŠ” κ΅¬μ‘°μ΄λ‹€.

 

πŸ‘½ Observer Pattern μ½”λ“œ


export default class Observer {
  constructor() {
    this._observers = new Set();
  }
  subscribe(observer) {
    this._observers.add(observer);
  }
  notify() {
    this._observers.forEach((observer) => observer());
  }
}

 

  • _observers: 각 Viewμ—μ„œ λ“±λ‘ν•œ render λ©”μ„œλ“œκ°€ μ €μž₯될 곳이닀.
  • subscribe: Viewμ—μ„œ render λ©”μ„œλ“œλ₯Ό λ“±λ‘ν•˜λŠ” ν•¨μˆ˜μ΄λ‹€.
  • notify: Model의 μƒνƒœκ°€ λ³€κ²½μ΄ λ  λ•Œ, Viewκ°€ λ“±λ‘ν•œ render ν•¨μˆ˜λ“€μ„ ν˜ΈμΆœν•˜λŠ” ν•¨μˆ˜μ΄λ‹€.

 

Model (μœ„μ˜ ν•¨μˆ˜λ₯Ό μƒμ†λ°›μŒ)
export default class TextModel extends Observer {
  constructor() {
    super();
    this.text = "hello world";
  }
  getText() {
    return this.text;
  }
  setText(text) {
    this.text = text;
    this.notify();
  }
}

 

  • getText: ν˜„μž¬ μƒνƒœλ₯Ό λ°˜ν™˜ν•œλ‹€.
  • setText: ν˜„μž¬ μƒνƒœλ₯Ό λ°›μ€ μΈμžλ‘œ λ³€κ²½μ‹œν‚€κ³  λ“±λ‘λœ render ν•¨μˆ˜λ“€μ„ ν˜ΈμΆœν•œλ‹€.

 

View (μœ„μ˜ Model ꡬ독)
export default class TextView {
  constructor({ model }) {
    this.$target = document.createElement("div");
    this.textModel = model;
    this.textModel.subscribe(this.render.bind(this)); //Model에 ꡬ독
    this.render();
  }
  render() {
    const text = this.textModel.getText(); //Model의 μƒνƒœλ₯Ό κ°€μ Έμ™€μ„œ λ Œλ”λ§
    this.$target.innerHTML = `
      <div>${text}</div>
    `;
}

 

View λ³€κ²½ λ²„νŠΌ
export default class ChangeTextBtn {
  constructor({ model }) {
    this.$target = document.createElement("div");
    this.textModel = model;
    this.render();
    this.$target.addEventListener("click", this.handleClick.bind(this));
  }
  render() {
    this.$target.innerHTML = `
      <input tpye='text' />
      <button>text λ³€κ²½!</button>
    `;
  }
  handleClick({ target }) {
    if (target.tagName !== "BUTTON") return;
    const input = this.$target.querySelector("input");
    this.textModel.setText(input.value);
    input.value = "";
  }
}

 

 

πŸ‘½ Reference


https://velog.io/@haero_kim/%EC%98%B5%EC%A0%80%EB%B2%84-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%85%90-%EB%96%A0%EB%A8%B9%EC%97%AC%EB%93%9C%EB%A6%BD%EB%8B%88%EB%8B%A4

 

μ˜΅μ €λ²„ νŒ¨ν„΄ κ°œλ… λ– λ¨Ήμ—¬λ“œλ¦½λ‹ˆλ‹€ πŸ₯„

λ„€ν‹°μ¦Œλ“€μ€ 'κ°œλ…μ„ 이해 당해버렸닀' λ“±μ˜ λ°˜μ‘μ„ λ³΄μ˜€λ‹€.

velog.io

https://velog.io/@proshy/%EC%98%B5%EC%A0%80%EB%B2%84-%ED%8C%A8%ED%84%B4%EC%9C%BC%EB%A1%9C-%EB%B0%94%EB%8B%90%EB%9D%BCJS-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0

 

μ˜΅μ €λ²„ νŒ¨ν„΄μœΌλ‘œ 바닐라JS μƒνƒœκ΄€λ¦¬ν•˜κΈ°

바닐라 JS μ˜΅μ €λ²„ νŒ¨ν„΄ μ‚¬μš©κΈ°

velog.io

https://codesandbox.io/s/keulraeseuhyeong-objeobeopaeteon-ikkod?from-embed 

 

ν΄λž˜μŠ€ν˜• μ˜΅μ €λ²„νŒ¨ν„΄ - CodeSandbox

ν΄λž˜μŠ€ν˜• μ˜΅μ €λ²„νŒ¨ν„΄ by hayoung123 using lodash, moment

codesandbox.io