有兴趣了解我们的下一本书吗?了解更多关于 使用 React 构建大型 JavaScript Web 应用程序

设计模式

享元模式

享元模式是一种在创建大量相似对象时节约内存的有效方法。

在我们的应用程序中,我们希望用户能够添加书籍。所有书籍都有一个 title、一个 author 和一个 isbn 号码!但是,图书馆通常不会只有一本相同书籍的副本:通常会有多本相同书籍的副本。

如果有多本完全相同的书籍,每次都创建一个新的书籍实例就没什么用了。相反,我们希望创建 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 本书籍的 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 个副本,但我们只有 3 个 Book 实例!

index.js
1class Book {
2 constructor(title, author, isbn) {
3 this.title = title;
4 this.author = author;
5 this.isbn = isbn;
6 }
7}
8
9const isbnNumbers = new Set();
10const bookList = [];
11
12const addBook = (title, author, isbn, availibility, sales) => {
13 const book = {
14 ...createBook(title, author, isbn),
15 sales,
16 availibility,
17 isbn
18 };
19
20 bookList.push(book);
21 return book;
22};
23
24const createBook = (title, author, isbn) => {
25 const book = isbnNumbers.has(isbn);
26 if (book) {
27 return book;
28 } else {
29 const book = new Book(title, author, isbn);
30 isbnNumbers.add(isbn);
31 return book;
32 }
33};
34
35addBook("Harry Potter", "JK Rowling", "AB123", false, 100);
36addBook("Harry Potter", "JK Rowling", "AB123", true, 50);
37addBook("To Kill a Mockingbird", "Harper Lee", "CD345", true, 10);
38addBook("To Kill a Mockingbird", "Harper Lee", "CD345", false, 20);
39addBook("The Great Gatsby", "F. Scott Fitzgerald", "EF567", false, 20);
40
41console.log("Total amount of copies: ", bookList.length);
42console.log("Total amount of books: ", isbnNumbers.size);

当您创建大量的对象,这些对象可能会消耗掉所有可用的 RAM 时,享元模式很有用。它允许我们最大限度地减少消耗的内存量。

在 JavaScript 中,我们可以通过 原型继承 轻松解决此问题。如今,硬件拥有 GB 级别的 RAM,这使得享元模式变得不那么重要了。


参考文献