亨元模式

当创建大量相似的对象时,享元模式是一种节省内存的有用方法。


图书馆案例

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

如果完全相同的书有多个副本,则每次都创建一个新书实例并不是很有用。
相反,我们想要创建 Book 构造函数的多个实例,代表一本书。

class Book {
  constructor(title, author, isbn) {
    this.title = title;
    this.author = author;
    this.isbn = isbn;
  }
}

让我们创建将新书添加到列表中的功能。

如果一本书具有相同的 ISBN 号,因此是完全相同的书籍类型,我们不想创建一个全新的 Book 实例。

相反,我们应该首先检查这本书是否已经存在。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

const isbnNumbers = new Set(); //允许存储任何类型的唯一值,无论是原始值或者是对象引用

const createBook = (title, author, isbn) => {
  const book = isbnNumbers.has(isbn);

  if (book) {
    return book;
  }
};

如果它还不包含书的 ISBN 号,我们将创建一个新书并将其 ISBN 号添加到 isbnNumbers 集。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

const isbnNumbers = new Set();

const createBook = (title, author, isbn) => {
  const book = isbnNumbers.has(isbn);

  if (book) {
    return book;
  }

  const book = new Book(title, author, isbn);
  isbnNumbers.add(isbn);

  return book;
};

createBook 函数帮助我们创建一种类型书籍的新实例。
但是,图书馆通常包含同一本书的多个副本!

创建一个 addBook 函数,它允许添加同一本书的多个副本。
它应该调用 createBook 函数,该函数返回一个新创建的 Book 实例,或者返回已经存在的实例。

为了跟踪副本总数,让我们创建一个 bookList 数组,其中包含图书馆中的图书总数。

const bookList = [];

const addBook = (title, author, isbn, availibility, sales) => {
  const book = {
    ...createBook(title, author, isbn),
    sales,
    availibility,
    isbn
  };

  bookList.push(book);
  return book;
};

Perfect! 不是每次添加副本时都创建一个新的 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 实例!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

class Book {
  constructor(title, author, isbn) {
    this.title = title;
    this.author = author;
    this.isbn = isbn;
  }
}

const isbnNumbers = new Set();
const bookList = [];

const addBook = (title, author, isbn, availibility, sales) => {
  const book = {
    ...createBook(title, author, isbn),
    sales,
    availibility,
    isbn
  };

  bookList.push(book);
  return book;
};

const createBook = (title, author, isbn) => {
  const book = isbnNumbers.has(isbn);
  if (book) {
    return book;
  } else {
    const book = new Book(title, author, isbn);
    isbnNumbers.add(isbn);
    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); // Total amount of copies:  5
console.log("Total amount of books: ", isbnNumbers.size); // Total amount of books:  3

优点

当您创建大量对象时,这可能会耗尽所有可用 RAM。

享元模式很有用,它使我们能够最大限度地减少消耗的内存量。

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


知识点

  • Set() - Set 对象允许存储任何类型的唯一值,无论是原始值或者是对象引用。
此页面上有什么