享元模式透過重複使用物件來減少資料量並節省記憶體。
圖書館有很多藏書,同一本書可能有多本館藏,以滿足讀者需求。假設每次購書都要將書本的基本資料輸入圖書管理系統,例如書名、作者和出版社,我們不必為相同的書籍重複建檔,而是應該為每一本館藏加上編號,並讓相同的書籍共用同一份資料。這些書籍資料就像享元物件一樣,透過重複使用書籍資料,可以避免重複並減少資料量。
當瀏覽器加載圖片時,會先檢查該圖片是否存在快取中,再根據結果決定要使用快取或是從伺服器下載圖片。這種機制不僅能提升網頁的回應速度,還能減輕對伺服器的負擔。我們試著用享元模式模擬這套快取機制。
ImageData
是一個享元物件,負責從伺服器下載並儲存圖片資料。這些資料可以重複渲染同一張圖片,以實現資源共享。
class ImageData {
readonly url: string;
constructor(url: string) {
this.url = url;
console.log(`Loading image from ${url}`);
}
}
Image
類別負責在畫面上渲染圖片。每個實例包含圖片的座標位置和對應的圖片資料。
class Image {
private x: number;
private y: number;
private imageData: ImageData;
constructor(x: number, y: number, imageData: ImageData) {
this.x = x;
this.y = y;
this.imageData = imageData;
}
render() {
console.log(
`Rendering image from: ${this.imageData.url} at position ` +
`(${this.x}, ${this.y})`
);
}
}
ImageDataStore
是圖片資料的管理中心,負責圖片資料的建立與快取管理。它只會在必要時加載圖片,以避免重複加載相同的資料。
class ImageDataStore {
private dataMap: Map<string, ImageData> = new Map();
getOne(url: string) {
if (!this.dataMap.has(url)) {
this.dataMap.set(url, new ImageData(url));
}
return this.dataMap.get(url)!;
}
}
這個類別用來模擬一個網頁文件,它提供新增圖片和渲染文件的方法,渲染方法渲染文件中的所有圖片。
class Document {
private images: Image[] = [];
private imageDataStore: ImageDataStore = new ImageDataStore();
addImage(x: number, y: number, url: string) {
const imageData = this.imageDataStore.getOne(url);
const image = new Image(x, y, imageData);
this.images.push(image);
}
render() {
this.images.forEach((image) => {
image.render();
});
}
}
以下範例展示 ImageDataStore
如何通過重複使用圖片資料來避免重複載入並節省資源。
class DocumentTestDrive {
static main() {
const document = new Document();
document.addImage(20, 20, "https://foo.com/images/sample1.png");
document.addImage(40, 40, "https://foo.com/images/sample2.png");
document.addImage(60, 60, "https://foo.com/images/sample1.png");
document.render();
}
}
DocumentTestDrive.main();
執行結果:
Loading image from https://foo.com/images/sample1.png
Loading image from https://foo.com/images/sample2.png
Rendering image from: https://foo.com/images/sample1.png at position (20, 20)
Rendering image from: https://foo.com/images/sample2.png at position (40, 40)
Rendering image from: https://foo.com/images/sample1.png at position (60, 60)
享元模式的主要目的是節省記憶體用量,特別適合處理數量龐大且重複性高的物件。它將物件的狀態分為可變與不變,將可變的狀態抽離,並將不變的狀態封裝成享元物件。透過重複使用享元物件,可以減少重複性資料,藉此減少記憶體的消耗。當物件中的重複性資料越多,其帶來的效益就越顯著。
https://github.com/chengen0612/design-patterns-typescript/blob/main/patterns/structural/flyweight.ts