享元模式
通过共享大量细粒度对象,来减少内存使用,提升性能。
适合的场景
系统中创建了大量类似对象,内存飙升!
希望复用相同状态(共享部分),只保留个别差异作为外部状态
节省对象创建成本、优化性能,尤其适合精灵图、粒子、字符串、地图块等等
基本结构
Flyweight(享元):共享对象的接口,通常是不可变的
ConcreteFlyweight(具体享元):实现共享逻辑
FlyweightFactory(享元工厂):管理共享对象的创建和复用
外部状态:变化的部分,由调用方传入
示例
csharp
// 享元类:单位图标(共享部分)
class UnitIcon
{
public string Texture { get; }
public UnitIcon(string texture) => Texture = texture;
public void Draw(int x, int y)
{
Console.WriteLine($"绘制单位图标 {Texture} 于位置({x}, {y})");
}
}
// 工厂:用于管理共享的图标对象
class IconFactory
{
private readonly Dictionary<string, UnitIcon> _icons = new();
public UnitIcon GetIcon(string type)
{
if (!_icons.ContainsKey(type))
_icons[type] = new UnitIcon($"assets/{type}.png");
return _icons[type];
}
}
// 使用:只存储坐标,图标统一复用
class Unit
{
public int X { get; }
public int Y { get; }
public UnitIcon Icon { get; }
public Unit(int x, int y, UnitIcon icon)
{
X = x;
Y = y;
Icon = icon;
}
public void Draw() => Icon.Draw(X, Y);
}
var factory = new IconFactory();
var icon = factory.GetIcon("knight"); // 所有骑士都用同一图标
var units = new List<Unit>
{
new(0, 0, icon),
new(1, 2, icon),
new(3, 4, icon),
};
foreach (var unit in units)
unit.Draw();GDScript示例
gdscript
# 享元类:弹幕样式
class BulletType extends Resource:
var texture_path: String
func draw(x: int, y: int) -> void:
print("在 (%d, %d) 绘制子弹:%s" % [x, y, texture_path])
# 工厂类
class BulletFactory:
var _cache := {}
func get_bullet(type_name: String) -> BulletType:
if not _cache.has(type_name):
var b = BulletType.new()
b.texture_path = "res://bullet/" + type_name + ".png"
_cache[type_name] = b
return _cache[type_name]
# 使用
func _ready():
var factory := BulletFactory.new()
var bullet_type := factory.get_bullet("fireball")
for i in 10:
bullet_type.draw(i * 10, i * 5)