08. 23种经典设计模式-22-享元模式
程序员文章站
2022-06-04 23:17:13
...
1. 享元模式
Use sharing to support large numbers of fine-grained objects efficiently. (使用共享对象可有效地支持大量的细粒度的对象)
1.1 享元模式核心思想
- 利用jvm缓存,解决应用中大量重复对象的内存浪费问题
- 享元标准模式并不是太好设计,享元思想很好实现
1.2 享元模式类图
- Flyweight: 抽象享元角色, 负责定义内部状态和外部状态
- 内部状态: 不会因环境和场景而变化的状态
- 外部状态: 会根据环境和场景变化的状态
- ConcreteFlyweight: 具体享元角色, 可共享的对象
- unSharedConcreteFlyweight: 不可共享的享元角色, 非必须. 享元模式不要求对象必须支持共享
- FlyweightFactory: 享元工厂, 实现缓存逻辑
[外链图片转存失败(img-Lk0mMbQJ-1566894907377)(https://raw.githubusercontent.com/zongf0504/blog-images/master/images/design-parttern/ldp-flyweight-01.png)]
1.3 享元模式优缺点
- 优点: 节省jvm 内存
- 缺点: 内部状态外部状态不容易区分,比较难以按照标准模式进行设计
1.4 享元模式适用场景
- 系统中存在大量的相似对象
- 对象缓存池的设计
- 广泛用于池技术,如数据库连接池, 字符串常量池等
2. 享元模式用例
对于享元模式, 笔者查阅了很多资料, 也没有发现很好的应用案例. 笔者认为, 了解享元模式核心思想是为了解决大量重复对象对jvm内存的浪费即可.
我们来举一个围棋的例子,一个棋盘上每个坐标上都有黑子或白子,区别在于坐标. 如果程序中为每个位置都创建一个棋子对象,那么显然时内存浪费.
2.1 类图
- 只实现共享角色, 不实现非共享角色.
- 内部状态: 颜色
- 外部状态: 棋盘, 坐标
[外链图片转存失败(img-qF78VNlD-1566894907378)(https://raw.githubusercontent.com/zongf0504/blog-images/master/images/design-parttern/ldp-flyweight-02.png)]
2.2 抽象享元角色-
public abstract class AbsGoPiece {
// 抽象落子方法, 传入落子坐标: 哪个棋盘的哪行哪列
public abstract void put(GoPiece[][] goBoard, int x, int y);
}
2.3 具体享元角色-GoPiece
public class GoPiece extends AbsGoPiece {
private String color;
public GoPiece(String color) {
this.color = color;
}
public String getColor() {
return color;
}
@Override
public void put(GoPiece[][] goBoard, int x, int y) {
goBoard[x][y] = this;
}
}
2.4 享元工厂类
享元模式解决的是节省jvm内存,因此缓存要使用Map对象.
public class GoPieceFactory {
private static HashMap<String, GoPiece> cacheMap = new HashMap<>();
public static GoPiece getGoPiece(String color) {
if (cacheMap.containsKey(color)) {
return cacheMap.get(color);
}else {
GoPiece goPieceFW = new GoPiece(color);
cacheMap.put(color, goPieceFW);
return goPieceFW;
}
}
}
2.5 测试
public class TestFlyweight {
@Test
public void test(){
// 创建棋盘对象
GoPiece[][] goBoard = new GoPiece[3][3];
for (int i = 0; i < 3; i++) {
GoPiece blackPiece = GoPieceFactory.getGoPiece("黑色");
blackPiece.put(goBoard, 0,i);
}
for (int i = 0; i < 3; i++) {
GoPiece whitePiece = GoPieceFactory.getGoPiece("白色");
whitePiece.put(goBoard, 1, i);
}
for (int i = 0; i < 3; i++) {
GoPiece blackPiece = GoPieceFactory.getGoPiece("黑色");
blackPiece.put(goBoard, 2,i);
}
printGoBoard(goBoard);
}
private void printGoBoard(GoPiece[][] goBoard) {
for (int i = 0; i < goBoard.length; i++) {
for (int j = 0; j < goBoard[i].length; j++) {
GoPiece goPieceFWS = goBoard[i][j];
if (goPieceFWS != null) {
System.out.print(goPieceFWS.getColor() + "@" + goPieceFWS.hashCode() + " ,");
}else {
System.out.print(" ,");
}
}
System.out.println();
}
}
}
2.6 测试输出
从测试结果中发现, 对象只有两个
黑色@233530418 ,黑色@233530418 ,黑色@233530418 ,
白色@683287027 ,白色@683287027 ,白色@683287027 ,
黑色@233530418 ,黑色@233530418 ,黑色@233530418 ,
上一篇: python基础-----六种数据类型
下一篇: 闹钟爆笑笑话