原理或定義
能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State).
一个内蕴状态是存储在享元对象内部的,并且不会随环境改变而有所不同.因此,一个享元可以具有内蕴状态并可以共享 .一个外蕴状态是随环境改变而改变的,不可以共享状态.享元对象的外蕴状态必须由客户端保存, 并在享元对象被创建之后, 在需要使用的时候再传到享元对象内部.
单纯享元模式结构
抽象享元(Flyweight)角色 :给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。
具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
享元工厂(FlyweightFactory)角色 :本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象;
复合享元模式结构
其他角色同上。
复合享元(ConcreteCompositeFlyweight)角色 :复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称作不可共享的享元对象。
類圖
案例与代码
景观设计软件项目遇到的问题:
树:XY坐标,树的大小,外观,需要很多树
例如10000000棵树
一般设计方案:
public class Tree {
private int xCoord, yCoord, age;
public Tree(int xCoord, int yCoord, int age) {
this.xCoord = xCoord;
this.yCoord = yCoord;
this.age = age;
}
public void display() {
// System.out.print("x");
}
}
一般会直接生成10000000个对象。但是生成10000000个对象是需要很多内存和CPU的开销的。
蝇量模式设计方案:
public class TreeFlyWeight {
public TreeFlyWeight() {
}
public void display(int xCoord, int yCoord, int age) {
// System.out.print("x");
}
}
public class TreeManager {
private int length = 10000000;
int[] xArray = new int[length], yArray = new int[length],
AgeArray = new int[length];
private TreeFlyWeight mTreeFlyWeight;
public TreeManager() {
mTreeFlyWeight = new TreeFlyWeight();
for (int i = 0; i < length; i++) {
xArray[i] = (int) (Math.random() * length);
yArray[i] = (int) (Math.random() * length);
AgeArray[i] = (int) (Math.random() * length) % 5;
}
}
public void displayTrees() {
for (int i = 0; i < length; i++) {
mTreeFlyWeight.display(xArray[i], yArray[i], AgeArray[i]);
}
}
}
public class MainTest {
public static void main(String[] args) {
showMemInfo();
TreeManager mTreeManager;
mTreeManager = new TreeManager();
showMemInfo();
mTreeManager.displayTrees();
showMemInfo();
}
public static void showMemInfo() {
// 已分配内存中的剩余空间 :
long free = Runtime.getRuntime().freeMemory();
// 分配内存:
long total = Runtime.getRuntime().totalMemory();
// 最大内存:
long max = Runtime.getRuntime().maxMemory();
// 已占用的内存:
long used = total - free;
System.out.println("最大内存 = " + max);
System.out.println("已分配内存 = " + total);
System.out.println("已分配内存中的剩余空间 = " + free);
System.out.println("已用内存 = " + used);
System.out.println("时间 = " + System.currentTimeMillis());
System.out.println("");
}
}
需求变更:景观项目里需要增加大量的草对象
抽象享元(Flyweight)角色 :
public abstract class Plant {
public Plant() {
}
public abstract void display(int xCoord, int yCoord, int age);
}
public class Grass extends Plant {
@Override
public void display(int xCoord, int yCoord, int age) {
// TODO Auto-generated method stub
// System.out.print("Grass x");
}
}
public class Tree extends Plant {
@Override
public void display(int xCoord, int yCoord, int age) {
// TODO Auto-generated method stub
// System.out.print("Tree x");
}
}
享元工厂(FlyweightFactory)角色 :
public class PlantFactory {
private HashMap<Integer, Plant> plantMap = new HashMap<Integer, Plant>();
public PlantFactory() {
}
public Plant getPlant(int type) {
if (!plantMap.containsKey(type)) {
switch (type) {
case 0:
plantMap.put(0, new Tree());
break;
case 1:
plantMap.put(1, new Grass());
break;
}
}
return plantMap.get(type);
}
}
public class PlantManager {
private int length = 10000000;
private int[] xArray = new int[length], yArray = new int[length],
AgeArray = new int[length], typeArray = new int[length];
private PlantFactory mPlantFactory;
public PlantManager() {
mPlantFactory=new PlantFactory();
for (int i = 0; i < length; i++) {
xArray[i] = (int) (Math.random() * length);
yArray[i] = (int) (Math.random() * length);
AgeArray[i] = (int) (Math.random() * length) % 5;
typeArray[i]= (int) (Math.random() * length) % 2;
}
}
public void displayTrees() {
for (int i = 0; i < length; i++) {
mPlantFactory.getPlant(typeArray[i]).display(xArray[i], yArray[i], AgeArray[i]);
}
}
}
测试类:
public class MainTest {
public static void main(String[] args) {
showMemInfo();
PlantManager mPlantManager;
mPlantManager = new PlantManager();
showMemInfo();
mPlantManager.displayTrees();
showMemInfo();
}
public static void showMemInfo() {
// 已分配内存中的剩余空间 :
long free = Runtime.getRuntime().freeMemory();
// 分配内存:
long total = Runtime.getRuntime().totalMemory();
// 最大内存:
long max = Runtime.getRuntime().maxMemory();
// 已占用的内存:
long used = total - free;
System.out.println("最大内存 = " + max);
System.out.println("已分配内存 = " + total);
System.out.println("已分配内存中的剩余空间 = " + free);
System.out.println("已用内存 = " + used);
System.out.println("时间 = " + System.currentTimeMillis());
System.out.println("");
}
}
通过共享的方式高效地支持大量细粒度的对象。
使用場景
1.一个应用程序使用了大量的对象。
2 完全由于使用大量的对象,造成很大的存储开销。
3 对象的大多数状态都可以变为外部状态。
4 如果删除对象以外的状态那么可以用相对较少的共享对象取代很多组对象。
5 应用程序不依赖于对象标识
優缺點
主要优点有:
1.减少运行时的对象实例个数,节省创建开销和内存
2.将许多“虚拟”对象的状态集中管理
主要缺点有:
1.系统设计更加复杂
2.需要专门维护对象的外部状态