享元模式

1 概念

1. 定义

“享”就表示共享,“元”表示对象。如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝,而不必为每一次使用都创建新的对象。目的是减少对象创建,减少内存占用,提高系统性能。

类型:结构型

比如:去图书馆借书,如果书架上有这本书直接拿走,到借阅机上借阅就好了,如果没有,可以到图书管理处去拿一本新书。对于整个图书馆来说,书其实就是共享的。对于我们借书的流程和图书共享的方式就是享元模式。

2 应用场景

  • 系统底层开发。比如Java的string类型,如果有则返回,没有则创建一个,保存在字符串缓存池里;数据库连接池。

3 优缺点

优点:

  • 减少对象创建,减少内存占用,提高系统性能。

缺点:

  • 关注内外部状态,关注线程安全问题。一般我们都用的HashMap,线程安全可以使用hashTable,提升效率可以concurentHashMap

  • 提高了系统的复杂度

4 主要角色

  • 抽象享元(Book):定义需要共享的对象业务接口。享元类被创建出来总是为了实现某些特定的业务逻辑.
  • 具体享元(ConcreteBook):实现抽象享元类的接口,完成某一具体逻辑。在这里表示可以被借出。
  • 享元工厂(Llibrary):用于创建具体享元类,维护相同的享元对象。当请求对象已经存在时,直接返回对象,不存在时,在创建对象。在例子中的解释就是图书馆,保存了所有的书,当学生借书时,有就拿走,没有买一本新书。这里面其实是使用了单例模式的

享元工厂是享元模式的核心,它需要确保系统可以共享相同的对象。它会维护一个对象列表,当我们想要获取享元类时,如果请求的享元类已经被创建,则直接返回已有的享元类:若没有,则创建一个新的享元对象,并将它加入到维护队列中。

2 代码实现

场景:去图书馆借书,如果书架上有这本书直接拿走,到借阅机上借阅就好了,如果没有,可以到图书管理处去拿一本新书。

1
2
3
public interface Book {
public void borrow();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ConcreteBook implements Book {
//被借出的书名,外部状态,不可以共享的状态,传入的书名不同,书不同
private String name;

// 内部状态,这些书都属于新华书店,可共享的状态
private String librarySign = "新华书店";

public ConcreteBook(String name) {
this.name = name;
}
@Override
public void borrow() {
System.out.println("图书馆借出一本书,书名为:" + this.name );
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 相当于bookFactory
public class Library {
private static final Map<String, Book> BOOK_MAP = new HashMap<String, Book>();

//图书馆外借图书
public static Book borrowBook(String bookName){
//如果书架有,直接借出
Book book = BOOK_MAP.get(bookName);
//如果书架没有,那就调进来一本新书
if(book == null){
book = new ConcreteBook(bookName);
BOOK_MAP.put(bookName, book);
}
return book;
}

//图书馆书架上的书的数量
public static int getAllBookSize(){
return BOOK_MAP.size();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

public class Test {
private static final String[] bookNames = {"白雪公主","一千零一夜","火烈鸟","海蒂"};
public static final int BOOK_SIZE = 10;

public static void main(String[] args) {
for (int i = 0; i < BOOK_SIZE; i++) {
int randomIndex = new Random().nextInt(bookNames.length);
String bookName = bookNames[randomIndex];
Book book = Library.borrowBook(bookName);
book.borrow();
}
//输出一些学生一共借多少本书
System.out.println("学生一共借了 " + BOOK_SIZE + " 本书! ");
//输出一下图书馆一共借出多少本书
System.out.println("图书馆实际借出" + Library.getAllBookSize() + " 本书");
}
}

输出:

图书馆借出一本书,书名为:海蒂
图书馆借出一本书,书名为:火烈鸟
图书馆借出一本书,书名为:一千零一夜
图书馆借出一本书,书名为:火烈鸟
图书馆借出一本书,书名为:火烈鸟
图书馆借出一本书,书名为:白雪公主
图书馆借出一本书,书名为:白雪公主
图书馆借出一本书,书名为:海蒂
图书馆借出一本书,书名为:海蒂
图书馆借出一本书,书名为:一千零一夜
学生一共借了 10 本书!
图书馆实际借出4 本书


享元模式
http://example.com/享元模式/
作者
Panyurou
发布于
2023年10月4日
许可协议