# 享元模式

享元模式，英文为Flyweight Pattern，fly weight翻译过来即轻量级（可以飞起来的重量，就是轻量级啊）

享元模式的本质：对象复用（节省内存空间，提升系统性能）

解释：假如你需要1000个对象A，而这1000个对象有非常多的属性或状态都是一样的（不会改变），只有一部分属性或状态不一样（随外界需求而变）。我们将这些一致的不变的属性称之为内部状态，将随外界环境（其实就是客户需求）的改变而改变的属性称之为外部状态。

举个例子，假如在设计游戏的时候，在一些场景下，需要1000个小兵，这1000个小兵只是在地图上的位置不同，但战斗力都相同。这里小兵的战斗力就是小兵的内部状态，而小兵的位置就是小兵的外部状态。

再举个例子，还有五子棋、围棋等游戏，假如需要100个棋子，这些棋子的位置是随时改变的，而棋子的归属（哪个玩家的）、棋子的颜色（一般同一玩家的棋子颜色一致）都是不会变化的，这里位置就是棋子的外部状态，而棋子的归属、颜色就是棋子内部状态。

再再举一个例子，假如系统中有10本书，然后每本书有1000个订单，现在这10\*1000个订单的信息（每个订单中要包含对应书的信息）。对这10\*1000个订单而言，订单自身信息（如下单人、下单时间、金额等）是不一样的，就是外部信息，而对于订单中包含的书的信息则属于内部状态，只有10种，系统中，只要有10个书的实例即可。享元，共享的是这10个书的实例。

**示例：上面书与订单的例子**

书

```java
public class Book {

    private String bookName;
    private String author;
    private int price;

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}
```

订单

```java
public class Order {

    private String username;
    private Book book;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }
}
```

生成订单

```java
public class OrderFactory {

    private static final Map<String, Book> books = new HashMap<>();

    public static Order generateOrder(String username, String bookName){
        Order order = new Order();
        order.setUsername(username);
        if(books.containsKey(bookName)){
            order.setBook(books.get(bookName));
        }else {
            Book book = createNewBookInstance(bookName);
            order.setBook(book);
            books.put(bookName,book );
        }
        return order;
    }

    private static Book createNewBookInstance(String bookName){
        //演示，实际可能是去数据库等获取具体信息
        Book book = new Book();
        book.setBookName(bookName);
        book.setAuthor("maxwell");
        book.setPrice(new Random().nextInt(100));
        return book;
    }
}
```

客户端

```java
public class Client {

    public static void main(String[] args) {

        //假如只有10种书，每本书有1000个订单，而在某处我们需要将这些订单信息都加载到内存中，
        // 这10*1000个订单实例则会共享这10个书的实例
        // 这样就可以节省[（10*1000 - 10 ）* 每个书的实例的大小]的内存空间
        List<Order> orders = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            String bookName = "book" + i;
            for (int j = 0; j < 1000; j++) {
                Order order = OrderFactory.generateOrder("xiaoming" + j, bookName);
                orders.add(order);
            }
        }
    }
}
```

## 参考

[JAVA设计模式-享元模式（Flyweight）](https://www.jianshu.com/p/f88b903a166a)

[一起学设计模式 - 享元模式](http://blog.battcn.com/2017/11/17/java/design-pattern/flyweight-pattern/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://maxwell.gitbook.io/way-to-architect/she-ji-mo-shi/chuang-jian-xing/xiang-yuan-mo-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
