享元模式
享元模式:多个功能相似的实例,共享一个公共的实例。
我们需要渲染一片森林,森林有一千颗树,每棵树有相同的部分:树的网格、树的纹理和树叶的纹理
每棵树又有不同的部分:位置、旋转、缩放等
将相同的部分封装为一个类,只实例化一次;不同的部分封装为一个类,实例化一千次。
在 Direct3D 和 openGL 的图形 API 中,分别提供
第一个是将被多次渲染的公共数据块——共享的树的类的实例
第二个是实例列表及其参数——一千棵树的实例(包含不同的位置、旋转、缩放)
这样就渲染了一片森林
享元模式的使用痕迹并不明显,如果不额外封装一个多个实例间共享的类,这看起来就是资源的共享。
在 1命令模式 中,跳跃命令是纯行为的无状态记录的,在这种情况下,拥有多个跳跃命令类的实例,会浪费内存,因为所有实例都是功能等效的。
Flyweight (享元)模式解决了“ 实例化多个相同功能的实例浪费内存 ”这个问题。
解决办法就是让多个相似的实例共用一个类的实例
享元模式如何使用?
举例说明,创建一个 2D 世界类,稍后生成世界类的实例
public class World
{
public List<Terrain> terrainList = new List<Terrain>();
public TerrainProp grassProp = new TerrainProp(1, false, Texture.GRASS_TEXTURE);
public TerrainProp hillProp = new TerrainProp(3, false, Texture.HILL_TEXTURE);
public TerrainProp riverProp = new TerrainProp(2, true, Texture.RIVER_TEXTURE);
}
世界类里面有地形类,地形类中的数据分为两部分:
一部分是地形实例在世界中的位置,每份地形实例应该在世界中不同的位置,这一部分就是每个实例不一样的、不可共享的;
public class Terrain
{
#region 不可共享的部分
// 地形块在世界中的左下顶点位置
public int x;
public int y;
public int width = 10;
public int height = 10;
#endregion
#region 共享的部分
public TerrainProp prop;
#endregion
public Terrain(int x, int y, TerrainProp prop)
{
this.x = x;
this.y = y;
this.prop = prop;
}
}
书中的例子是将地形以数组的形式存入世界类的成员属性中,因此数组的索引就直接表示了地形的位置,不同地形间就只剩下可共享的部分
另一部分是地形实例的特性,例如“在地形上的移动速度”、“这个地形能否行船”、“这个地形的贴图”这样的特性,这一部分就是可以在同一类型的地形类实例中可共享的。
public class TerrainProp
{
public int moveSpeed;
public bool isWater;
public Texture texture;
public TerrainProp(int moveSpeed, bool isWater, Texture texture)
{
this.moveSpeed = moveSpeed;
this.isWater = isWater;
this.texture = texture;
}
}
public class Texture
{
public static Texture GRASS_TEXTURE;
public static Texture HILL_TEXTURE;
public static Texture RIVER_TEXTURE;
}
最后,在生成世界的多个地形实例的时候,相同类型的地形共享同一个地形属性 TerrainProp
public void GenerateWorld()
{
terrainList.Clear();
// 生成 两块草地、两块山丘、两块河流地形横向排列
for (int i = 0; i < 6; i++)
{
TerrainProp tmp;
if (i < 2)
{
tmp = grassProp;
}
else if (i < 4)
{
tmp = hillProp;
}
else
{
tmp = riverProp;
}
var terrain = new Terrain(i * 10, 0, tmp);
terrainList.Add(terrain);
}
}