Flyweight (Cache)
- 각 객체에 모든 데이터를 유지하는 대신
여러 객체 간에 상태의 공통 부분을 공유하여 사용할 수 있는 RAM에 더 많은 객체를 포함할 수 있도록 함
- 객체 내부에 Extrinsic (Unique, Mutable)의 저장을 중단하고,
대신 이 상태를 이 상태에 의존하는 특정 메서드들에 전달할 것을 제안함
즉, Intrinsic (Repeating, Immutable)만 저장함
- 공유한 상태 스토리지
- 공유한 상태는 패턴을 적용하기 전에 객체들을 집합시키는 컨테이너 객체로 이동됨
- 플라이웨이트와 불변성
- 플라이웨이트 팩토리
- 프로그램이 많은 수의 객체들을 지원해야 해서 사용할 수 있는 RAM을 거의 다 사용했을 때만 사용하기
- 프로그램들이 객체들의 메모리 소비를 낮게 유지하여 방대한 양의 객체들을 지원할 수 있도록 함
- 여러 객체 사이의 객체 상태를 공유함
- 다른 객체들이 공통으로 사용하는 데이터를 캐싱하여 RAM 절약
- 동일한 객체를 다룰 때 이미 존재하는 인스턴스를 재사용함
- 비슷한 객체를 대량으로 만들어야 할 때 메모리 절약할 수 있게 해주는 유용한 패턴
- 메모리 사용량 최소화할 수 있음
- JS에서 프로토타입 상속을 통해서도 비슷한 효과를 낼 수 있어서 크게 중요하지는 않음
- 예시
/**
* The Flyweight stores a common portion of the state (also called intrinsic
* state) that belongs to multiple real business entities. The Flyweight accepts
* the rest of the state (extrinsic state, unique for each entity) via its
* method parameters.
*/
class Flyweight {
private sharedState: any;
constructor(sharedState: any) {
this.sharedState = sharedState;
}
public operation(uniqueState: any): void {
const s = JSON.stringify(this.sharedState);
const u = JSON.stringify(uniqueState);
console.log(`Flyweight: Displaying shared (${s}) and unique (${u}) state.`);
}
}
/**
* The Flyweight Factory creates and manages the Flyweight objects. It ensures
* that flyweights are shared correctly. When the client requests a flyweight,
* the factory either returns an existing instance or creates a new one, if it
* doesn't exist yet.
*/
class FlyweightFactory {
private flyweights: { [key: string]: Flyweight } = <any>{};
constructor(initialFlyweights: string[][]) {
for (const state of initialFlyweights) {
this.flyweights[this.getKey(state)] = new Flyweight(state);
}
}
/**
* Returns a Flyweight's string hash for a given state.
*/
private getKey(state: string[]): string {
return state.join('_');
}
/**
* Returns an existing Flyweight with a given state or creates a new one.
*/
public getFlyweight(sharedState: string[]): Flyweight {
const key = this.getKey(sharedState);
if (!(key in this.flyweights)) {
console.log(
"FlyweightFactory: Can't find a flyweight, creating new one."
);
this.flyweights[key] = new Flyweight(sharedState);
} else {
console.log('FlyweightFactory: Reusing existing flyweight.');
}
return this.flyweights[key];
}
public listFlyweights(): void {
const count = Object.keys(this.flyweights).length;
console.log(`\nFlyweightFactory: I have ${count} flyweights:`);
for (const key in this.flyweights) {
console.log(key);
}
}
}
/**
* The client code usually creates a bunch of pre-populated flyweights in the
* initialization stage of the application.
*/
const factory = new FlyweightFactory([
['Chevrolet', 'Camaro2018', 'pink'],
['Mercedes Benz', 'C300', 'black'],
['Mercedes Benz', 'C500', 'red'],
['BMW', 'M5', 'red'],
['BMW', 'X6', 'white'],
// ...
]);
factory.listFlyweights();
// ...
function addCarToPoliceDatabase(
ff: FlyweightFactory,
plates: string,
owner: string,
brand: string,
model: string,
color: string
) {
console.log('\nClient: Adding a car to database.');
const flyweight = ff.getFlyweight([brand, model, color]);
// The client code either stores or calculates extrinsic state and passes it
// to the flyweight's methods.
flyweight.operation([plates, owner]);
}
addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'M5', 'red');
addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'X1', 'red');
factory.listFlyweights();
class Book {
constructor(title, author, isbn) {
this.title = title;
this.author = author;
this.isbn = isbn;
}
}
const books = new Map();
const bookList = [];
const addBook = (title, author, isbn, availability, sales) => {
const book = {
...createBook(title, author, isbn),
sales,
availability,
isbn
};
bookList.push(book);
return book;
};
const createBook = (title, author, isbn) => {
const existingBook = books.has(isbn);
if (existingBook) {
return books.get(isbn);
}
const book = new Book(title, author, isbn);
books.set(isbn, book);
return book;
};
addBook("Harry Potter", "JK Rowling", "AB123", false, 100);
addBook("Harry Potter", "JK Rowling", "AB123", true, 50);
addBook("To Kill a Mockingbird", "Harper Lee", "CD345", true, 10);
addBook("To Kill a Mockingbird", "Harper Lee", "CD345", false, 20);
addBook("The Great Gatsby", "F. Scott Fitzgerald", "EF567", false, 20);
console.log("Total amount of copies: ", bookList.length);
console.log("Total amount of books: ", books.size);
- 활용
반응형
'Personal-Study > Design Patterns' 카테고리의 다른 글
[TS Design Patterns] 행동 패턴 - 책임 연쇄 (2) | 2023.11.01 |
---|---|
[TS Design Patterns] 행동 패턴 - 옵저버 (0) | 2023.10.30 |
[TS Design Patterns] 구조 패턴 - 퍼사드 (0) | 2023.10.28 |
[TS Design Patterns] 구조 패턴 - 데코레이터 (2) | 2023.10.28 |
[TS Design Patterns] 구조 패턴 - 프록시 (2) | 2023.10.26 |
댓글