享元模式(Flyweight Pattern)
Posted 小风的笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了享元模式(Flyweight Pattern)相关的知识,希望对你有一定的参考价值。
享元模式(运用共享技术有效的支持大量细粒度的对象)
- 优点:大大减少对象的创建,降低系统的内存,使效率提高。
- 缺点:提高了系统的复杂度,需要分离出内蕴状态和外蕴状态,而且外蕴状态具有固有化的性质,不应该随着内蕴状态的变化而变化,否则会造成系统的混乱。
- 享元模式的定义提出了两个要求,细粒度和共享对象。因为要求细粒度,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象的信息分为两个部分:内部状态和外部状态。
内蕴状态:对象共享出来的信息,存储在享元对象内部并且不会随环境的改变而改变。
外蕴状态:对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。 - 享元模式的主要角色
抽象享元角色:为具体享元角色规定了必须实现的方法,非享元的外蕴状态以参数的形式通过此方法传入。
具体享元角色:实现抽象享元角色的接口。
享元工厂角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检查系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在,则创建一个新的享元对象。
非享元角色:是不可以共享的外蕴状态,它以参数的形式注入具体享元的相关方法中。 - 例子:围棋只有黑白两色,所以棋子颜色就是棋子的内蕴状态;而各个棋子之间的差别就是位置的不同,我们落子嘛,落子颜色是定的,但位置是变化的,所以方位坐标就是棋子的外蕴状态,类图如下:
- 代码如下:
非享元角色
/**
* 棋盘位置(外蕴状态)
*/
public class Location {
private int x;
private int y;
public Location(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
抽象享元角色
/**
* 棋子
*/
public interface ChessPieces {
void downPieces(Location location);
}
具体享元角色
/**
* 白棋(内蕴状态)
*/
public class WhitePieces implements ChessPieces {
public WhitePieces() {
System.out.println("+++生成白棋对象+++");
}
@Override
public void downPieces(Location location) {
System.out.println("白棋对象已经存在,被成功获取!");
System.out.println("坐标X="+location.getX()+";Y="+location.getY());
}
}
/**
* 黑棋(内蕴状态)
*/
public class BlackPieces implements ChessPieces {
public BlackPieces() {
System.out.println("+++生成黑棋对象+++");
}
@Override
public void downPieces(Location location) {
System.out.println("黑棋对象已经存在,被成功获取!");
System.out.println("坐标X="+location.getX()+";Y="+location.getY());
}
}
享元工厂角色
/**
* 工厂
*/
public class PiecesFactory {
private static final String WRITE = "白棋";
private static final String BLACK = "黑棋";
Map<String, ChessPieces> pieces = new HashMap<>();
// 获取棋子对象
public ChessPieces getPieceInstance(String color) {
if(pieces.get(color) == null) {
if(color == WRITE) {
WhitePieces whitePieces = new WhitePieces();
pieces.put(color, whitePieces);
}else if(color == BLACK){
BlackPieces blackPieces = new BlackPieces();
pieces.put(color, blackPieces);
}else {
System.out.println("不存在的颜色");
return null;
}
}
return pieces.get(color);
}
}
测试
public class Test {
private static final String WRITE = "白棋";
private static final String BLACK = "黑棋";
public static void main(String[] args) {
try {
PiecesFactory factory = new PiecesFactory();
System.out.println("---游戏开始---");
String color = WRITE;
while (true) {
if (color.equals(WRITE)) {
System.out.println("---白棋请落子---");
} else {
System.out.println("---黑棋请落子---");
}
System.out.println("请输入X坐标");
Scanner scanner1 = new Scanner(System.in);
int x = scanner1.nextInt();
System.out.println("请输入y坐标");
Scanner scanner2 = new Scanner(System.in);
int y = scanner2.nextInt();
ChessPieces chessPieces = factory.getPieceInstance(color);
chessPieces.downPieces(new Location(x, y));
if (WRITE.equals(color)) {
color = BLACK;
} else {
color = WRITE;
}
}
} catch (Exception e) {
System.out.println("---游戏结束---");
}
}
}
// 运行结果
---游戏开始---
---白棋请落子---
请输入X坐标
1
请输入y坐标
2
+++生成白棋对象+++
白棋对象已经存在,被成功获取!
坐标X=1;Y=2
---黑棋请落子---
请输入X坐标
4
请输入y坐标
5
+++生成黑棋对象+++
黑棋对象已经存在,被成功获取!
坐标X=4;Y=5
---白棋请落子---
请输入X坐标
3
请输入y坐标
3
白棋对象已经存在,被成功获取!
坐标X=3;Y=3
---黑棋请落子---
请输入X坐标
5
请输入y坐标
5
黑棋对象已经存在,被成功获取!
坐标X=5;Y=5
---白棋请落子---
请输入X坐标
eee
---游戏结束---
运行上面代码,可以发现,在一局游戏中,只会在一开始生成白棋和黑棋对象两个对象,后面的落子只需要在工厂之中获取就好。
以上是关于享元模式(Flyweight Pattern)的主要内容,如果未能解决你的问题,请参考以下文章
二十四种设计模式:享元模式(Flyweight Pattern)