Skip to content

Commit

Permalink
[우창완] 챕터 7: 자바스크립트 디자인 패턴 (3/3) (#67)
Browse files Browse the repository at this point in the history
* 7-3

* 오타

* chapter 8
  • Loading branch information
WooWan authored Nov 17, 2024
1 parent c82ebac commit f081052
Show file tree
Hide file tree
Showing 2 changed files with 305 additions and 0 deletions.
78 changes: 78 additions & 0 deletions 챕터_7/우창완.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,81 @@ const milkCoffee = new MilkDecorator(coffee);
### 7.14 의사 클래스 데코레이터

`Interface.ensureImplements`까지 하는 것은 투머치.. 타입스크립트를 사용하자

### 7.16 플라이웨이트 패턴

플라이웨이트 패턴은 반복되고 비효율적으로 데이터를 공유하는 코드를 최적화하는 구조적 해결 방법

OOP + Data Oriented Programming 과 비슷한 느낌, 데이터 응집성에 포커스를 맞춘다.

`checkoutMember`, `dueReturnDate` 는 Book 의 속성? -> 아니다.

OOP 의 메모리 과도한 점유를 `상태``데이터`의 결합도를 낮춘 형태. 결국 중요한 것은 응집도

### 7.17 행위 패턴

행위패턴이란 `객체간의 의사소통`

- 관찰자 패턴
- 중재자 패턴
- 커맨드 패턴

### 7.18 관찰자 패턴

관찰자 패턴은 update를 기반으로 상태를 관리 (Subject, Observer)

주체를 업데이트 할때, 데이터 변경을 감지할 때 `update`를 기반으로 동작한다.

Subject: Observer: 1: N, (N:M이 될수도 있음)

> Subject.action -> Subject.nofity(Observer.update()) 형태로 Observer에게 Subject의 상태 변경을 알린다.
```
Subject: 데이터의 주체
action: notify() 를 호출한다.
addObserver, removeObserver: Observer => void
notify: data => void // Observer.update() 자신을 구독하고 있는 Observer에게 상태변화를 알림.
Observer: Subject의 관찰자.
update: () => T // 상태변화에 따른 특정 액션
```

### 7.18.1 관찰자 패턴과 발행/구독 패턴의 차이점

Pub/sub 패턴과의 차이는 변경 전파 책임

관찰자 패턴의 변경 감지 전파의 책임은 Subject에게 있다.

시그니처를 보았을 때는 Pub/sub 더 유연해보이고, 상태 변화/감지의 책임이 더 잘 나누어진 것으로 보였음

하지만, 대부분의 경우는 Subject -> Observer로 바로 상태변화를 알리는 것이 명료해보이지만, 응집도는 많이 떨어짐

아래 사고를 거쳐서 계층의 필요타당성을 생각해보기

- 두 객체간의 결합도를 낮추는 것이 꼭 필요할 때 (분리가 필요한 계층, 계층적으로 달라야 필요성이 있을 듯)
- 발행/구독 계층이 어떤 문제를 해결해주는가?

예시 중, 사용자와 리뷰의 관계가 결합도를 낮춰야할만큼의 다른 계층인가? -> 아니라고 생각함, 오히려 응집도가 낮아짐(161p)

EventEmitter 도 떠오르는데, 어떤 Event가 emit되면 특정 함수를 호출하는 형태도 pub/sub의 일부와 비슷해보인다.

RxJS 처음 본 인상은 Effect(state) => ui 형태로 사이드이펙트를 잘 제어할 수 있으면, 유지보수하기 좋은 형태를 만들 수 있을 것 같지만,

사이드이펙트 관리에 대한 이해가 부족하면 오히려 독이 있을 것 같다 (debugging, 참조 투명성, descriptive name의 부재 등)

### 7.19 중재자 패턴

중재자 패턴은 하나의 객체가 이벤트 발생 시, 다른 여러 객체들에게 알림을 보낼 수 있는 디자인 패턴 -> 관찰자 패턴가 뭐가 다르지?

### 7.20 커맨드 패턴

명령을 trigger하는 객체와 명령을 execute 하는 객체가 분리되어 있는 패턴

책의 예시는 실질적으로 결합도를 낮추지 못한다. 불필요한 추상화

-> `buyVehicle``buyCar` 로 변경되면 execute('buyCar')도 함께 변경되어야 한다.

결합도 관련해서 재밌게 읽은 글 남깁니다!
https://maxkim-j.github.io/posts/coupling
227 changes: 227 additions & 0 deletions 챕터_8/우창완.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# 자바스크립트 MV* 패턴



## 8.1 MVC 패턴

MVC 패턴에서 Model과 View가 Subject, Observer 관계로 결합도를 낮춘 형태

* Model

```js
// Model: 데이터 관리와 비즈니스 로직
class TodoModel {
constructor() {
this.todos = [];
this.observers = [];
}

addTodo = (text) => {
this.todos.push({ id: Date.now(), text, completed: false });
this.notify();
}

addObserver = (observer) => {
this.observers.push(observer);
}

notify = () => {
this.observers.forEach(observer => observer(this.todos));
}
}
```

* Controller

Controller에서 View에 함수를 binding, model에 observer를 추가한다.

```js
// Controller: Model과 View 연결
class TodoController {
constructor(model, view) {
this.model = model;
this.view = view;

// View의 이벤트를 Model과 연결
this.view.bindAddTodo(this.handleAddTodo);
this.model.addObserver(this.view.display);
}

handleAddTodo = (text) => {
this.model.addTodo(text);
}
}
```



* View

```js
// View: UI 표시와 사용자 입력 처리
class TodoView {
constructor() {
this.input = document.createElement("input");
this.button = document.createElement("button");
this.list = document.createElement("ul");
}

display = (todos) => {
this.list.innerHTML = "";
todos.forEach(todo => {
const li = document.createElement("li");
li.textContent = todo.text;
this.list.appendChild(li);
});
}

bindAddTodo = (handler) => {
this.button.addEventListener("click", () => {
if (this.input.value) {
handler(this.input.value);
this.input.value = "";
}
});
}
}
```





## MVP 패턴

MVC 패턴에서 model과 view 가 관찰자 패턴으로 커뮤니케이션 했다면, MVP패턴은 Presenter 계층이 중간에서 조정하는 역할을한다.

* MVC

```
Model ──(Observer 패턴)─→ View
↑ │
└─────── Controller ──────┘
```



* MVP

```
Model ←→ Presenter ←→ View
```



* 계층 별로 테스트 하기가 더 용이

* 개인적으로는 더 명시적이어서 개발 인지부하가 더 적을거 같다.

* 수동적인 VIew 계층 (MVC에서는 데이터 조작에 직접 관여, MVP에서는 관여 여지가 적음)











### MVVM 모델

Mvvm 모델로 오면서, UI 개발자와 서버 개발자가 분리될 수 있었음

코드를 살펴봤을 때는 MVC모델에서 Model의<->View의 관찰자 패턴의 ViewModel(presenter) <-> View의 관찰자 패턴으로 이동한 것 같다.



MVP에서 Model과 View의 분리의 장점을 가져가면서도, 단방향 데이터 흐름을 만들 수 있는 것이 ``이다



아래 코드에서 ViewModel이 View를 직접적으로 모르지만, `상태`가 업데이트되었음을 알리고, View에서 render() 를 통해 선언적으로 UI를 표현하는 방식이 react에도 많은 영향을 주지 않았나 싶다.

```js
class TodoViewModel {
private todos: string[] = [];
private subscribers: Array<() => void> = [];

// ... 중요한 로직들

subscribe(callback: () => void): void {
this.subscribers.push(callback);
}

private notifySubscribers(): void {
this.subscribers.forEach(callback => callback());
}
}

// View
class TodoViewMVVM {
private input: HTMLInputElement;
private list: HTMLUListElement;

constructor(private viewModel: TodoViewModel) {
// DOM 설정...

// 이벤트 바인딩
this.input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const todo = this.input.value;
if (todo) {
this.viewModel.addTodo(todo);
this.input.value = '';
}
}
});

// ViewModel 구독
this.viewModel.subscribe(() => this.render());
}

private render(): void {
const todos = this.viewModel.getTodos();
this.list.innerHTML = '';
todos.forEach((todo, index) => {
const li = document.createElement('li');
li.textContent = todo;
li.addEventListener('click', () => this.viewModel.removeTodo(index));
this.list.appendChild(li);
});
}
}

```































0 comments on commit f081052

Please sign in to comment.