享元模式
# 享元模式
享元模式是为了对象复用,节省内存,防止对象的频繁创建和销毁。
# 定义
享元模式(Flyweight Pattern)是一种结构设计模式,旨在通过共享对象来减少内存使用和提高性能。它适用于大量细粒度的对象,其中许多对象具有相似的属性和行为。
# 结构
抽象享元(Flyweight):定义享元对象的接口,包含享元对象的公共方法。这个接口可以描述内部状态和外部状态的操作。
具体享元(ConcreteFlyweight):实现抽象享元接口,并存储内部状态。具体享元对象需要注意内部状态的共享和复用,确保可以被多个客户端共享。
享元工厂(Flyweight Factory):负责创建和管理享元对象。它维护一个享元池(或缓存),用于存储已创建的享元对象。当客户端请求获取享元对象时,享元工厂首先检查享元池中是否存在符合要求的对象,如果存在则返回已有的对象,否则创建一个新的对象并将其放入享元池中。
客户端(Client):使用享元对象的客户端。客户端通常会维护一个对享元工厂的引用,并通过享元工厂获取享元对象。客户端需要将外部状态传递给享元对象,以完成具体的操作。
- img: https://bitouyun.com/images/design-pattern/flyweight.png
link: https://bitouyun.com/images/design-pattern/flyweight.png
name: 享元模式
2
3
# 优点
享元模式通过共享内部状态,可以减少系统中对象的数量,节省内存空间。相同或相似的对象可以共享一份内部状态,从而减少了对象的创建和销毁的开销,提升系统的响应速度。
# 缺点
增加了系统复杂性:要分离出外部状态和内部状态,引入享元工厂来管理享元对象,这增加了系统的复杂性。
# 应用场景
享元模式适用于需要创建大量相似对象、希望减少对象数量、节省内存空间并提高系统性能的场景。它可以在对象的内部状态和外部状态之间进行分离,并通过共享内部状态来实现对象的复用。如文字、图像处理、商品、缓存、池管理等。
# 示例代码1
场景1
黑白棋游戏使用享元模式,减少对象的创建,
/**
* 棋子
* 抽象享元接口
*/
public interface Piece {
// 设置坐标位置
void put(int x, int y);
}
2
3
4
5
6
7
8
/**
* 黑棋
* 具体享元类
*/
@Slf4j
public class BlackPiece implements Piece {
@Override
public void put(int x, int y) {
log.info("在坐标(x:{},y:{})放置了一个黑棋子", x, y);
}
}
/**
* 白棋
* 具体享元类
*/
@Slf4j
public class WhitePiece implements Piece {
@Override
public void put(int x, int y) {
log.info("在坐标(x:{},y:{})放置了一个白棋子", x, y);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 棋子工厂类
* 享元工厂
*/
@Slf4j
public class PieceFactory {
// 棋子map
private final Map<String, Piece> pieceMap = new HashMap<>();
// 饿汉式单例
private static PieceFactory instance = new PieceFactory();
// 私有构造方法
private PieceFactory() {
}
// 获取实例
public static PieceFactory getInstance() {
return instance;
}
// 获取棋子对象
public Piece getPiece(String color) {
Piece piece = pieceMap.get(color);
if (piece == null) {
switch (color) {
case "black":
piece = new BlackPiece();
log.info("创建黑棋");
break;
case "white":
piece = new WhitePiece();
log.info("创建白棋");
break;
default:
throw new IllegalArgumentException("不支持的颜色:" + color);
}
pieceMap.put(color, piece);
}
return piece;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
Piece black = PieceFactory.getInstance().getPiece("black");
black.put(1, 1);
Piece black1 = PieceFactory.getInstance().getPiece("black");
black1.put(2, 2);
Piece white = PieceFactory.getInstance().getPiece("white");
white.put(3, 3);
Piece white1 = PieceFactory.getInstance().getPiece("white");
white1.put(4, 4);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Make sure to add code blocks to your code group
# 示例代码2
场景2
文本编辑器中字符显示,在文本编辑器中有许多字符需要显示,大部分字符是相似,如字体、大小和颜色,使用享元模式可以共享相同的字符对象,下面是一个简化的示例。
/**
* 字符
* 抽象享元接口
*/
public interface Character {
// 显示字符
void display();
}
2
3
4
5
6
7
8
/**
* 具体字符
* 具体享元类
*/
@Slf4j
public class ConcreteCharacter implements Character {
// 字符
private String symbol;
public ConcreteCharacter(String symbol) {
this.symbol = symbol;
}
@Override
public void display() {
log.info("字符:{}", symbol);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 字符工厂
* 享元工厂类
*/
@Slf4j
public class CharacterFactory {
// 字符map
private static Map<String, Character> characterMap = new HashMap<>();
public static Character getCharacter(String symbol) {
Character character = characterMap.get(symbol);
if (character == null) {
character = new ConcreteCharacter(symbol);
log.info("创建字符对象");
characterMap.put(symbol, character);
}
return character;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
Character character = CharacterFactory.getCharacter("A");
character.display();
Character character2 = CharacterFactory.getCharacter("A");
character2.display();
}
}
2
3
4
5
6
7
8
9
10
11
// Make sure to add code blocks to your code group