携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情
简介
享元模式的英文叫:Flyweight Design Pattern。即“轻量级”设计模式,顾名思义就是代码轻量级化。中文“享元”是指被共享的单元,此处的共享是指共享对象,达到节省资源的目的。
当软件模块创建了大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务调用,直接返回在内存中已有的对象使用,避免重新创建对象,造成资源浪费,也可以提高软件使用效率。
我们常见的String常量池、数据库连接池、线程池等等都是享元模式的应用,享元模式是池技术的重要实现方式。
当我们的系统中需要创建大量的对象,并且对象占用了相对大规模的内存,且这些对象中的部分属性是一样的值,而且后续不会再改变,是固定值,那么我们就可以将这些相同的属性用一个对象来表示,这样就节省了很多内存空间。我们将这些相同的属性共享出来,所有的相同类别的对象共享这个单元,这些属性我们称之为内部状态。
内部状态指对象共享出来的信息,存储在享元对象内部并且不会随环境的改变而改变。
外部状态指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。
案例
我们还是通过网络上开房间下象棋的经典案例来说明享元设计模式。一个象棋游戏平台肯定有很多的房间,每个房间都有一盘棋,每盘棋上有32颗棋子,就有32个对象,但是每个房间里的【将】的属性有很多都是相同的,比如名字、颜色等,而且它们在各个房间的棋盘中都是不会发生变化的,唯一不同的就是所在的位置不一样。所以相同的属性就可以抽出来作为共享单元。
话不多说,看例子:
享元类,即棋子公共的属性
public class ShareChessAttr {
private Integer id;
private String name;
private String color;
public ShareChessAttr(Integer id, String name, String color) {
this.id = id;
this.name = name;
this.color = color;
}
}
定义一个工厂去获取对应棋子的享元
public class ShareChessAttrFactory {
public static final HashMap<Integer, ShareChessAttr> shareChessAttrMap = new HashMap();
static {
shareChessAttrMap.put(1, new ShareChessAttr(1, "将", "红"));
shareChessAttrMap.put(2, new ShareChessAttr(2, "帅", "黑"));
shareChessAttrMap.put(3, new ShareChessAttr(3, "车", "红"));
shareChessAttrMap.put(4, new ShareChessAttr(4, "车", "黑"));
}
public static ShareChessAttr getShareChessAttr(Integer i) {
return shareChessAttrMap.get(i);
}
}
定义棋子
public class Chess {
private ShareChessAttr shareChessAttr;
private Integer positionX;
private Integer positionY;
public Chess(ShareChessAttr shareChessAttr, Integer positionX, Integer positionY) {
this.shareChessAttr = shareChessAttr;
this.positionX = positionX;
this.positionY = positionY;
}
}
定义棋盘
public class ChessBoard {
private HashMap<Integer, Chess> chessOnBoard = new HashMap<Integer, Chess>();
public ChessBoard() {
chessOnBoard.put(1, new Chess(ShareChessAttrFactory.getShareChessAttr(1), 5, 0));
chessOnBoard.put(2, new Chess(ShareChessAttrFactory.getShareChessAttr(2), 5, 0));
}
}
如此每个棋盘中的棋子的id,名字和颜色都指向了同一个shareChessAttr。实现享元。
总结
享元模式的思想与单例比较类似,但是单例模式强调的是全局唯一,而享元模式则强调的是内存共享。