디자인 패턴을 항상 공부하고 싶었다.
하지만 그 시절의 나에겐 뭔가 어려웠고, 개념 자체가 이해가 잘 되지 않아 여러번 포기 했었던 것 같다.
올해 초부터 이제 공부할 타이밍이구나를 느끼고, 강의를 찾아보게 되었다.
그동안 업무하면서 겪었던 경험들이 하나둘씩 떠오르면서,
머리 속에 각각 떠돌아다니던 지식들이 패턴화되어 깔끔하게 정리가 되는 느낌이었다.
타입스크립트로 보는 GoF의 디자인 패턴 강좌 라는 유튜브 강의를 듣게 되었는데
타입스크립트를 사용하여 이해도 되고 전반적으로 깨닫는 것이 많아서 학습 내용을 정리해보려고 한다.
디자인패턴 - Flyweigh
Flyweight
동일한 객체를 중복하여 생성하지 않고, 미리 생성된 객체를 공유해서 사용한다는 개념의 패턴이다.
공유할 속성과 아닌 속성을 구분해서 생각해 주어야 한다.
연관 관계
DigitFactory 는 최대 10개의 Digit 을 소유하고,
Number 는 Digit 객체를 n개 이상 참조하고 있다
DigitFactory 는 Number 객체를 사용한다.
index.ts
나는 디버깅 관점에서 패턴을 해석해 보았다. index.ts 가 최초 발화지점(?)으로, 이곳에서 역으로 각각의 클래스들을 추적해보기로 하였다.
digitFactory 라는 객체가 생성되었고, #temp 라는 돔도 선택되었다. 아마 이놈에서 실행하는 모양이다.
number 라는 객체를 생성하기 위해 factory 객체와 value 를 넣어주었다. 그리고 number 객체의 put 이라는 함수에 dom 도 넣어주었다.
(number 객체는 이 패턴의 정점에 서있는 녀석이고, 꽤나 중요한 징검다리 역할을 담당하는 것 같다)
그럼 이제 Number 클래스로 들어가 봐야겠다.
// index.ts
const factory = new DigitFactory();
const domTarget = document.querySelector('#temp');
let value = 434341
setInterval(() => {
const number = new Number(factory, value++);
// Number객체를 생성 (factory 객체와 value 를 넣어서 만듬)
number.put(domTarget); // Number클래스의 put 함수를 실행
}, 100);
Number.ts
number 클래스 내부로 진입하였다.
일단 요놈은 constructor 로 index.ts 에서 받은 factory 와 num 을 받고 있다는 것이 확인되었다.
이 준비물들로 뭘 하는지 들여다 볼까
put 이라는 놈이 있다. (이친구는 index.ts 에서 number.put() 을 실행하던 그놈이다)
put 으로 들어간 index.ts의 domTarget 은 누군가를 자기 하위 엘레멘트로 append 한다. 어떤 놈을 append 하는 걸까?
put 으로 들어간 index.ts의 value 는 한글자 한글자 검사를 하며, factory 객체의 getDigit 이라는 함수를 실행하고, 반환값은 (객체로 추정) 자기가 지닌 put 함수를 실행한다. => 여기서 domTarget은 가공되어 나온 결과물인 div를 append 하는 것이다.
그렇다면 이제 factory 객체를 들여다 봐야 하지 않을까?
// Number.ts
export default class Number {
constructor(private factory: DigitFactory, private num: number) {}
put(dom: Element) {
const strNum = this.num.toString()
const len = strNum.length
dom. innerHTML = ''
for (let 1=0; i<len; i++) {
const div = document.createElement ("div")
this.factory.getDigit(parseInt(strNum[i])).put(div)
// factory 객체의 getDigit 메소드는 digit 객체를 반환하고,
// digit 객체의 put 메소드를 실행한다!
dom.append (div)
}
}
}
DigitFactory.ts
요놈은 생각보다 단순하다
getDigit 함수는 찾고있는 Digit 객체를 반환하는 함수이다.
내부에는 pool 이라는 10개의 저장 공간을 만들어두고, 매개 변수로 받은 인덱스에 값이 있으면 해당 Digit 객체를 반환하고, 아니면 새로운 객체를 생성한다. => 여기에서 이미 생성된 놈은 중복생성을 안하고 가져다 쓰는 개념을 실행한다.
그럼 getDigit이 반환하는 Digit 객체는 어떤 놈일까?
// DigitFactory.ts
export default class DigitFactory {
private pool: Array<Digit | null> = [null,null,null,null,null,null,null,null,null,null]
getDigit(n: number): Digit { // 넣은 숫자에 맞는 Digit 객체를 반환
if(!this.pool[n]) this.pool[n] = new Digit(`./data/${n}.json`)
// 배열 인덱스에 맞는 객체가 없으면, 새로운 digit 객체를 생성
return this.pool[n]
// 배열의 아이템을 리턴한다
}
}
Digit.ts
요놈이 핵심 중추인 Digit 이다.
url 을 받아 최초 생성시 데이터를 가져오게 된다. 그리고 자신의 put 메소드를 실행하여 돔을 생성한다.
put 메소드는 데이터가 없는 경우를 제외하고는 인자로 받은 dom 안에 data 를 넣어준다.
// Digit.ts
export default class Digit {
private data: Array<string> = null
constructor(private url: string) {}
// 최초 객체 생성시 데이터 로드 및 돔 생성 함수
private load(url: string, domOutput: Element) {
fetch(url) .then (response => { // url로 데이터 페칭
return response.json();
}).then (json => {
this.data = json
if (domOutput) this.put(domOutput)
// 돔이 있으면, put 함수로 div 엘레멘트 생성
}).catch(function (error) {
console.warn(error)
});
}
put(dom: Element): void {
if (!this.data) {
this.load(this.url, dom)
// data가 없으면 load함수를 실행해서 fetch를 받아옴
} else {
dom.innerHTML = '‹div class="digit-layout"></div›'
// data가 있으면 digit-layout 이라는 돔을 생성
const domLayout = dom.querySelector('.digit-layout')
this.data.forEach((item: string) => { // data 한글자씩 검사하면서 div를 추가
const len = item.length
for (let i = 0; i ‹ len; i++) {
const domCell = document.createElement('div' )
domCell.style.backgroundColor = item[i] === '1' ? '#ff0' : '#333'
domLayout.append(domCell)
}
})
}
}
}
강의) TypeScript로 보는 GoF의 디자인 패턴: 10. Flyweight
아래 강의를 보면서 정리하였다!
'JavaScript' 카테고리의 다른 글
HTML - 공식문서 1.8 HTML vs XML syntax (0) | 2025.01.07 |
---|---|
HTML - 이미지 태그에 lazy loading 적용하기 (4) | 2024.12.27 |
Network - Cache 그리고 Cache-Control (5) | 2024.11.14 |
HTML - 공식문서 1.7 Design notes (0) | 2024.08.19 |
CSS - Scss vs Css in Js 동작방식 비교하기 (0) | 2024.08.04 |
댓글