目录
一、前言
二、享元模式
三、总结
一、前言
享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少大量细粒度对象的内存占用。它通过共享尽可能多的相同数据来节约内存空间。
享元模式由以下角色组成:
Flyweight(享元):
一个接口或抽象类,定义了对象的外部状态和内部状态的方法
ConcreteFlyweight(具体享元):
实现享元接口的具体类,包含享元对象的内部状态
UnsharedConcreteFlyweight(非享元):
不需要共享的对象
FlyweightFactory(享元工厂):
创建和管理享元对象,确保共享的享元对象被正确地使用
整个享元模式的结构图:
二、享元模式
我们可以以围棋为例,围棋坐标是19*19=361,围棋只有两种颜色,黑色和白色,有很多棋子,此时我们可以利用享元模式,所有黑棋共享一个对象,所有白棋共享一个对象,棋子格子的位置不同,因此位置可以设置为不共享的对象。
首先创建围棋享元接口类GoPiece.class:
/**
* @Author dengyifan
* @create 2024/7/24 14:26
* @description 享元接口
*/
public interface GoPiece {
String getColor();
void place(int x, int y);
}
再创建黑棋对象BlackPiece.class:
/**
* @Author dengyifan
* @create 2024/7/24 14:26
* @description 具体享元类,黑棋
*/
public class BlackPiece implements GoPiece{
private final String color = "Black";
@Override
public String getColor() {
return color;
}
@Override
public void place(int x, int y) {
System.out.println("棋子:" + color + ",位置信息:(" + x + ", " + y + ")");
}
}
白棋对象WhitePiece.class:
/**
* @Author dengyifan
* @create 2024/7/24 14:26
* @description 具体享元类,白棋
*/
public class WhitePiece implements GoPiece{
private final String color = "White";
@Override
public String getColor() {
return color;
}
@Override
public void place(int x, int y) {
System.out.println("棋子:" + color + ",位置信息:(" + x + ", " + y + ")");
}
}
编写享元工厂GoPieceFactory.class:
import java.util.HashMap;
import java.util.Map;
/**
* @Author dengyifan
* @create 2024/7/24 14:26
* @description 享元工厂
*/
public class GoPieceFactory {
private static final Map<String, GoPiece> pieceMap = new HashMap<>();
public static GoPiece getPiece(String color) {
GoPiece piece = pieceMap.get(color);
if (piece == null) {
if (color.equalsIgnoreCase("Black")) {
piece = new BlackPiece();
} else if (color.equalsIgnoreCase("White")) {
piece = new WhitePiece();
}
pieceMap.put(color, piece);
}
return piece;
}
}
棋盘类BoardPosition.class:
/**
* @Author dengyifan
* @create 2024/7/24 14:29
* @description 棋盘位置类,包含享元对象和位置,共享GoPiece对象,以及不共享的x、y位置信息
*/
public class BoardPosition {
private final int size;
private final GoPiece[][] board;
public BoardPosition(int size) {
this.size = size;
this.board = new GoPiece[size][size];
}
public void placePiece(String color, int x, int y) {
GoPiece piece = GoPieceFactory.getPiece(color);
board[x][y] = piece;
piece.place(x, y);
}
public void printBoard() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (board[i][j] != null) {
System.out.print(board[i][j].getColor().charAt(0) + " ");
} else {
System.out.print(". ");
}
}
System.out.println();
}
}
public GoPiece getPieceAt(int x, int y) {
return board[x][y];
}
}
客户端调用类:
/**
* @Author dengyifan
* @create 2024/7/24 14:27
* @description
*/
public class Client {
public static void main(String[] args) {
BoardPosition board = new BoardPosition(19);
board.placePiece("Black", 1, 2);
board.placePiece("White", 2, 3);
board.placePiece("Black", 3, 4);
board.placePiece("White", 4, 5);
board.printBoard();
GoPiece piece1 = board.getPieceAt(1, 2);
GoPiece piece2 = board.getPieceAt(2, 3);
GoPiece piece3 = board.getPieceAt(3, 4);
GoPiece piece4 = board.getPieceAt(4, 5);
System.out.println("棋子1和棋子3: " + (piece1 == piece3));
System.out.println("棋子2和棋子4: " + (piece2 == piece4));
}
}
运行结果:
三、总结
优点与缺点
优点:
减少对象数量:
通过共享技术可以有效减少内存中的对象数量,从而提高系统的性能
节约内存:
共享的享元对象能够极大地节约内存空间
缺点:
复杂性增加:
系统中引入了享元工厂和共享机制,增加了系统的复杂性
非共享对象:
并不是所有的对象都适合使用享元模式,对于那些包含大量不变数据的对象,享元模式才有明显的优势
应用场景:
文本编辑器:
在文本编辑器中,每个字符可以看作是一个对象。如果文档非常大,这些字符对象将占用大量内存。使用享元模式,可以将相同字符的对象共享起来,显著减少内存消耗
图形系统:
在图形系统中,经常需要绘制大量相同或相似的图形元素,如点、线、圆等。通过享元模式,可以将相同的图形对象共享,以节约内存
数据库连接池:
在数据库应用中,创建和销毁数据库连接的开销很大。使用享元模式,可以创建一个数据库连接池,所有的数据库连接都从池中获取和释放,从而提高性能和资源利用率
游戏开发:
在游戏开发中,大量的游戏对象(如树木、建筑物、NPC等)需要频繁使用。使用享元模式,可以将相同类型的游戏对象共享,从而减少内存占用,提高游戏性能