设计模式之享元模式
一、享元模式是什么?
享元模式是通过共享使用已存在的对象来减少对象的创建,从而减少内存的占用来提高性能。一般一些比较占用内存的大量对象,而且这些对象跟系统之间的耦合性很小的时候可以考虑使用享元模式。例如:生活中常见的共享单车,单车跟我们没有任何关系,但是我们谁都可以使用,不需要去买;代码中我们经常使用的数据库连接池。
使用享元模式需要注意的地方是享元模式需要一个缓存池(HashMap)来存放共享的对象,而且共享的对象需要一个识别码(单车的二维码,HashMap的Key)供我们找到这个对象。
二、享元模式详解
1.享元模式组成
享元模式的主要角色有如下:
- 抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
- 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
- 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
- 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色,需要有个Map存放享元对象。
享元模式需要注意的是需要区分对象的属性,某些是否需要共享,不需要共享的部分外部化,否则可能会引起线程安全问题
2.示例demo
用画圆来举个例子,假设我们把圆的颜色作为共享,而半径不共享(为了说明共享和不共享把颜色和半径分开了,举的例子不太恰当就这样看吧)。那么圆是具体共享角色,半径就是非共享角色。
抽象共享角色:
public interface Shape {
/**
* 画图形
* @param radius
*/
void draw(Radius radius);
}
具体共享角色:
@Data
public class Circle implements Shape{
/**
* 颜色,假设我们需要相同颜色圆
*/
private String color;
public Circle(String color) {
this.color = color;
}
@Override
public void draw(Radius radius) {
/**
* 画一个半径为X的圆,因为半径是不共享的所以作为参数传递了
*/
}
}
非共享角色:
@Data
public class Radius {
/**
* 假设这是用来装的非享元属性
*/
private int radius;
public Radius(int radius) {
this.radius = radius;
}
}
享元工厂:
public class CircleFactory {
/**
* 用来装享元角色的
*/
private static final HashMap<String,Circle> cache = new HashMap();
/**
* 获取享元角色的,此处的操作就类似于平常使用缓存的操作。
* @param color
* @return
*/
public static Shape getCircle(String color) {
Circle circle = cache.get(color);
if(circle == null) { //如果不存在先创建再放到缓存中
circle = new Circle(color);
cache.put(color, circle);
}
return circle;
}
}
客户端使用(最终打印结果为true):
public static void main(String[] args) {
//获取半径为10红色的圆,此时没有创建
Shape redCircle1 = CircleFactory.getCircle("red");
redCircle1.draw(new Radius(10));
//获取半径为20红色的圆,此时其实是共享的红色圆
Shape redCircle2 = CircleFactory.getCircle("red");
redCircle2.draw(new Radius(20));
System.out.println(redCircle1 == redCircle2);
}
总结
优点:
- 减少了对象的创建,降低了内存的使用,有利于提高系统效率。
缺点:
- 一些不共享的部分需要外部化,增加了系统的复杂度