Contents

Observer Design Pattern

Observer Pattern

ํ•œ ๊ฐ์ฒด์˜ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋ฉด, ๊ทธ ๊ฐ์ฒด๋ฅผ ์˜์กดํ•˜๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์— ์—ฐ๋ฝ์ด ๊ฐ€๊ณ  ์ž๋™์œผ๋กœ ๋‚ด์šฉ์ด ๊ฐฑ์‹ ๋˜๋„๋ก ํ•˜๋Š” ํŒจํ„ด์œผ๋กœ OneToMany ์˜์กด์„ฑ์„ ์ •์˜ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ OneToMany ์˜์กด์„ฑ์ด๋ž€, ์ฃผ์ œ๋Š” ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ œ์–ดํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ƒํƒœ๊ฐ€ ๋“ค์–ด์žˆ๋Š” ๊ฐ์ฒด๋Š” ์˜ค๋กœ์ง ํ•˜๋‚˜์ด๋‹ค. ๋ฐ˜๋ฉด์— ๊ทธ ์ƒํƒœ๋ฅผ ์˜์กดํ•˜๋Š” Observer ๊ฐ์ฒด๋Š” ์—ฌ๋Ÿฌ๊ฐœ์ด๋‹ค ๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.โ‚ฉโ‚ฉ

์ฃผ๋กœ ํ”„๋ก ํŠธ์—”๋“œ ๊ด€์ ์—์„œ, observer pattern์„ ์ •์˜ํ•œ ๊ณณ์ด ๋งŽ์ง€๋งŒ ๋ฐฑ์—”๋“œ์—์„œ๋„ observer pattern์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ์˜ˆ์ œ ์ผ€์ด์Šค๋“ค์ด ๋งŽ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, nodejs์˜ eventEmitter / logging / socket / distributed system / caching

observer pattern์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  • Subject์™€ Observer ๊ฐ€ ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ๋Š์Šจํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด Subject์— ๋ณ€ํ™”๊ฐ€ ์žˆ์–ด๋„ Observer์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.
  • ์—ฌ๋Ÿฌ Observer๊ฐ€ ์กด์žฌํ•˜๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์—์„œ, ์ƒˆ๋กœ์šด Observer๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค๋ฉด ๋‹จ์ˆœํžˆ Subject๊ฐ€ ๊ตฌ๋…๋งŒ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ๋ฐ˜๋Œ€๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค.
  • Observer pattern ์—์„œ๋Š” Subject ๋งŒ์ด ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ œ์–ดํ•จ์œผ๋กœ์จ, ๋ฆฌ์†Œ์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ณณ์€ ํ•˜๋‚˜์ด๋ฏ€๋กœ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋น„๋™๊ธฐ ์ž‘์—…์„ ๊ฐ์‹œํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€, ์•Œ๋ฆผ์œผ๋กœ ์ „๋‹ฌํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

๋Š์Šจํ•œ ๊ฒฐํ•ฉ(loose coupling)

  • ์ฃผ์ œ๋Š” ์˜ต์ €๋ฒ„๊ฐ€ ํŠน์ • interface๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค๋งŒ ์•ˆ๋‹ค.
  • ์˜ต์ €๋ฒ„๋Š” ์–ธ์ œ๋“ ์ง€ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์ œ๊ฑฐ๋  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฃผ์ œ๋‚˜ ์˜ต์ €๋ฒ„๋ฅผ ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด๋„ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋Š์Šจํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋Š์Šจํ•œ ๊ฒฐํ•ฉ์€ ๊ฐ์ฒด ์‚ฌ์ด์˜ ์ƒํ˜ธ์˜์กด์„ฑ์„ ์ตœ์†Œํ™”ํ•จ์œผ๋กœ์จ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ƒ๊ฒจ๋„ ๋ฌด๋‚œํžˆ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐํ•œ ๊ฐ์ฒด์ง€ํ–ฅ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์˜ˆ์ œ

์˜ˆ๋ฅผ ๋“ค์–ด NewPost๋ผ๋Š” class๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. ์ด class ๋Š” ์ƒˆ๋กœ ๋ฐœํ–‰๋œ ๊ฒŒ์‹œ๋ฌผ์„ ๊ด€๋ฆฌํ•˜๋Š”๋ฐ ์ƒˆ๋กœ์šด ๊ฒŒ์‹œ๋ฌผ์ด ๋“ฑ๋ก๋  ๋•Œ๋งˆ๋‹ค ์šฐ๋ฆฌ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜๋ฅผ ์—…๋ฐ์ดํŠธ / ์ผ๋ณ„ ํฌ์ŠคํŒ… ์ˆ˜ ์—…๋ฐ์ดํŠธ / ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์„ ์ž‘์„ฑํ•œ ์œ ์ €๋ฅผ ํŒ”๋กœ์ž‰ํ•˜๊ณ  ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋‚˜๊ฐ„ ์•Œ๋ฆผ ์ˆ˜๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํ•ด๋ณด์ž.

๊ตฌํ˜„๋ณด๋‹ค๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ผ๋Š” ๋””์ž์ธ ์›์น™ / ๋ฐ”๋€Œ๋Š” ๋ถ€๋ถ„์€ ์บก์Šํ™”ํ•œ๋‹ค๋Š” ๋””์ž์ธ ์›์น™์„ ์–ด๊ธฐ๊ณ  ๋Œ€์ถฉ ์งœ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์„ ๊ฒƒ์ด๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class NewPosts {
  const userIdx = getUserIdx()
  const postIdx = getPostIdx()
  const followingIds = getFollowingIds()

  // ๊ตฌํ˜„์— ํŽธ์˜์„ฑ์„ ์œ„ํ•ด ํ•„์š”์—†๋Š” ์ธ์ž๋„ ๋„˜๊ฒผ๋‹ค.
  postNumByCategory.update(userIdx, postIdx, followingIds)
  postNumByDaily.update(userIdx, postIdx, followingIds)
  notiNumByFollowing.update(userIdx, postIdx, followingIds)

}

์œ„์™€ ๊ฐ™์ด ๊ตฌ์„ฑ์„ ํ•˜๊ฒŒ ๋˜๋ฉด, ์ถ”๊ฐ€์ ์ธ ํ†ต๊ณ„์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ด๋ฏธ newPosts๋ผ๋Š” ๊ฐ์ฒด์—์„œ ๊ตฌํ˜„๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ updateํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์ถฉ๋ถ„ํžˆ ๋ฐ”๋€” ์—ฌ์ง€๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์บก์Šํ™”๋ฅผ ํ•ด์•ผํ•  ๊ฒƒ์ด๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
interface Subjects {
  // Attach an observer to the subject.
  attach(observer: Observer): void;

  // Detach an observer from the subject.
  detach(observer: Observer): void;

  // Notify all observers
  notify(): void;
}

class NewPosts implements Subjects {
  postIdx: number;
  userIdx: number;
  followingIds: number;

  /**
   * The subscription management methods.
   */
  public attach(observer: Observer): void {
    const isExist = this.observers.includes(observer);
    if (isExist) {
      return console.log("Subject: Observer has been attached already.");
    }

    console.log("Subject: Attached an observer.");
    this.observers.push(observer);
  }

  public detach(observer: Observer): void {
    const observerIndex = this.observers.indexOf(observer);
    if (observerIndex === -1) {
      return console.log("Subject: Nonexistent observer.");
    }

    this.observers.splice(observerIndex, 1);
    console.log("Subject: Detached an observer.");
  }

  /**
   * Trigger an update in each subscriber.
   */
  public notify(): void {
    console.log("Subject: Notifying observers...");
    for (const observer of this.observers) {
      observer.update(this);
    }
  }
}

interface Observer {
  update(subject: Subject);
}

class PostNumByCategory implements Observer {
  update(subject: Subject) {
    // update post num by category
  }
}

class PostNumByDaily implements Observer {
  update(subject: Subject) {
    // update post num by Daily
  }
}

class NotiNumByFollowing implements Observer {
  update(subject: Subject) {
    // update noti num by following
  }
}

์œ„ ์ฒ˜๋Ÿผ ๊ตฌ์„ฑํ•˜๊ฒŒ ๋˜๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด subject ๊ฐ€ observer๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ๋˜๋Š” ํ•ด์ง€ํ•˜๋Š” ๊ฒƒ์ด ์šฉ์ดํ•˜๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const newPosts = new newPosts();

const postNumByCategory = new PostNumByCategory();
newPosts.attach(postNumByCategory);

const PostNumByDaily = new PostNumByDaily();
newPosts.attach(PostNumByDaily);

const NotiNumByFollowing = new NotiNumByFollowing();
newPosts.attach(NotiNumByFollowing);

// ๋งŒ์•ฝ ์ƒˆ๋กœ์šด ๊ฒŒ์‹œ๊ธ€์ด ์ƒ๊ฒผ๋‹ค๋ฉด ๋‹จ์ˆœํžˆ ๊ตฌ๋…์ค‘์ธ observer๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ  notify๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.
newPosts.notify();