设计模式之享元模式

75 阅读2分钟

一、概述

  • 享元模式(Flyweight Pattern): 也叫蝇亮模式,运用共享技术有效地支持大量细粒度的对象
  • 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象。在这些连接对象中有我们需要的则可以直接拿来用,避免重复创建。
  • 享元模式能够解决重复对象的内存浪费问题,当系统中有大量相似对象,需要缓冲池时,不需要总是创建新的对象,可以从缓冲池中拿。这样可以降低系统内存,同时提高效率。
  • 经典应用场景:池技术。String常量池、数据库连接池、缓冲池等等都是享元模式的应用。享元模式是池技术的重要实现方式
  • 内部状态和外部状态
    • 内部状态指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变
    • 外部状态指对象得以依赖的一个标记,是随环境变化而变化的,不可共享的状态

二、享元模式在象棋中的使用

  • 在一个游戏大厅中,有多个房间在玩象棋,每个房间的象棋布局都不一样,但是棋子的样式都一样。因此,象棋的样式就是内部状态,位置布局就是外部状态。所有游戏大厅可以共享一副棋,只是每个房间的棋子位置布局不一样。
  • 单个棋子样式,所有房间共享一个
// 单个棋子的样式
public class ChessPieceUnit {
  private int id;
  private String text;
  private Color color;

  public ChessPieceUnit(int id, String text, Color color) {
    this.id = id;
    this.text = text;
    this.color = color;
  }

  public static enum Color {
    RED, BLACK;
  }
}
  • 包含棋子样式及其位置坐标的一个类
// 包含棋子及其位置的一个类
public class ChessPiece {
  private ChessPieceUnit unit;
  private int positionX;
  private int positionY;

  public ChessPiece(ChessPieceUnit unit, int positionX, int positionY) {
    this.unit = unit;
    this.positionX = positionX;
    this.positionY = positionY;
  }
}
  • 棋子的工厂,一份棋子就可以提供所有房间了
public class ChessPieceUnitFactory {
  private static final Map<Integer, ChessPieceUnit> pieces = new HashMap<>(); // 存储所有棋子的一个仓库

  static {
    pieces.put(1, new ChessPieceUnit(1, "車", ChessPieceUnit.Color.BLACK));
    pieces.put(2, new ChessPieceUnit(2, "馬", ChessPieceUnit.Color.BLACK));
    //...省略摆放其他棋子的代码...
  }

  /**
   * 根据ID获取棋子
   * @param chessPieceId
   * @return
   */
  public static ChessPieceUnit getChessPiece(int chessPieceId) {
    return pieces.get(chessPieceId);
  }
}
  • 棋盘
public class ChessBoard {
  private Map<Integer, ChessPiece> chessPieces = new HashMap<>();

  public ChessBoard() {
    init();  // 初始化棋子位置坐标
  }

  private void init() {
    chessPieces.put(1, new ChessPiece(ChessPieceUnitFactory.getChessPiece(1), 0, 0));
    chessPieces.put(1, new ChessPiece(ChessPieceUnitFactory.getChessPiece(2), 1, 0));
    //...省略摆放其他棋子的代码...
  }

  public void move(int chessPieceId, int toPositionX, int toPositionY) {
    //...省略...
  }
}