flyweight-pattern について
JavaScript のフライウェイトパターンを解説する学習スキルです。多数の類似オブジェクトを扱う際に共有状態を再利用してメモリ使用量を抑える方法を、ISBN によるキャッシュを例に紹介します。
主な機能
- 01共有オブジェクトインスタンスの再利用
- 02Map によるオブジェクトのキャッシュ
- 03共有状態と固有状態の分離
- 04書籍ごとの個体管理
活用シーン
- 01同じ書籍の複数冊の表現
- 02類似オブジェクトのメモリ使用量削減
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ patternsdev/ skills --skill flyweight-patternインストール後、Claude Code で/flyweight-patternを入力して読み込まれたか確認します。
詳細
フライウェイトパターン
フライウェイトパターンは、類似したオブジェクトを大量に作成するときに、メモリを節約するための便利な方法です。
アプリケーションでは、ユーザーが書籍を追加できるようにします。すべての書籍には、title、author、isbn 番号があります。しかし、図書館には通常、同じ書籍が1冊だけあるわけではありません。通常、同じ書籍の複数のコピーがあります。
使用する場合
- 利用可能なメモリを使い果たす可能性のあるオブジェクトを大量に作成する場合に使用します
- 多くのオブジェクトが同じ固有のプロパティを共有する場合に役立ちます(例:同じ ISBN の書籍)
使用しない場合
- メモリを気にする必要がない程度に、オブジェクトの数が少ない場合
- オブジェクトが共有する固有のプロパティがほとんどない、またはまったくない場合 — 固有状態と外部状態を分離すると、節約効果がないまま複雑さが増します
- 追加される検索や管理のオーバーヘッドが、メモリの節約効果を上回る場合
手順
- 固有(共有)状態と外部(固有)状態を分離します
- Map または同様の構造を使用して、共有オブジェクトのインスタンスをキャッシュし、再利用します
- 多くの場合、より簡単な代替手段として JavaScript のプロトタイプ継承を検討します
詳細
まったく同じ書籍のコピーが複数ある場合、そのたびに新しい書籍のインスタンスを作成してもあまり意味はありません。その代わりに、1冊の書籍を表す Book コンストラクターのインスタンスを複数作成します。
class Book {
constructor(title, author, isbn) {
this.title = title;
this.author = author;
this.isbn = isbn;
}
}
書籍をリストに追加する機能を作成しましょう。書籍の ISBN 番号が同じ場合、つまりまったく同じ種類の書籍である場合は、まったく新しい Book インスタンスを作成しないようにします。その代わりに、まずこの書籍がすでに存在するかどうかを確認します。
const books = new Map();
const createBook = (title, author, isbn) => {
const existingBook = books.has(isbn);
if (existingBook) {
return books.get(isbn);
}
};
書籍の ISBN 番号がまだ含まれていない場合は、新しい書籍を作成し、その ISBN 番号を isbnNumbers セットに追加します。
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;
};
createBook 関数を使うと、ある種類の書籍の新しいインスタンスを作成できます。しかし、図書館には通常、同じ書籍のコピーが複数あります。同じ書籍のコピーを複数追加できる addBook 関数を作成しましょう。この関数は createBook 関数を呼び出し、新しく作成された Book インスタンスか、すでに存在するインスタンスのいずれかを返す必要があります。
コピーの総数を把握するために、図書館にある書籍の総数を含む bookList 配列を作成しましょう。
const bookList = [];
const addBook = (title, author, isbn, availability, sales) => {
const book = {
...createBook(title, author, isbn),
sales,
availability,
isbn,
};
bookList.push(book);
return book;
};
完璧です。コピーを追加するたびに新しい Book インスタンスを作成する代わりに、そのコピーに対応する既存の Book インスタンスを効果的に再利用できます。3種類の書籍、Harry Potter、To Kill a Mockingbird、The Great Gatsby をそれぞれ5冊ずつ作成しましょう。
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);
コピーは5冊ありますが、Book インスタンスは3つだけです。
フライウェイトパターンは、利用可能な RAM をすべて使い果たす可能性のあるオブジェクトを大量に作成するときに役立ちます。消費されるメモリの量を最小限に抑えることができます。
JavaScript では、プロトタイプ継承を通じて、この問題を簡単に解決できます。現在のハードウェアには GB 単位の RAM が搭載されているため、フライウェイトパターンの重要性は低くなっています。
ソース
参考資料
- Flyweight - Refactoring Guru
- Flyweight Design Pattern - How To Do In Java