一、蝇量模式简介
Flyweight模式也叫享元模式,是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用。
二、蝇量模式的结构
三、蝇量模式的角色与职责
- 抽象享元角色: 所有具体享元类的父类,规定一些需要实现的公共接口。
- 具体享元角色: 抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法。
- 享元工厂角色: 负责创建和管理享元角色。
四、蝇量模式的具体实现
某游戏在剧情中需要大量的树木装饰,本来他们已经设计了一个模式,但是游戏中加载时间太长,用户体验不好,想让我们帮忙想想办法。
那我们先看看他们是怎么设计的。
1、不使用蝇量模式
方案设计
直接创建1000000个数对象,并使用显示在屏幕上。
在这里通过打印创建时间以及内存使用情况来对比。
类设计
首先是游戏中的树类,有x坐标、y坐标以及年龄三个域。
// An highlighted block
package design.Flyweight.gys.noFlyweight;
public class Tree {
private int x;
private int y;
private int age;
public Tree(int x, int y, int age) {
super();
this.x = x;
this.y = y;
this.age = age;
}
public void display() {
}
}
由于不使用设计模式,需要有参构造器来初始化树对象。而display()方法则不做任何输出。
接着他们使用了一个管理类来管理这1000000个数对象。
// An highlighted block
package design.Flyweight.gys.noFlyweight;
import java.util.ArrayList;
import java.util.Random;
public class Manager {
ArrayList<Tree> arr=new ArrayList<>();
Random r=new Random();
public void test() {
for(int i=0;i<1000000;i++)
arr.add(new Tree(r.nextInt(), r.nextInt(), r.nextInt()));
for(Tree t:arr)
t.display();
}
}
进入加载游戏的界面。看一下效果
// An highlighted block
package design.Flyweight.gys.noFlyweight;
public class Test {
public static void main(String[] args) {
info();
new Manager().test();
info();
}
public static void info() {
long max=Runtime.getRuntime().maxMemory();
long total=Runtime.getRuntime().totalMemory();
long free=Runtime.getRuntime().freeMemory();
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("-------------");
}
}
这里的info()方法输出了总的内存、占用内存、空闲内存以及系统的时间:
// An highlighted block
最大内存:259522560
全部内存:16252928
空闲内存:15222784
已用内存:1030144
时间:1545707516538
-------------
最大内存:259522560
全部内存:64888832
空闲内存:34835712
已用内存:30053120
时间:1545707517488
-------------
可以看到,不适用蝇量模式的时候,游戏加载了将近1秒,占用了29M的内存。游戏玩家的视觉体验太差。
下面我们使用蝇量模式来对游戏进行改进。
2、使用蝇量模式
方案设计
类设计
同样存在一个树类,但是该树拥有的是无参构造器,并且display()方法也不做任何事。
// An highlighted block
package design.Flyweight.gys.Flyweight;
public class Tree {
private int x;
private int y;
private int age;
public Tree() {
}
public void display(int x,int y, int age) {
}
}
在上一个管理类中,使用的是LIst容器对树对象进行管理,在蝇量模式中,我们定义三个数组,分别用来存储x坐标、y坐标、年龄:
// An highlighted block
import java.util.Random;
public class Manager {
private Tree tree=new Tree();
int[] x=new int[1000000];
int[] y=new int[1000000];
int[] age=new int[1000000];
Random r=new Random();
public void test() {
for(int i=0;i<1000000;i++)
{
x[i]=r.nextInt();
y[i]=r.nextInt();
age[i]=r.nextInt();
}
for(int i=0;i<100000;i++)
tree.display(x[i],y[i],age[i]);
}
}
接下来我们测试一下我们的代码加载速度以及运行时间,同样的测试代码:
// An highlighted block
package design.Flyweight.gys.Flyweight;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
info();
new Manager().test();
info();
}
public static void info() {
long max=Runtime.getRuntime().maxMemory();
long total=Runtime.getRuntime().totalMemory();
long free=Runtime.getRuntime().freeMemory();
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("-------------");
}
}
屏气凝神:
// An highlighted block
最大内存:259522560
全部内存:16252928
空闲内存:15238152
已用内存:1014776
时间:1545708086746
-------------
最大内存:259522560
全部内存:16318464
空闲内存:3642976
已用内存:12675488
时间:1545708087038
-------------
可以看到,加载速度大约在0.25秒左右,内存占用11M。可以说极大的提高了用户体验。
由于本人的电脑比较废,读者可以试着尝试10000000个对象。
五、蝇量模式的优缺点
- 优点:
- 减少运行时的对象实例的个数,节省创建的开销和内存
- 将对象集中管理
- 缺点:
- 可能会增加系统的设计复杂度
- 需要专门的管理外部状态