- 一、导语
- 二、怎么用
1.样例背景
2.UML类图
3.代码示例- 三、优缺点
- 四、使用场景
1.概括描述
2.现存知名产品中的使用示例- 五、与其他设计模式的对比
- 六、参考
一、导语
享元模式(Flyweight),提供了减少对象数量从而改善应用所需的对象结构的方式。(概括来讲,就是减少对象创建的数量,从而减少内存的占用,并且提高性能)
运用共享技术有效的支持大量细粒度对象
在享元模式的时候,一定要关注线程安全问题。
内部状态:在享元对象的内部,不会随着环境改变而改变的部分。
外部状态:随着环境改变而改变的部分。
二、怎么用
共有2个示例,代码详见访问链接
下面以example2举例说明
1. 样例背景
围棋游戏中,棋子的情况
(分析: 这种情况下,对于棋子,颜色上只有黑白两种区别,
而棋盘上所有的棋子,其实除了位置属性不同之外别的差别都不大)
2. UML类图
Piece ---------------------------------- 棋子接口
WhitePiece --------------------------- 白子
BlackPiece ----------------------------- 黑子
PieceFactory --------------------------- 创建棋子的工厂类
3. 代码示例
/**
* description: 棋子的接口
*/
public interface Piece {
/**
* description: 摆放棋子的方法
*/
void put();
}
/**
* description: 黑棋
*/
public class BlackPiece implements Piece {
@Override
public void put() {
System.out.println(color + "将棋子放到了" + Arrays.toString(position));
}
// 内部属性
private static final String color = "黑手";
// 外部属性
private long[] position;
public void setPosition(long[] position) {
if (null == position || position.length != 2) {
throw new RuntimeException("棋子位置输入错误");
}
this.position = position;
}
}
/**
* description: 白棋
*/
public class WhitePiece implements Piece {
@Override
public void put() {
System.out.println(color + "将棋子放到了" + Arrays.toString(position));
}
// 内部属性
private static final String color = "白手";
// 外部属性
private long[] position;
public void setPosition(long[] position) {
if (null == position || position.length != 2) {
throw new RuntimeException("棋子位置输入错误");
}
this.position = position;
}
}
/**
* description: 棋子工厂
*/
public class PieceFactory {
private final static Map<String,Piece> PIECE_MAP= new HashMap<>();
public final static String BLACK_PIECE = "black";
public final static String WHITE_PIECE = "white";
public static Piece getPiece(String color){
Piece piece = PIECE_MAP.get(color);
if (null == piece) {
if (BLACK_PIECE.equalsIgnoreCase(color)) {
piece = new BlackPiece();
} else if (WHITE_PIECE.equalsIgnoreCase(color)) {
piece = new WhitePiece();
}
PIECE_MAP.put(color, piece);
}
return piece;
}
}
/**
* description: 客户端测试类
* todo 感觉在其真正的使用方式上还是有疑惑
*/
public class Test {
public static void main(String[] args) {
long[] position;
for(int i=0; i<10; i++){
position = new long[]{(long)(Math.random() * 362),(long)(Math.random() * 362)};
if (i % 2 == 0) {
BlackPiece piece = (BlackPiece) PieceFactory.getPiece(PieceFactory.BLACK_PIECE);
piece.setPosition(position);
piece.put();
}else {
WhitePiece piece = (WhitePiece) PieceFactory.getPiece(PieceFactory.WHITE_PIECE);
piece.setPosition(position);
piece.put();
}
}
}
}
执行结果
黑手将棋子放到了[56, 336]
白手将棋子放到了[325, 336]
黑手将棋子放到了[75, 177]
白手将棋子放到了[266, 226]
黑手将棋子放到了[50, 1]
白手将棋子放到了[10, 53]
黑手将棋子放到了[89, 187]
白手将棋子放到了[289, 332]
黑手将棋子放到了[122, 180]
白手将棋子放到了[299, 185]
三、优缺点
缺点
1.需要关注内部/外部状态以及线程安全问题
2.使系统逻辑程序复杂化优点
1.减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率
2.减少内存之外的其他资源占用
四、使用场景
1. 概括描述
- 常常应用于系统底层的开发,以便解决系统性能问题
- 系统有大量相似对象,需要缓冲池的场景
2. 现存知名产品中的使用示例 todo
2.1 java.lang.String (jdk)
比如 java中的String 类型使用的就是享元模式:
如果有,则返回,则创建一个字符串,并且保存在字符串的缓存迟中,
2.2 java.lang.Integer.valueOf(int i) (jdk)
2.3 org.apache.commons.pool.impl.GenericObjectPool
五、相关设计模式
1.享元模式和代理模式
代理模式,它会代理一个类,那如果生成这个代理类需要花费的时间和资源都比较多,那么就可以使用享元模式,来提高程序的处理速度。
2.享元模式和单例模式
容器单例,就是他们二者的一个结合,
享元模式就是一种复用对象的思想。