hooyantsing's Blog

P87 享元模式(2)-工作原理

字数统计: 1.1k阅读时长: 4 min
2020/11/11

尚硅谷Java设计模式(图解+框架源码剖析)

享元模式 Flyweight Pattern

  1. 也叫蝇量模式:运用共享技术有效地支持大量细粒度的对象
  2. 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
  3. 享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率
  4. 享元模式经典的应用场景就是池技术了,string常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式。

角色

hooy.xyz

  1. FlyWeight 是抽象的享元角色,他是产品的抽象类,同时定义出对象的外部状态内部状态的接口或实现。
  2. ConcreteFlyweight 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务。
  3. UnsharedConcreteFlyWeight 是不可共享的角色,一般不会出现在享元工厂。
  4. FlyWeightFactory 享元工厂类,用于构建一个池容器(集合),同时提供从池中获取对象的方法。

内部状态和外部状态

  1. 享元模式提出了两个要求:细粒度和共享对象。这里就涉及到内部状态和外部状态,即将对象的信息分为两个部分:内部状态外部状态
  2. 内部状态:指对象共享出来的信息,储存在享元对象内部且不会随环境的改变而改变
  3. 外部状态:指对象得以以来的一个标记,是随环境改变而改变的,不可共享的状态
  4. 举个例子。围棋理论上有361个空位可以放棋子,每盘棋都有可能有两三百个棋子对像产生,因为内存空间有限,一台服务器很难支持更多的玩家玩围棋游戏,如果用享元模式来处理棋子,那么棋子对象就可以减少到只有两个实例,这样就很好的解决了对象开销问题

案例 网站外包

抽象类

1
2
3
4
public abstract class WebSite {
// 抽象方法
public abstract void use(User user);
}

具体子类

[内部状态]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 具体的子类
public class ConcreteWebSite extends WebSite{
// [内部状态]
private String type = "";

public ConcreteWebSite(String type) {
this.type = type;
}

@Override
public void use(User user) {
System.out.println("网站的发布形式:" + type + " 正在使用的是:" + user.getName());
}
}

工厂类,提供具体子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 工厂类
public class WebSiteFactory {
// 集合,充当池的作用
private Map<String,WebSite> pool = new HashMap<>();

public WebSite getWebSiteCategory(String type){
if (!pool.containsKey(type)){
// 如果不存在,就存一个进去
pool.put(type,new ConcreteWebSite(type));
}
return pool.get(type);
}

// 获取池中对象数量
public int getWebSiteCount(){
return pool.size();
}
}

[外部状态]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// [外部状态]
public class User {
private String name;

public User(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

调用测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Client {
public static void main(String[] args) {
// 创建一个工厂
WebSiteFactory webSiteFactory = new WebSiteFactory();

// 客户要以新闻形式发布网站
WebSite webSite1 = webSiteFactory.getWebSiteCategory("新闻");
webSite1.use(new User("Hooy"));
// 客户要以博客形式发布网站
WebSite webSite2 = webSiteFactory.getWebSiteCategory("博客");
webSite2.use(new User("小明"));
// 客户要以博客形式发布网站
WebSite webSite3 = webSiteFactory.getWebSiteCategory("博客");
webSite3.use(new User("小红"));

System.out.println(webSiteFactory.getWebSiteCount());

}
}

执行结果:

1
2
3
4
网站的发布形式:新闻 正在使用的是:Hooy
网站的发布形式:博客 正在使用的是:小明
网站的发布形式:博客 正在使用的是:小红
2

可见到内部状态对象的个数为2,实际上被3个对象使用。共享了对象资源。

享元模式在Integer类中的应用

1
2
3
4
5
6
7
8
9
10
11
public class IntegerTest {
public static void main(String[] args) {
Integer x = Integer.valueOf(127);
Integer y = Integer.valueOf(127);
Integer z = new Integer(127);
Integer w = new Integer(127);
System.out.println(x == y); // true IntegerCache范围在[-128,127] 使用享元模式
System.out.println(x == z); // false
System.out.println(z == w); // false
}
}
CATALOG
  1. 1. 享元模式 Flyweight Pattern
  2. 2. 角色
  3. 3. 内部状态和外部状态
  4. 4. 案例 网站外包
  5. 5. 享元模式在Integer类中的应用