Skip to content

Commit

Permalink
Merge branch 'main' into 챕터7_2/박상범
Browse files Browse the repository at this point in the history
  • Loading branch information
sangbooom authored Nov 4, 2024
2 parents 27dd4f0 + 30ab0d1 commit c5c8355
Show file tree
Hide file tree
Showing 2 changed files with 296 additions and 0 deletions.
295 changes: 295 additions & 0 deletions 챕터_7/박승훈.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
## 생성자 패턴(Constructor Pattern)

> 객체가 새로 만들어진 뒤 초기화하는 데에 사용되는 특별한 메서드

### 객체 생성

자바스크립트에서 새로운 객체를 만들 때는 일반적으로 아래 3가지 방법을 사용한다.

```js
// 1. 객체 리터럴
const newObject = {};

// 2. Object.create() 메서드 사용
const newObject = Object.create(Object.prototype);

// 3. Object 생성자
const newObject = new Object();
```

### 클래스

- ES2015에서 도입
- 객체 템플릿을 정의하고 캡슐화 및 상속을 구현할 수 있게 해준다.
- 새 객체를 초기화하는 **constructor()** 라는 이름의 메서드를 가지고 있어야 한다.
- **new** 키워드로 생성자를 호출
- 생성자 내부에서 사용된 **this** 키워드는 새로 생성된 해당 객체(instance)
- 단점 1: 상속이 어렵다.
- 단점 2: 객체 생성시 내부 함수를 매번 새로 정의하는데, 인스턴스들은 모두 동일한 함수를 공유해야 해서 불편이 있다.


### 프로토타입

- 프로토타입 객체는 함수나 클래스 등 **특정 객체의 모든 인스턴스 내에 공통 메서드를 쉽게 정의**할 수 있게 한다.
- *나의 생각 : prototype 건드는 건 악질 안티패턴이라고 하지 않았나?*


## 모듈 패턴(Module Pattern)

> 프로젝트를 구성하는 코드 단위를 체계적으로 분리 및 관리

### 초기 자바스크립트의 모듈 구현

- 객체 리터럴 표기법
- 모듈 패턴
- AMD 모듈
- CommonJS 모듈


### 객체 리터럴

- 객체는 중괄호(`{}`) 안에서 키와 값을 쉼표(,)로 구분하여 객체를 정의
- 오류 방지를 위해 마지막 줄 끝에는 쉼표 사용을 권장하지 않는다.

<br />

> 나의 생각
prettier 같은 곳에서 trailing comma에 대한 여부를 설정할 수 있는데, 오류를 야기할 수 있다면 이런 옵션을 설정하는 기능이 없어야 하는 거 아닌가 하는 생각이 들었어요.

![trailing commas](/imgs/posts/2024/10/29/1.png)

그래서 MDN([링크](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Trailing_commas))을 찾아보니 JS 코드에서 새로운 요소를 추가할 때 이전의 마지막 줄을 변경하지 않고 새로운 줄을 바로 추가할 때 유용하게 사용할 수 있다고 나와요. 이렇게 하면 버전 관리가 더 깔끔해지고 코드 편집이 덜 번거로워질 수 있다고 하네요. **JSON을 제외한** 나머지 자바스크립트 코드에서는 허용을 하게 되어있다고 하니, 내용이 조금 충돌하는 면이 있지 않나 싶어요. 오류가 생기는 경우에 대해 알고 계시다면 의견 부탁드릴게요.


### 모듈 패턴

- 클래스의 캡슐화를 위해 처음 고안
- 클로저(closure)를 사용하여 '비공개' 상태와 구성을 캡슐화
- 공개 API만을 노출하고 나머지는 클로저 내부에 비공개로 유지 가능
- 장점: 다른 app이 사용해야 하는 부분만 노출하고, 핵심 작업은 보호
- 즉시 실행 함수(IIFE)로 구현


### WeakMap

- 모듈에서 반환된 객체에 포함된 변수를 비공개할 때 사용
- 객체만 키로 설정 가능
- 순회 불가능
- 모듈 내부의 객체에 접근하는 유일한 방법 : 해당 객체의 참조를 통해서만 가능


### 모듈 패턴의 변형 : 믹스인(mixin) import

- 유틸 함수나 외부 라이브러리 같은 전역 스코프에 있는 요소를 모듈 내부의 고차 함수에 인자로 전달
- 전역 스코프 요소를 가져와 마음대로 지정(alias)하여 사용 가능


### 모듈 패턴의 장점

- 모듈 패턴은 캡슐화 개념보다 객체 지향 프로그래밍 지식을 가진 초보 개발자가 이해하기 용이
- 비공개 지원
- 공개되면 안 되는 코드 캡슐화 가능
- 여러 의존성을 동시에 사용 가능
- 이름의 충돌 방지


### 모듈 패턴의 단점

- 공개와 비공개 멤버를 서로 다르게 접근해야 한다.
- 공개 여부를 바꾸고 싶다면 값이 위치한 파일로 가서 각각 변경해야 한다.
- 나중에 추가한 메서드에서는 비공개 멤버에 접근할 수 없다.
- 자동화 단위 테스트에서 비공개 멤버는 제외된다.
- 핫픽스가 필요한 오류를 고칠 때 복잡도를 높인다.
- 비공개 멤버는 쉽게 수정하기도 힘들기에 생각만큼 유연하게 사용할 수 없다.
- 모든 JS 런타임에서 ES2015 모듈을 사용하려면 babel 같은 트랜스파일러를 사용해야 한다.


### WeakMap을 사용한 모듈 패턴

- ES6에서 도입
- 약한 참조를 가진 키-값의 쌍으로 구성된 집합체
- 키는 객체, 값은 어떤 것이든 가능
- 키가 약하게 유지되는 map : 참조되지 않는 키는 가비지 컬렉션의 대상이 된다.


## 노출 모듈 패턴

- 공개 변수나 메서드에 접근하기 위해 가져온 메인 객체의 이름을 반복 사용해야 하는 불편에서 개선
- 모든 함수와 변수를 비공개 스코프에 정의
- 공개하고 싶은 부분만 포인터를 통해 비공개 요소에 접근할 수 있게 하는 익명 객체 반환

```js
let privateCounter = 0;

const privateFunction = () => {
privateCounter++;
};

const publicFunction = () => {
publicIncrement();
};

const publicIncrement = () => {
privateFunction();
};

const publicGetCount = () => {
return privateCounter;
};


// 비공개 함수와 속성에 접근하는 공개 포인터
const myRevealingModule = {
start: publicFunction,
increment: publicIncrement,
count: publicGetCount,
};

export default myRevealingModule;


// 사용법
import myRevealingModule from './myRevealingModule.js';

myRevealingModule.start();
```


### 장단점

- 장점
- 코드 일관성 유지 가능
- 모듈의 가장 아래에 위치한 공개 객체를 더 알아보기 쉽게 바꾸어 가독성 향상
- 단점
- 비공개 함수를 참조하는 공개 함수 수정 불가
- 비공개 변수를 참조하는 공개 객체 멤버 또한 수정 불가
- 기존 모듈 패턴보다 취약할 수 있다.


### 나의 생각

메인 객체를 계속 반복해서 사용해야 한다는 점은 같지 않나요...? 기존 모듈 객체 방식이랑 뭐가 크게 차이 나는지는 잘 모르겠어요.


## 싱글톤 패턴(Singleton Pattern)

> 클래스의 인스턴스가 오직 하나만 존재하도록 제한하는 패턴
- 전역에서 접근 및 공유해야 하는 단 하나의 객체가 필요할 때 유용
- 이미 존재하는 인스턴스가 없어야 한다.
- 인스턴스가 이미 존재할 경우 해당 인스턴스의 참조를 반환
- 정적 클래스나 객체와는 다르게 **초기화를 지연시킬 수 있다.**
- 초기화 시점에 필요한 특정 정보가 유효하지 않을 수도 있기 때문
- 클래스 내에 공개된 get, set 메서드를 통해 인스턴스를 읽기/수정 가능


### 싱글톤의 특징

- 인스턴스에 대한 전역 접근을 허용
- 클래스의 **인스턴스는 정확히 하나만 있어야 한다.**
- 눈에 잘 보이는 곳에 위치시켜 접근을 용이하게 해야 한다.
- 싱글톤의 인스턴스는 **서브클래싱(sub-classing)**을 통해서만 확장할 수 있어야 한다.
- 코드의 수정 없이 확장된 인스턴스를 사용할 수 있어야 한다.


### 지연된 실행?

> 싱글톤에서는 어째서 지연된 실행이 중요한 걸까?
- 개발자들에게 제어권을 주어 동적 초기화 순서의 예측 불가능성을 제거하는 역할
- 싱글톤과 정적 클래스(또는 객체) 사이의 차이점을 명확히 아는 것이 중요
- **필요할 때까지는 리소스나 메모리를 소모하지 않도록 지연 생성될 수도 있다.**


### 주의할 점

> JS에서 싱글톤이 필요하다는 것은 설계를 다시 생각해 봐야 한다는 신호일 수도 있다.
- C++은 객체를 생성하기 위해서 클래스를 정의해야 하지만, JS는 직접 생성할 수 있기 때문
- 즉, 객체를 하나 생성할 수 있는 상황에서 클래스를 쓰고 있지는 않는지 확인 필요
- 싱글톤 패턴은 유용하지만 남용되어서는 안 된다.(전역 공간을 차지하기 때문)


### 싱글톤의 단점

- **싱글톤임을 파악하는 것이 힘들다** : 여러 객체를 인스턴스화 하거나, 부적절하게 수정할 수 있다.
- **테스트하기 힘들다** : 숨겨진 의존성, 의존성 대체의 어려움 등 다양한 문제로 테스트하기 어렵다.


### 리액트의 상태관리

> 리액트 쓰면 싱글톤 대신 전역 상태 관리 도구를 통해 개발 가능
- 전역 상태 관리 도구는 변경 불가능한 읽기 전용 상태 제공
- 단점을 모두 쉽게 처리할 순 없지만, 적어도 컴포넌트가 전역 상태를 직접 변경할 수 없도록 한다.
- **전역 상태가 의도한 대로 변경될 수 있도록 도와준다.**


## 프로토타입 패턴(Prototype Pattern)

> 이미 존재하는 객체를 복제해 만든 템플릿을 기반으로 새 객체를 생성하는 패턴 - GoF
- 프로토타입 상속과 클래스는 별개로 사용
- 클래스 : 따로 정의
- 프로토타입 : 존재하는 다른 객체를 복제하여 새 객체를 생성

### 장점

> 다른 언어의 기능을 따라하지 않고, JS만의 고유한 방식으로 작업할 수 있다.
- *나의 생각 : 사용 언어의 특성을 살리는 것은 좋지만.. JS 구린데 그렇게 해야 하나?*

<br />

> 상속을 구현하는 쉽고 성능 좋은 방법
- 객체 내에 함수를 정의할 때 복사본이 아닌 참조로 생성
- 모든 자식 객체가 동일한 함수를 가리키게 할 수 있기 때문


### 클래스와 생성자

- 클래스와 생성자도 결국 내부적으로는 함수와 프로토타입으로 컴파일
- 여전히 프로토타입의 장점과 동시에 성능상 이점을 누리고 있는 것
- *나의 생각 : 그러면 JS 프로토타입의 성능상 이점을 살리기 위해 굳이 prototype을 쓸 필요는 없는 거 아닌가?*


## 팩토리 패턴(Factory Pattern)

> 객체 생성을 위한 인터페이스를 정의하고, 어떤 클래스의 인스턴스를 만들지 서브클래스에서 결정할 수 있게 하는 패턴

### 사용하면 좋은 상황

- 객체나 컴포넌트의 생성과정이 복잡할 때
- 상황에 맞춰 다양한 객체 인스턴스를 편리하게 생성해야 할 때
- 같은 속성을 공유하는 여러 개의 작은 객체 또는 컴포넌트를 다뤄야 할 때
- 덕 타이핑처럼 API 규칙만 충족하면 되는 다른 객체의 인스턴스와 함께 객체를 구성할 때


### 사용하면 안 좋은 상황

> 잘못된 상황에서 팩토리 패턴을 적용하면 애플리케이션의 복잡도가 크게 증가
- 객체 생성 인터페이스 제공이 작업중인 라이브러리나 프레임워크의 설계 목표가 아닐 때
- 이럴 때는 차라리 위험을 피해 생성자를 사용하는 것이 좋다.
- 객체 생성 과정이 복잡할 경우
- 단위 테스트의 복잡성이 증가할 수 있다.
- 객체 생성 과정을 인터페이스 뒤에 추상화하기 때문


### 추상 팩토리 패턴(Abstract Factory Pattern)

> 같은 목푤르 가진 각각의 팩토리들을 하나의 그룹으로 캡슐화
- 객체가 어떻게 생성되는지에 대한 세부사항을 알 필요 없이 객체를 사용할 수 있게 한다.
- **객체의 생성 과정에 영향을 받지 않아야 하거나, 여러 타입의 객체로 작업해야 할 때 유용**


## 총평

전체적으로 JS를 사용한 디자인패턴을 알아봤는데, 피부로 와닿게 사용에 대한 효용이나 필요성을 느끼지는 못한 것 같아요. 뭔가 실무적인 예시가 더 있었다면 이럴 때 쓰면 편하겠구나 체감이 될 것 같은데 간단한 예시 코드에 그치는 것 같아 아쉬웠어요. 제 깊이가 부족한 탓일까요.. 이후엔 조금 더 앞서 소개한 디자인 패턴을 활용하는 실무적인 과정이나 가이드가 있다면 좋겠다고 생각했어요.

1 change: 1 addition & 0 deletions 챕터_7/상범.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,4 @@ const MyMixins = superclass =>
> 솔직히 책 내용이 와닿지는 않아서 다른 아티클 보고 공부했다
> 플라이웨이트에 대해 잘 설명해주는 글 공유 하고 마무리 하겠습니다
> https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-Flyweight-%ED%8C%A8%ED%84%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90

0 comments on commit c5c8355

Please sign in to comment.