一、是什么
是池化技术的重要实现,主要用于创建大量相似对象时,减少对象的创建,减少内存占用和资源的重复利用,提高性能。这些对象有些公共特征,如需要大量创建、生命周期短用完即弃、对象之间存在部分相同数据,这个时候就可以考虑使用享元模式。
举个例子,最近有本书火了,很多人都想看,于是就花钱买了(new对象),但看完学到知识后这本书就没用了,会被垫桌脚或丢弃(gc垃圾回收),这样就导致金钱和资源的浪费。如果图书馆有这本书,大家轮流去借这本书看,看完再还回去,这就提高了资源的重复利用,并且也不会造成金钱的消耗(new对象造成的性能消耗)。
二、模式定义
使用共享对象可有效地支持大量的细粒度的对象。
模式中的角色:
-
享元对象:相当于图书。分为内部状态和外部状态。内部状态是指大家都有的并且可以共享出去的属性,比如图书号,图书名字。外部状态是指随着环境变化而变化并且不能共享的状态,比如当前借书人的信息。
-
享元工厂:相当于图书馆。工厂中维护着一个享元池,享元池中保存着拥有相同内部状态的享元对象。
三、类图
四、代码实现
Book
:享元对象的公共抽象,包含享元对象可共享的内部状态。borrow方法表示借走图书,back方法表示借还图书。
public abstract class Book {
public int bookId;
// 1表示已借走,0表示可借
public int status;
public abstract void borrow(String readerName);
public abstract void back();
}
SpringStudyBook
:具体的享元对象,定义了不可共享的外部状态。
public class SpringStudyBook extends Book{
// 外部状态,借书人名字
private String readerName;
public SpringStudyBook (int bookId) {
this.bookId = bookId;
this.status = 0;
}
@Override
public void borrow(String readerName) {
this.readerName = readerName;
this.status = 1;
System.out.println(readerName + "借走了书号为 " + bookId + " 的书");
}
@Override
public void back() {
this.status = 0;
}
}
Library
:享元工厂,维护着books享元池。
public class Library {
// 享元池
private CopyOnWriteArrayList<Book> books = new CopyOnWriteArrayList();
public Library() {
for (int i = 1; i < 3; i++) {
books.add(new SpringStudyBook(i));
}
}
// 获取图书
public Book getBook() {
Book rsBook = null;
// 遍历找寻可借的图书
for (Book book : books) {
if (book.status == 0) {
rsBook = book;
break;
}
}
return rsBook;
}
}
五、实际应用
- 线程池
- Integer缓存池[-128,127]
…
六、优缺点
享元模式可以大大减少对象的创建,降低程序内存的占用,但也提高了复杂性,需要剥离出外部状态和内部状态。