目录
1. 享元模式
1.1 定义、优缺点
- 1. 享元模式
- 1.1 定义、优缺点
- 1.2 模式的结构与实现
定义:通过共享已经存在的对象来大幅度减少创建的对象数量,提高系统资源的利用率。比如数据库连接池,可以对一个数据库连接进行重复使用
系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源。 大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态。 由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式
优点:相同对象只要保存一份,降低了系统中对象的数量
缺点:
- 为了使对象可以共享,需要将一些不能共享的状态外部化(例如骑共享单车的每个人),这将增加程序的复杂性
- 读取享元模式的外部状态会使得运行时间稍微变长
适用场景:
- 系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源
- 大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态
- 由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式
如果要创建的对象很相似,需要将不同的部分(非享元角色Unsharable Flyweight)抽离出来。通过函数进行不同部分的设置。比如数据库连接的使用状态
结构:
- 抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入
- 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口
- 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中
- 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象
实现:
import java.util.HashMap;
public class FlyweightTest {
public static void main(String[] args) {
ConnectPool connectPool = new ConnectPool();
// 从数据库连接池获取数据库连接01,进行第一次使用再释放
Connect connect01FirstUse = connectPool.getConnect("01");
connect01FirstUse.setStatus(new Status("正在使用"));
connect01FirstUse.setStatus(new Status("未使用"));
// 从数据库连接池获取数据库连接01,进行第二次使用再释放
Connect connect01SecondUse = connectPool.getConnect("01");
connect01SecondUse.setStatus(new Status("正在使用"));
connect01SecondUse.setStatus(new Status("未使用"));
}
}
// 抽象享元角色:抽象的数据库连接接口
interface Connect {
// 设置数据库连接状态
void setStatus(Status status);
}
// 具体享元角色:具体的数据连接类
class ConcreteConnect implements Connect {
// 数据库连接唯一ID
private String id;
// 新创建的数据库连接默认是未使用状态
private Status status = new Status("未使用");
public ConcreteConnect(String id) {
this.id = id;
}
public void setStatus(Status status) {
this.status = status;
System.out.printf("数据库连接%s的状态为%s\n", this.id, this.status.getStatusName());
}
}
// 享元工厂角色:从数据库连接池中获取数据库连接
class ConnectPool {
// 用于储存创建的数据库连接,key-数据库连接ID,value-创建的数据库连接
private HashMap connects = new HashMap();
// 从数据库连接池获取数据库连接
public Connect getConnect(String id) {
Connect connect = connects.get(id);
// 如果数据库连接池没有该数据库连接,则进行创建再返回
if (connect == null) {
connect = new ConcreteConnect(id);
connects.put(id, connect);
}
return connect;
}
}
// 非享元角色: 数据库连接状态
class Status {
private String statusName;
public Status(String statusName) {
this.statusName = statusName;
}
public String getStatusName() {
return this.statusName;
}
}
运行程序,结果如下:
数据库连接01的状态为正在使用
数据库连接01的状态为未使用
数据库连接01的状态为正在使用
数据库连接01的状态为未使用