享元模式是一种结构型设计模式,在实际开发中用的比较少,它主要用于重复利用对象来减少内存占用,当某种场景下,我们需要大量相似的对象,如果我们每次都新创建对象,那内存消耗将非常大,如果能够考虑重复使用某些对象,那么就能大大减少内存使用。
下面以一个示例来说明享元模式的用法,现在有一个Circle类用于绘制圆形,假设其中Circle的color属性是不可变的,通过构造方法传入,而radius属性可以通过setRadius进行修改。
1public enum Color {
2 Red, Yellow, Blue, Green
3}
4
5public class Circle {
6 private final Color color;
7 private int radius;
8
9 public Circle(Color color) {
10 this.color = color;
11 }
12
13 public void setRadius(int radius) {
14 this.radius = radius;
15 }
16
17 public void draw() {
18 System.out.println("draw circle(color=" + color + ", radius=" + radius + ")");
19 }
20}
现在需求是让我们绘制10万个随机颜色和大小的圆形,最简单的实现是这样的。
for (int i = 0; i < 10e5; i++) {
Circle circle = new Circle(randomColor());
circle.setRadius(random());
circle.draw();
}
很明显这样会创建10万个Circle对象,而且这些对象很相似,它们只有color和radius属性不同,color属性是通过构造参数传入且不可修改,而radius属性可以通过setRadius修改,那么可以将带有不同color属性的Cricle对象缓存下来。
下面创建一个用于缓存和创建Circle的工厂类CircleFactory,它的作用是根据color来获取和缓存Color对象。
1public class CircleFactory {
2 private static final HashMap<Color, Circle> cache = new HashMap<>();
3
4 public static Circle getCircle(Color color) {
5 Circle circle = cache.get(color);
6 if (circle == null) {
7 circle = new Circle(color);
8 cache.put(color, circle);
9 }
10 return circle;
11 }
12}
在遍历绘制图形时,将创建Circle对象改为通过CircleFactory获取。
for (int i = 0; i < 10e5; i++) {
Circle circle = CircleFactory.getCircle(randomColor());
circle.setRadius(random());
circle.draw();
}
享元模式的主要目的就是减少内存的使用,但是同时它也增加了一些额外代码,当我们使用从工厂类获取的缓存对象时,通常还需要将对象的属性数据重置,而且缓存本身也需要消耗一定的资源,所以在有大量重复相似对象的情况才适合使用享元模式。