Luckylau's Blog

设计模式之享元模式

​ 享元模式(Flyweight Pattern)以共享的方式支持大量的细粒度的对象。尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。从而减少创建对象的数量和内存占用量,提高性能。这种类型的设计模式属于结构型模式。

​ 首先了解两个概念:内部状态、外部状态。内部状态:在享元对象内部不随外界环境改变而改变的共享部分。外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。

​ 在我们的程序设计过程中,我们可能会需要大量的细粒度对象来表示对象,如果这些对象除了几个参数不同外其他部分都相同,这个时候我们就可以利用享元模式来大大减少应用程序当中的对象。如何利用享元模式呢?这里我们只需要将他们少部分的不同的部分当做参数移动到类实例的外部,然后在方法调用的时候将他们传递过来就可以了。这里也就说明了一点:内部状态存储于享元对象内部,而外部状态则应该由客户端来考虑。

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
/**
* 享元实体对象
* 一个学科可以包含多个学生(姓名,电话)
* 所以学科为内部不可变状态,而学生(姓名,电话)为外部可变状态
*
* @Author: ZRH
* @Date: 2021/2/3 15:51
*/
@Data
public class XiangYuanModel {
/**
* 学科 - 内部状态
*/
private String subject;
/**
* 姓名 - 外部状态
*/
private String name;
/**
* 电话 - 外部状态
*/
private String phone;
/**
* 构造含内部状态对象
*
* @param subject
*/
public XiangYuanModel(String subject) {
this.subject = subject;
}
}
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
/**
* 享元实体工厂类
*
* @Author: ZRH
* @Date: 2021/2/3 15:51
*/
@Slf4j
public class XiangYuanModelFactory {
/**
* 自定义对象池,保存共享对象
*/
private final static Map<String, XianYuanModel> POOL = Maps.newConcurrentMap();
/**
* 创建享元实体工厂方法
*
* @param name
* @param phone
* @param subject
* @return
*/
public static XianYuanModel getXianYuanModel(String name, String phone, String subject) {
if (POOL.containsKey(subject)) {
XianYuanModel model = POOL.get(subject);
model.setName(name);
model.setPhone(phone);
log.info("使用对象池获取对象:{}", model);
return model;
}
XianYuanModel model = new XianYuanModel(subject);
POOL.put(subject, model);
model.setName(name);
model.setPhone(phone);
log.info("new一个新对象:{}", model);
return model;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 享元模式测试实例
*
* @param args
*/
public static void main(String[] args) {
XianYuanModelFactory.getXianYuanModel("小明", "155555555551", "数学");
XianYuanModelFactory.getXianYuanModel("小王", "155555555552", "英语");
XianYuanModelFactory.getXianYuanModel("小华", "155555555553", "数学");
XianYuanModelFactory.getXianYuanModel("小李", "155555555554", "语文");
XianYuanModelFactory.getXianYuanModel("小天", "155555555555", "语文");
}
new一个新对象:XianYuanModel(subject=数学, name=小明, phone=155555555551)
new一个新对象:XianYuanModel(subject=英语, name=小王, phone=155555555552)
使用对象池获取对象:XianYuanModel(subject=数学, name=小华, phone=155555555553)
new一个新对象:XianYuanModel(subject=语文, name=小李, phone=155555555554)
使用对象池获取对象:XianYuanModel(subject=语文, name=小天, phone=155555555555)
Luckylau wechat
如果对您有价值,看官可以打赏的!