1、享元模式的概念
享元模式,英文Flyweight Pattern,属于结构型模式。主要用来减少创建对象的数量,进而减少内存占用来提高系统性能。我们都知道,创建出来的对象基本都会存放在JVM的堆中,堆中存在着大量的对象,也是GC回收的主要区域,内存中对象过多会影响系统性能,而享元模式的根本目的就是减少对象的创建,在一定程度上可以提高系统的性能。
享元模式尝试重用现有的同类对象,如果没有的话,再创建,如果已经存在着这样的对象,直接用而不是创建。
2、享元模式的特点
- 重用现有的同类对象,没有再创建,尽量减少创建对象,从而减少内存开销,提高系统的性能。
3、关于享元模式
- 使用目的:共享已有的同类对象,减少对象创建,减小系统开销,提高系统性能。
- 解决问题:当需要创建大量的对象时,很可能内存会溢出,这时候可以将类型相同的对象抽象出来,然后在业务需要该类型对象的时候,直接返回内存中已存在的该类型对象,而不用频繁的创建。
- 使用时机:
- 当系统中有大量对象并且会占用大量内存的时候。
- 对象的状态可以外部化。
- 系统并不依赖对象的身份。
- 保证享元:用代表唯一的标识码来标识对象,当内存中有的话,直接返回这个标识码对应的对象,而不用重新创建。
- 享元关键:这些共享对象用HashMap来进行存储。
4、享元模式的优缺点
优点:
- 减少大量对象的创建,减少了系统开销,从而提高了系统的性能。
缺点:
- 一定程度上提高了系统的复杂度,需要分离外部状态和内部状态。
5、享元模式的使用场景
- 系统中存在着大量的相似对象。
- 需要用到缓冲池时。
注意: 需要严格划分外部状态和内部状态,否则可能会引起线程安全问题。 其次,这些类必须有一个工厂对象加以控制。
6、享元模式的实现
(1)创建Shape接口和实现类
public interface Shape {
void draw();
}
/*
* 接口的实现类
*/
public class Circle implements Shape {
private int x;
private int y;
private String color;
private int radius;
// 构造方法
public Circle(String color) {
this.color = color;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("以坐标(" + this.x + "," + this.y + ")为圆心,以"
+ this.radius + "为半径画圆,圆内填充" + this.color);
}
}
(2)创建工厂类
需要创建一个工厂类,用来管理对象的生成和返回,如下:
public class ShapeFactory {
private static final HashMap<String, Circle> circleMap = new HashMap<>();
// 定义一个方法,用于返回Shape对象
public static Shape getCircle(String color) {
// 先从Map中查找
Circle circle = circleMap.get(color);
// 找不到的话,再创建
if (circle == null) {
circle = new Circle(color);
// 存进map里
circleMap.put(color, circle);
System.out.println("创建一个" + color + "的圆!");
}
return circle;
}
}
(3)测试
public class Test {
// 定义一个全局Random类型对象
private static Random random = new Random();
// 定义一个数组
private static final String[] colors = {"红色", "绿色", "黄色", "灰色" };
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
// 获取随机颜色
String randomColor = getColor();
Circle circle = (Circle) ShapeFactory.getCircle(randomColor);
circle.setX(getXRandom());
circle.setY(getYRandom());
circle.setRadius(10);
circle.draw();
}
}
// 定义一个方法,随机返回一个50以内的int型X坐标
private static int getXRandom() {
return random.nextInt(51);
}
// 随机返回Y坐标
private static int getYRandom() {
return random.nextInt(51);
}
// 随机返回一个数组中的颜色
private static String getColor() {
// 数组转成List
List<String> colors2 = Arrays.asList(colors);
// 随机返回一个集合长度以内的整数
int res = random.nextInt(colors2.size());
return colors2.get(res);
}
}
可以看到,类似的对象,确实只创建了一次,后来需要的时候,是直接从内存中取到的,而不是再重新创建。
7、小结
享元模式的目的在于减少相似对象的重复创建,从而减少系统开销来提高系统性能,当系统中存在大量的类似对象时,可以考虑采用享元模式。