文章内容
一、什么是享元模式
享元模式,运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来最大程度减少需要创建的对象数量,避免大量相似对象的开销,从而提高系统资源的利用率。
享元模式,也叫作蝇量模式,属于结构型设计模式。
二、享元模式类图

三、享元模式角色
- 抽象享元角色(FlyWeight): 要求是一个抽象类或接口,声明抽象方法,这些方法需要具体享元类来实现,并向外界提供享元对象的内部状态数据及外部状态数据。
- 具体享元角色(ConcreteFlyWeight): 它继承或实现了抽象享元类,称为享元对象,需要通过享元工厂类来提供唯一的享元对象。
- 非享元角色(UnshareConcreteFlyWeight): 不能被共享的子类可设计为非共享具体享元类,它代表了享元对象的外部状态。非享元对象可以直接作为享元对象方法的参数进行传递。
- 享元工厂角色(FlyWeightFactory): 负责创建和管理享元对象,客户端直接通过享元工厂对象来获取所需要的享元对象。
四、享元模式两种状态
- 内部状态:不会随环境改变而改变的可共享部分。比如围棋的颜色就两种(白棋、黑棋)。
- 外部状态:随环境改变而改变的不可以共享的部分。比如围棋的位置(也就是坐标)。
五、享元模式优缺点
1、优点
- 极大减少内存中共享对象的数量,节约内存资源,提高系统性能。
- 享元模式中外部状态相对独立,且不影响内部状态。
2、缺点
- 需要将享元对象的状态,分离为内部状态和外部状态,程序逻辑变得复杂了。
六、享元模式demo示例
1、Demo需求
以围棋为例,通过享元模式来实现,其中把白棋、黑棋作为具体享元类,白色、黑色是内部状态,围棋的坐标位置是外部状态。
2、数据类定义
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | /** * @Description: 非享元角色类(外部状态,棋子坐标) **/ public class GoChessPoint { // x 坐标 private double x; // y 坐标 private double y; public GoChessPoint( double x, double y) { this .x = x; this .y = y; } @Override public String toString() { return "棋子坐标{" + "x=" + x + ", y=" + y + '}' ; } } |
3、抽象类定义
1 2 3 4 5 6 7 | /** * @Description: 抽象享元角色:围棋类 **/ public abstract class AbstractGoChess { public abstract void show(GoChessPoint point); } |
4、具体化对象类
1 2 3 4 5 6 7 8 9 | /** * @Description: 具体享元角色类:白棋 **/ public class WhiteGoChess extends AbstractGoChess { @Override public void show(GoChessPoint point) { System.out.println( "白棋, " + point); } } |
1 2 3 4 5 6 7 8 9 | /** * @Description: 具体享元角色类:黑棋 **/ public class BlackGoChess extends AbstractGoChess { @Override public void show(GoChessPoint point) { System.out.println( "黑棋, " + point); } } |
5、工厂类定义
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** * @Description: 享元工厂角色:围棋工厂类 **/ public class GoChessFactory { // 饿汉式模式实例化单例对象 private static GoChessFactory goc = new GoChessFactory(); // 存放白棋/黑棋对象 private Map<String, AbstractGoChess> goChessMap = new HashMap<>(); // 私有化默认构造方法 private GoChessFactory() { goChessMap.put( "白棋" , new WhiteGoChess()); goChessMap.put( "黑棋" , new BlackGoChess()); } // 获取单例对象 public static GoChessFactory GetInstance() { return goc; } /** * 获取棋子对象 * * @param name * @return */ public AbstractGoChess getGoChess(String name) { return goChessMap.get(name); } } |
6、测试
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /** * @Description: 享元模式客户端:围棋客户端测试类 **/ public class GoClient { public static void main(String[] args) { // 获取白棋对象 AbstractGoChess white1 = GoChessFactory.GetInstance().getGoChess( "白棋" ); AbstractGoChess white2 = GoChessFactory.GetInstance().getGoChess( "白棋" ); // 获取黑棋对象 AbstractGoChess black1 = GoChessFactory.GetInstance().getGoChess( "黑棋" ); AbstractGoChess black2 = GoChessFactory.GetInstance().getGoChess( "黑棋" ); // 展示白棋1 white1.show( new GoChessPoint( 11.5 , 20.8 )); // 展示白棋2 white2.show( new GoChessPoint( 11.5 , 20.8 )); System.out.println( "white1==white2: " + (white1 == white2)); System.out.println( "===============================" ); // 展示黑棋1 black1.show( new GoChessPoint( 21.5 , 26.7 )); // 展示黑棋2 black2.show( new GoChessPoint( 16.1 , 28.3 )); System.out.println( "black1==black2: " + (black1 == black2)); } } |
1 2 3 4 5 6 7 | 白棋, 棋子坐标{x=11.5, y=20.8} 白棋, 棋子坐标{x=11.5, y=20.8} white1==white2: true =============================== 黑棋, 棋子坐标{x=21.5, y=26.7} 黑棋, 棋子坐标{x=16.1, y=28.3} black1==black2: true |