享元模式(flyweight pattern)

126 阅读3分钟

重用现有实例来处理相同的对象

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

在我们的应用中,我们希望用户能够添加书籍。所有的书籍都有,title, author, isbn 。可是,图书馆通常不会只有一本书的副本,一本书通常会有大量的副本。

如果现有的书存在多个副本,那么每次都创建一个书的实例并不是很有用。相反,我们要创建Book构造函数的多个实例来代表一本书。

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

让我们创建一个把新书添加到列表中的功能,如果一本书拥有相同的ISBN号,可以说这是相同的书籍类型。我们不需要创建一本全新的书的实例,反而,我们首先需要检查这本书是否存在

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实例

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);
console.log("Total amount of books: ", isbnNumbers.size);

当你要创建大量对象的时候,它可能会耗尽你的RAM内存,使用享元模式能够非常有用的最大限度的减少内存的消耗。

在JavaScript中,我们可以很容易的通过原型继承来解决这个问题。现在的硬件都拥有数GB的RAM内存,这显得享元模式并没那么重要。