什么是享元模式?

运用共享技术有效地支持大量细粒度的对象。重用现有的同类对象,如果未找到匹配的对象,则创建新对象。主要用于减少创建对象的数量,以减少内存占用和提高性能。

适用场景

大量对象耗费大量内存,复用相似对象节省内存

代码实现

示例:围棋,围棋的棋子可以简化为两个对象,黑棋和白棋,不同的是棋子的坐标。

  1. /**
  2. * 棋子
  3. */
  4. class Piece {
  5. protected Color color;//颜色
  6. protected int x;//x坐标
  7. protected int y;//y坐标
  8. public Piece(Color color, int x, int y) {
  9. this.color = color;
  10. this.x = x;
  11. this.y = y;
  12. }
  13. @Override
  14. public String toString() {
  15. return "棋子:" + color + ",横坐标:" + x + ",纵坐标:" + y;
  16. }
  17. }
  18. /**
  19. * 枚举 棋子类型
  20. */
  21. enum Color {
  22. Black,
  23. White;
  24. }
  25. /**
  26. * 棋子工厂类,实现对象共享
  27. */
  28. class PieceFactory {
  29. private static final Map<Color, Piece> map = new ConcurrentHashMap<>();
  30. public synchronized static Piece getPiece(@NotNull Color color, int x, int y) {
  31. Piece piece = map.get(color);
  32. if (null == piece) {
  33. piece = new Piece(color, x, y);
  34. map.put(color, piece);
  35. }
  36. System.out.println("内存占用:" + map.size());
  37. return piece;
  38. }
  39. }
  40. /**
  41. * 组合模式测试
  42. */
  43. public class FlyweightPattern {
  44. public static void main(String[] args) {
  45. //模拟棋盘 100*100
  46. final int width = 100;
  47. final int high = 100;
  48. //随机获取一百个棋子
  49. final int count = 100;
  50. //两个线程 模拟两个人对弈
  51. //对弈者1
  52. new Thread(() -> {
  53. Random random = new Random();
  54. for (int i = 0; i < count; i++) {
  55. int x = random.nextInt(width);
  56. int y = random.nextInt(high);
  57. Piece piece = null;
  58. //利用奇数偶数模拟黑白棋子
  59. if (i % 2 != 0) {//奇数 白棋
  60. piece = PieceFactory.getPiece(Color.White, x, y);
  61. } else {
  62. piece = PieceFactory.getPiece(Color.Black, x, y);
  63. }
  64. System.out.println(piece);
  65. }
  66. }).start();
  67. //对弈者2
  68. new Thread(() -> {
  69. Random random = new Random();
  70. for (int i = 0; i < count; i++) {
  71. int x = random.nextInt(width);
  72. int y = random.nextInt(high);
  73. Piece piece = null;
  74. //利用奇数偶数模拟黑白棋子
  75. if (i % 2 != 0) {//奇数 白棋
  76. piece = PieceFactory.getPiece(Color.White, x, y);
  77. } else {
  78. piece = PieceFactory.getPiece(Color.Black, x, y);
  79. }
  80. System.out.println(piece);
  81. }
  82. }).start();
  83. //输出:
  84. //内存占用:1
  85. //内存占用:1
  86. //棋子:Black,横坐标:43,纵坐标:52
  87. //棋子:Black,横坐标:43,纵坐标:52
  88. //内存占用:2
  89. //棋子:White,横坐标:88,纵坐标:68
  90. //内存占用:2
  91. //棋子:White,横坐标:88,纵坐标:68
  92. //内存占用:2
  93. //棋子:Black,横坐标:43,纵坐标:52
  94. //内存占用:2
  95. //棋子:Black,横坐标:43,纵坐标:52
  96. //内存占用:2
  97. //棋子:White,横坐标:88,纵坐标:68
  98. //内存占用:2
  99. //棋子:White,横坐标:88,纵坐标:68
  100. //内存占用:2
  101. //棋子:Black,横坐标:43,纵坐标:52
  102. //内存占用:2
  103. //棋子:Black,横坐标:43,纵坐标:52
  104. //内存占用:2
  105. //棋子:White,横坐标:88,纵坐标:68
  106. //内存占用:2
  107. //棋子:White,横坐标:88,纵坐标:68
  108. //内存占用:2
  109. //棋子:Black,横坐标:43,纵坐标:52
  110. //内存占用:2
  111. //棋子:Black,横坐标:43,纵坐标:52
  112. //.....
  113. }
  114. }