一、简介
享元模式是一种结构型设计模式,旨在通过共享对象来最大程度地减少内存使用和提高性能。它主要用于减少创建对象的数量,节省内存和提高性能。
该模式通过共享相似对象之间的公共部分来减少内存占用。当需要创建大量相似对象时,通过重用已存在的相似对象,而不是每次都新建一个对象来节省内存。这个被共享的对象称为享元(Flyweight),包含了对象的共享状态和非共享状态。共享状态是可以被多个对象共享的部分,而非共享状态是对象独有的部分。
通过分离内部状态(不变且可共享)和外部状态(变化且不可共享),享元模式允许在运行时共享许多细粒度对象,从而提高系统的性能和效率。典型的例子是文本编辑器中的字符对象,大量的字符对象在外观上是相似的,例如,大写字母 “A” 的字形和颜色通常是相同的,所以可以使用享元模式来共享这些共同的特性,从而节省内存。
二、享元模式
当涉及中国象棋时,可以使用享元模式来模拟棋子。每个棋子(如将、车、马等)都有自己的共享属性(例如颜色、类型),而位置是每个棋子独有的非共享属性。
2.1、棋子类
首先,定义棋子类 ChessPiece:
// 棋子类
public class ChessPiece {
private String type; // 共享属性 - 棋子类型
private String color; // 共享属性 - 棋子颜色
private int x, y; // 非共享属性 - 棋子位置
public ChessPiece(String color, String type) {
this.type = type;
this.color = color;
this.x = 0; // 默认位置
this.y = 0;
}
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
public void display() {
System.out.println("象棋: " + color + " " + type + " 的位置 (" + x + ", " + y + ")");
}
}
2.2、棋子工厂类
然后,创建一个工厂类 ChessPieceFactory 来管理棋子的共享:
// 棋子工厂类
public class ChessPieceFactory {
private static final Map<String, ChessPiece> pieces = new HashMap<>();
public static ChessPiece getChessPiece(String color, String type) {
String key = color + "_" + type;
if (!pieces.containsKey(key)) {
pieces.put(key, new ChessPiece(color, type));
}
return pieces.get(key);
}
}
2.3、棋子类
接下来,使用示例:
public class FlyweightChessDemo {
public static void main(String[] args) {
ChessPiece piece1 = ChessPieceFactory.getChessPiece("红", "炮");
piece1.setPosition(0, 3);
piece1.display();
ChessPiece piece2 = ChessPieceFactory.getChessPiece("红", "车");
piece2.setPosition(1, 3);
piece2.display();
ChessPiece piece3 = ChessPieceFactory.getChessPiece("黑", "马");
piece3.setPosition(0, 6);
piece3.display();
ChessPiece piece4 = ChessPieceFactory.getChessPiece("黑", "卒");
piece4.setPosition(3, 5);
piece4.display();
}
}
运行结果:
象棋: 红 炮 的位置 (0, 3)
象棋: 红 车 的位置 (1, 3)
象棋: 黑 马 的位置 (0, 6)
象棋: 黑 卒 的位置 (3, 5)
在这个例子中,ChessPieceFactory 管理着共享的棋子对象。当需要创建棋子时,首先检查该类型和颜色的棋子是否已经存在,如果存在则直接返回已存在的棋子对象,否则创建新的棋子对象。这样可以实现共享相同类型和颜色的棋子,减少了棋子对象的创建数量,节省了内存空间。
三、优点与缺点
享元模式的优点和缺点如下所示:
优点:
- 减少内存消耗: 通过共享相似对象的公共部分来减少内存消耗。对于大量相似对象,可以显著减少所需内存。
- 提高性能: 通过重用已存在的享元对象,避免了频繁创建和销毁对象,从而提高了系统的性能和效率。
- 降低系统复杂度: 享元模式将对象的状态分为内部状态和外部状态,使得系统更加简单和易于管理。
缺点:
- 可能引入复杂性: 实现享元模式需要对对象的内部状态和外部状态进行分离,可能会引入额外的复杂性,使得代码变得复杂难懂。
- 限制共享对象的可变性: 由于共享的对象通常具有不可变性,因此共享对象的修改可能会影响到其他对象,需要慎重考虑对象的可变性。
- 可能降低单个对象的独立性: 对象的部分状态变为共享状态,可能降低单个对象的独立性,需要根据实际情况进行权衡。
综上所述,享元模式在合适的场景下能够显著减少内存消耗和提高性能,但需要注意在设计和实现时平衡可维护性和复杂性,避免引入过多的共享状态以及可能导致的对象状态不一致问题。