「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
1.享元模式的简介
享元(Flyweight)模式:“享”即使共享的意思,“元”即表示对象,所以从字面意思我们可以理解为共享对象的意思。它主要通过共享技术,尝试共享大量细粒度的对象,减少大量相同对象的创建。减少大量相同对象的内存占用,提高系统资源利用率,能一定程度上避免内存溢出。
它的主要应用在池上,如缓存池,String常量池,线程池等,当池中有我们需要的对象,我们可以直接拿出来使用,避免重复创建,降低系统开销。当池中没有的时候,我们可以自己创建一个放入池中,共享给别的程序使用。
-
前面我们说了一个细粒度对象,那么何为细粒度。
把一个对象分的更细,这里指分出它的内部状态和外部状态,这里引申出来两个概念,内部状态和外部状态
-
内部状态:一个对象固有的,不会随外部状态改变的信息,可以共享的,比如一个人的两个眼睛,一个鼻子这些是无法改变的,可以称之为内部状态。
-
外部状态:及一个对象会随外部状态改变的信息,不可共享。如人的工作公司,收入等。
-
2.享元模式结构图
- 抽象享元角色(Flyweight):是所有的具体享元类的基类,它负责定义享元角色的外部状态的接口和内部状态。
- 具体享元角色(Concrete Flyweight):实现抽象享元角色中所定义的相关接口。
- 非享元角色(Unsharable Flyweight):即享元角色不可以共享的外部状态,它可以以参数的形式注入具体享元对应的方法中。
- 享元工厂角色(Flyweight Factory):负责创建和管理享元角色。当客户端想要获取一个享元对象时,他会先检査工厂中是否存在符合要求的享元对象,如果存在则直接提供;如果不存在的话,则创建一个新的。
3.代码举例
- 抽象享元角色
public abstract class Flyweight {
public abstract void use(OutRole outRole);//抽象方法
}
- 具体享元角色
//具体享元角色
public class ConcreteFlyweight extends Flyweight {
//共享的部分,内部状态
private String type = "";
//构造器
public ConcreteFlyweight(String type) {
this.type = type;
}
@Override
public void use(OutRole outRole) {
// TODO Auto-generated method stub
System.out.println("类型为:" + type + " 使用的外部角色是" + outRole.getName());
}
}
3.外部状态(这里也可以做成抽象的)
public class OutRole {
private String name;
public OutRole(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 享元工厂
// 享元工厂类,根据需要返回一个享元
public class FlyweightFactory {
//集合, 充当池的作用,保存已创建的享元类
private HashMap<String, ConcreteFlyweight> pool = new HashMap<>();
//根据类型,返回一个享元类, 如果没有就创建一个享元类,并放入到池中,并返回
public Flyweight getFlyweightCategory(String type) {
if(!pool.containsKey(type)) {
//就创建一个网站,并放入到池中
pool.put(type, new ConcreteFlyweight(type));
}
return (Flyweight)pool.get(type);
}
//获取享元类的总数 (池中有多少个享元类)
public int getWebSiteCount() {
return pool.size();
}
}
- 客户端
public static void main(String[] args) {
// TODO Auto-generated method stub
// 创建一个工厂类
FlyweightFactory factory = new FlyweightFactory();
// 客户要一个以新闻形式发布的网站
Flyweight flyweight = factory.getFlyweightCategory("测试1");
flyweight.use(new OutRole("outRole1"));
// 客户要一个以博客形式发布的网站
Flyweight flyweight1 = factory.getFlyweightCategory("测试2");
flyweight1.use(new OutRole("outRole2"));
System.out.println("网站的分类共=" + factory.getWebSiteCount());
}
4. 应用案列
java中的,int常量池(-128 - 127),string常量池,线程池,数据库连接池,还有一些缓存,都是基于享元模式的应用案例。 这里我就不一一举例,大家可以自己去看看。