# 对象池系统 (Object Pool System)

## 概述

GFramework 的对象池系统是一个高效的内存管理机制，旨在减少垃圾回收（GC）压力，通过复用对象实例来提高应用程序性能。该系统实现了对象的创建、获取、释放和销毁的完整生命周期管理。

**核心优势：**

- **减少 GC 压力**：复用对象实例，避免频繁的内存分配和回收
- **提高性能**：避免重复创建开销大的对象
- **灵活管理**：支持多个独立的对象池，按需分类管理
- **自动生命周期**：与 System 生命周期集成，自动管理对象销毁
- **类型安全**：基于泛型实现，编译时类型检查

## 核心组件

### IPoolableObject 接口

定义了可池化对象的行为规范，所有需要池化的对象都必须实现此接口。

```csharp
public interface IPoolableObject
{
    /// <summary>
    /// 当对象从池中获取时调用，用于初始化或重置对象状态
    /// </summary>
    void OnAcquire();

    /// <summary>
    /// 当对象被放回池中时调用，用于清理对象状态
    /// </summary>
    void OnRelease();

    /// <summary>
    /// 当对象池被销毁时调用，用于执行最终清理
    /// </summary>
    void OnPoolDestroy();
}
```

**生命周期：**

```
创建 → Acquire（从池取出）→ 使用 → Release（放回池）→ 可再次 Acquire
                                          ↓
                                    Pool Destroy → OnPoolDestroy → 销毁
```

### IObjectPoolSystem 接口

定义了对象池系统的基本操作接口。

```csharp
public interface IObjectPoolSystem<TKey, TObject>
    where TObject : IPoolableObject
    where TKey : notnull
{
    /// <summary>
    /// 从指定键的对象池中获取一个对象
    /// </summary>
    /// <param name="key">对象池的键值</param>
    /// <returns>获取到的对象实例</returns>
    TObject Acquire(TKey key);

    /// <summary>
    /// 将对象释放回指定键的对象池中
    /// </summary>
    /// <param name="key">对象池的键值</param>
    /// <param name="obj">需要释放的对象</param>
    void Release(TKey key, TObject obj);

    /// <summary>
    /// 清空所有对象池，销毁所有池中的对象
    /// </summary>
    void Clear();
}
```

### AbstractObjectPoolSystem 抽象类

实现了 `IObjectPoolSystem` 接口的具体逻辑，提供了对象池管理的完整实现。

**核心特性：**

- 使用字典存储多个对象池，以键区分不同的对象池
- 使用栈（Stack）存储池中的对象，实现 LIFO（后进先出）管理
- 提供获取和释放对象的方法
- 通过抽象方法 `Create` 让子类决定如何创建对象
- 在系统销毁时自动清理所有对象池

**内部实现：**

```csharp
public abstract class AbstractObjectPoolSystem<TKey, TObject>
    : AbstractSystem, IObjectPoolSystem<TKey, TObject>
    where TObject : IPoolableObject
    where TKey : notnull
{
    // 存储对象池的字典，键为池标识，值为对应类型的对象栈
    protected readonly Dictionary<TKey, Stack<TObject>> Pools = new();

    // 获取对象
    public TObject Acquire(TKey key)
    {
        if (!Pools.TryGetValue(key, out var pool))
        {
            pool = new Stack<TObject>();
            Pools[key] = pool;
        }

        var obj = pool.Count > 0
            ? pool.Pop()  // 从池中取出
            : Create(key); // 创建新对象

        obj.OnAcquire(); // 调用对象的获取钩子
        return obj;
    }

    // 释放对象
    public void Release(TKey key, TObject obj)
    {
        obj.OnRelease(); // 调用对象的释放钩子

        if (!Pools.TryGetValue(key, out var pool))
        {
            pool = new Stack<TObject>();
            Pools[key] = pool;
        }

        pool.Push(obj); // 放回池中
    }

    // 清空所有对象池
    public void Clear()
    {
        foreach (var obj in Pools.Values.SelectMany(pool => pool))
        {
            obj.OnPoolDestroy(); // 调用对象的销毁钩子
        }

        Pools.Clear();
    }

    // 子类实现：创建新对象
    protected abstract TObject Create(TKey key);

    // 系统销毁时自动清空对象池
    protected override void OnDestroy()
    {
        Clear();
    }
}
```

## 基本使用

### 1. 定义池化对象

首先，创建一个实现 `IPoolableObject` 接口的类。

```csharp
public class Bullet : IPoolableObject
{
    public int Damage { get; private set; }
    public float Speed { get; private set; }
    public Vector3 Position { get; private set; }
    public Vector3 Direction { get; private set; }
    public bool IsActive { get; private set; }

    public void OnAcquire()
    {
        // 从池中获取时调用，初始化对象状态
        IsActive = true;
    }

    public void OnRelease()
    {
        // 放回池中时调用，清理对象状态
        IsActive = false;
        Damage = 0;
        Speed = 0;
        Position = Vector3.Zero;
        Direction = Vector3.Zero;
    }

    public void OnPoolDestroy()
    {
        // 对象池销毁时调用，执行最终清理
        // 可以在这里释放非托管资源
    }

    // 设置子弹属性的方法
    public void Setup(int damage, float speed, Vector3 position, Vector3 direction)
    {
        Damage = damage;
        Speed = speed;
        Position = position;
        Direction = direction;
    }

    // 更新子弹逻辑
    public void Update(float deltaTime)
    {
        Position += Direction * Speed * deltaTime;
    }
}
```

### 2. 实现对象池系统

继承 `AbstractObjectPoolSystem<TKey, TObject>` 并实现 `Create` 方法。

```csharp
public class BulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
    protected override Bullet Create(string key)
    {
        // 根据键值创建不同类型的子弹
        return key switch
        {
            "standard" => new Bullet(),
            "heavy" => new Bullet(),
            "explosive" => new Bullet(),
            _ => new Bullet()
        };
    }

    protected override void OnInit()
    {
        // 可以预先创建一些对象放入池中
        for (int i = 0; i < 10; i++)
        {
            var bullet = Create("standard");
            bullet.OnAcquire();
            bullet.OnRelease();
            Release("standard", bullet);
        }
    }
}
```

### 3. 在架构中注册对象池系统

```csharp
public class GameArchitecture : Architecture
{
    protected override void Init()
    {
        // 注册其他组件
        RegisterModel(new PlayerModel());
        RegisterSystem(new CombatSystem());

        // 注册对象池系统
        RegisterSystem(new BulletPoolSystem());
    }
}
```

### 4. 使用对象池

```csharp
public class ShootingSystem : AbstractSystem
{
    private BulletPoolSystem _bulletPool;
    private List<Bullet> _activeBullets = new();

    protected override void OnInit()
    {
        _bulletPool = this.GetSystem<BulletPoolSystem>();
        this.RegisterEvent<ShootEvent>(OnShoot);
        this.RegisterEvent<GameUpdateEvent>(OnUpdate);
    }

    private void OnShoot(ShootEvent e)
    {
        // 从对象池获取子弹
        var bullet = _bulletPool.Acquire("standard");

        // 设置子弹属性
        bullet.Setup(
            damage: e.Damage,
            speed: 10.0f,
            position: e.StartPosition,
            direction: e.Direction
        );

        // 添加到活跃列表
        _activeBullets.Add(bullet);
    }

    private void OnUpdate(GameUpdateEvent e)
    {
        // 更新所有活跃子弹
        for (int i = _activeBullets.Count - 1; i >= 0; i--)
        {
            var bullet = _activeBullets[i];
            bullet.Update(e.DeltaTime);

            // 检查子弹是否需要销毁（例如：超出范围或击中目标）
            if (ShouldDestroyBullet(bullet))
            {
                // 放回对象池
                _bulletPool.Release("standard", bullet);
                _activeBullets.RemoveAt(i);
            }
        }
    }

    private bool ShouldDestroyBullet(Bullet bullet)
    {
        // 简单示例：子弹超出一定范围则销毁
        return bullet.Position.Length() > 1000.0f;
    }
}
```

## 高级用法

### 1. 多键对象池管理

```csharp
public class ParticlePoolSystem : AbstractObjectPoolSystem<string, Particle>
{
    protected override Particle Create(string key)
    {
        // 根据键值创建不同类型的粒子效果
        return key switch
        {
            "explosion" => new Particle(explosionPrefab),
            "smoke" => new Particle(smokePrefab),
            "spark" => new Particle(sparkPrefab),
            _ => throw new ArgumentException($"Unknown particle type: {key}")
        };
    }

    // 提供便捷方法
    public Particle SpawnExplosion(Vector3 position)
    {
        var particle = Acquire("explosion");
        particle.Position = position;
        particle.Play();
        return particle;
    }
}

// 使用
public class EffectSystem : AbstractSystem
{
    private ParticlePoolSystem _particlePool;

    protected override void OnInit()
    {
        _particlePool = this.GetSystem<ParticlePoolSystem>();
    }

    public void PlayExplosion(Vector3 position)
    {
        _particlePool.SpawnExplosion(position);
    }
}
```

### 2. 动态对象池管理

```csharp
public class EnemyPoolSystem : AbstractObjectPoolSystem<string, Enemy>
{
    protected override Enemy Create(string key)
    {
        // 根据敌人类型创建不同的敌人
        var enemyPrefab = LoadEnemyPrefab(key);
        return new Enemy(enemyPrefab);
    }

    // 动态注册新的敌人类型池
    public void RegisterEnemyType(string enemyType)
    {
        if (!Pools.ContainsKey(enemyType))
        {
            Pools[enemyType] = new Stack<Enemy>();

            // 预热：预先创建几个敌人放入池中
            for (int i = 0; i < 3; i++)
            {
                var enemy = Create(enemyType);
                enemy.OnAcquire();
                enemy.OnRelease();
                Release(enemyType, enemy);
            }
        }
    }
}

// 使用
public class EnemySpawnerSystem : AbstractSystem
{
    private EnemyPoolSystem _enemyPool;

    protected override void OnInit()
    {
        _enemyPool = this.GetSystem<EnemyPoolSystem>();

        // 注册不同类型的敌人
        _enemyPool.RegisterEnemyType("goblin");
        _enemyPool.RegisterEnemyType("orc");
        _enemyPool.RegisterEnemyType("dragon");
    }

    public void SpawnEnemy(string enemyType, Vector3 position)
    {
        var enemy = _enemyPool.Acquire(enemyType);
        enemy.Position = position;
        enemy.Activate();
    }
}
```

### 3. 对象池大小限制

```csharp
public class LimitedBulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
    private const int MaxPoolSize = 50;

    protected override Bullet Create(string key)
    {
        return new Bullet();
    }

    public new void Release(string key, Bullet obj)
    {
        // 检查对象池大小
        if (Pools.TryGetValue(key, out var pool) && pool.Count >= MaxPoolSize)
        {
            // 池已满，不回收对象，让它被 GC 回收
            return;
        }

        // 调用基类的 Release 方法
        base.Release(key, obj);
    }
}
```

### 4. 对象池统计和调试

```csharp
public class DebuggablePoolSystem : AbstractObjectPoolSystem<string, PoolableObject>
{
    public Dictionary<string, int> PoolSizes => Pools.ToDictionary(
        kvp => kvp.Key,
        kvp => kvp.Value.Count
    );

    public int TotalPooledObjects => Pools.Values.Sum(stack => stack.Count);

    public void LogPoolStatus()
    {
        foreach (var (key, stack) in Pools)
        {
            Console.WriteLine($"Pool [{key}]: {stack.Count} objects");
        }

        Console.WriteLine($"Total pooled objects: {TotalPooledObjects}");
    }

    protected override void OnDestroy()
    {
        LogPoolStatus();
        base.OnDestroy();
    }
}
```

## 使用场景

### 1. 游戏对象池

**适用对象：**

- 子弹、箭矢、投射物
- 敌人、NPC
- 爆炸效果、粒子系统
- UI 元素（提示、对话框）

**示例：子弹池**

```csharp
// 定义子弹
public class Bullet : IPoolableObject
{
    public Vector3 Position { get; private set; }
    public Vector3 Velocity { get; private set; }
    public float Lifetime { get; private set; }

    public void OnAcquire()
    {
        Lifetime = 5.0f; // 5秒后自动销毁
    }

    public void OnRelease()
    {
        Position = Vector3.Zero;
        Velocity = Vector3.Zero;
    }

    public void OnPoolDestroy() { }

    public void Update(float deltaTime)
    {
        Position += Velocity * deltaTime;
        Lifetime -= deltaTime;
    }
}

// 子弹对象池
public class BulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
    protected override Bullet Create(string key) => new Bullet();
}

// 射击系统
public class ShootingSystem : AbstractSystem
{
    private BulletPoolSystem _bulletPool;
    private List<Bullet> _activeBullets = new();

    protected override void OnInit()
    {
        _bulletPool = this.GetSystem<BulletPoolSystem>();
        this.RegisterEvent<ShootEvent>(OnShoot);
        this.RegisterEvent<GameUpdateEvent>(OnUpdate);
    }

    private void OnShoot(ShootEvent e)
    {
        var bullet = _bulletPool.Acquire("normal");
        bullet.Position = e.StartPosition;
        bullet.Velocity = e.Direction * e.Speed;
        _activeBullets.Add(bullet);
    }

    private void OnUpdate(GameUpdateEvent e)
    {
        for (int i = _activeBullets.Count - 1; i >= 0; i--)
        {
            var bullet = _activeBullets[i];
            bullet.Update(e.DeltaTime);

            if (bullet.Lifetime <= 0)
            {
                _bulletPool.Release("normal", bullet);
                _activeBullets.RemoveAt(i);
            }
        }
    }
}
```

### 2. UI 元素池

**适用对象：**

- 对话框
- 提示框
- 菜单项
- 列表项

**示例：提示框池**

```csharp
public class Tooltip : IPoolableObject
{
    public string Text { get; set; }
    public bool IsActive { get; private set; }

    public void OnAcquire()
    {
        IsActive = true;
    }

    public void OnRelease()
    {
        IsActive = false;
        Text = "";
    }

    public void OnPoolDestroy() { }

    public void Show(string text, Vector3 position)
    {
        Text = text;
        // 更新 UI 位置和内容
    }
}

public class TooltipPoolSystem : AbstractObjectPoolSystem<string, Tooltip>
{
    protected override Tooltip Create(string key) => new Tooltip();
}

public class UISystem : AbstractSystem
{
    private TooltipPoolSystem _tooltipPool;

    protected override void OnInit()
    {
        _tooltipPool = this.GetSystem<TooltipPoolSystem>();
    }

    public void ShowTooltip(string text, Vector3 position)
    {
        var tooltip = _tooltipPool.Acquire("default");
        tooltip.Show(text, position);
    }
}
```

### 3. 网络消息对象池

**适用对象：**

- 网络包
- 协议消息
- 数据包

**示例：网络包池**

```csharp
public class NetworkPacket : IPoolableObject
{
    public byte[] Data { get; private set; }
    public int Length { get; private set; }

    public void OnAcquire()
    {
        Data = Array.Empty<byte>();
        Length = 0;
    }

    public void OnRelease()
    {
        // 清理敏感数据
        if (Data != null)
        {
            Array.Clear(Data, 0, Data.Length);
        }
        Length = 0;
    }

    public void OnPoolDestroy() { }

    public void SetData(byte[] data)
    {
        Data = data;
        Length = data.Length;
    }
}

public class PacketPoolSystem : AbstractObjectPoolSystem<string, NetworkPacket>
{
    protected override NetworkPacket Create(string key) => new NetworkPacket();
}
```

## 最佳实践

### 1. 对象生命周期管理

```csharp
// ✅ 好的做法：确保所有对象都放回池中
public class BulletSystem : AbstractSystem
{
    private List<Bullet> _activeBullets = new();

    protected override void OnDestroy()
    {
        // 系统销毁时，确保所有活跃子弹都放回池中
        foreach (var bullet in _activeBullets)
        {
            _bulletPool.Release("standard", bullet);
        }

        _activeBullets.Clear();
        base.OnDestroy();
    }
}

// ❌ 不好的做法：忘记放回对象，导致泄漏
public class BadBulletSystem : AbstractSystem
{
    private List<Bullet> _activeBullets = new();

    private void OnUpdate(GameUpdateEvent e)
    {
        // 子弹销毁时忘记放回池中
        if (bullet.Lifetime <= 0)
        {
            _activeBullets.RemoveAt(i);
            // 忘记调用 _bulletPool.Release(...)
        }
    }
}
```

### 2. 对象状态重置

```csharp
// ✅ 好的做法：在 OnRelease 中彻底重置对象状态
public class Bullet : IPoolableObject
{
    public int Damage { get; set; }
    public float Speed { get; set; }
    public List<string> Tags { get; set; }
    public Dictionary<string, object> Data { get; set; }

    public void OnRelease()
    {
        // 重置所有属性
        Damage = 0;
        Speed = 0;
        Tags?.Clear();
        Data?.Clear();

        // 也可以设置为新实例（如果性能允许）
        Tags = new List<string>();
        Data = new Dictionary<string, object>();
    }
}

// ❌ 不好的做法：不完全重置状态
public class BadBullet : IPoolableObject
{
    public List<string> Tags = new List<string>();

    public void OnRelease()
    {
        // 只清空列表，但列表实例本身保留
        // 这可能导致问题：如果其他代码持有列表引用
        Tags.Clear();
    }
}
```

### 3. 对象池预热

```csharp
// ✅ 好的做法：预先创建一些对象放入池中
public class BulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
    protected override Bullet Create(string key) => new Bullet();

    protected override void OnInit()
    {
        // 为常用的子弹类型预热对象池
        var commonTypes = new[] { "standard", "heavy", "sniper" };

        foreach (var type in commonTypes)
        {
            // 预先创建 5 个对象
            for (int i = 0; i < 5; i++)
            {
                var bullet = Create(type);
                bullet.OnAcquire();
                bullet.OnRelease();
                Release(type, bullet);
            }
        }
    }
}
```

### 4. 对象池大小管理

```csharp
// ✅ 好的做法：限制对象池大小，避免内存浪费
public class BoundedPoolSystem : AbstractObjectPoolSystem<string, PooledObject>
{
    private const int MaxPoolSize = 100;

    public new void Release(string key, PooledObject obj)
    {
        if (Pools.TryGetValue(key, out var pool) && pool.Count >= MaxPoolSize)
        {
            // 池已满，不回收对象
            return;
        }

        base.Release(key, obj);
    }
}

// ✅ 好的做法：动态调整对象池大小
public class AdaptivePoolSystem : AbstractObjectPoolSystem<string, PooledObject>
{
    private Dictionary<string, int> _peakUsage = new();

    public new void Release(string key, PooledObject obj)
    {
        // 记录峰值使用量
        if (Pools.TryGetValue(key, out var pool))
        {
            _peakUsage[key] = Math.Max(_peakUsage.GetValueOrDefault(key, 0), pool.Count);
        }

        // 根据使用情况动态调整
        int maxAllowed = _peakUsage.GetValueOrDefault(key, 10) * 2;
        if (pool.Count >= maxAllowed)
        {
            return; // 不回收
        }

        base.Release(key, obj);
    }
}
```

### 5. 调试和监控

```csharp
// ✅ 好的做法：添加对象池统计功能
public class MonitoredPoolSystem : AbstractObjectPoolSystem<string, PooledObject>
{
    private Dictionary<string, int> _acquireCount = new();
    private Dictionary<string, int> _releaseCount = new();

    public new PooledObject Acquire(string key)
    {
        _acquireCount[key] = _acquireCount.GetValueOrDefault(key, 0) + 1;
        return base.Acquire(key);
    }

    public new void Release(string key, PooledObject obj)
    {
        _releaseCount[key] = _releaseCount.GetValueOrDefault(key, 0) + 1;
        base.Release(key, obj);
    }

    public void PrintStatistics()
    {
        foreach (var key in Pools.Keys)
        {
            int acquired = _acquireCount.GetValueOrDefault(key, 0);
            int released = _releaseCount.GetValueOrDefault(key, 0);
            int leaked = acquired - released;

            Console.WriteLine($"Pool [{key}]:");
            Console.WriteLine($"  Acquired: {acquired}");
            Console.WriteLine($"  Released: {released}");
            Console.WriteLine($"  Leaked: {leaked}");
            Console.WriteLine($"  Pool size: {Pools[key].Count}");
        }
    }
}
```

## 性能优化

### 1. 减少对象创建

```csharp
// ✅ 好的做法：对象池预热，避免运行时创建
public class PreheatedPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
    protected override Bullet Create(string key) => new Bullet();

    protected override void OnInit()
    {
        // 预热常用对象池
        PreheatPool("standard", 20);
        PreheatPool("heavy", 10);
    }

    private void PreheatPool(string key, int count)
    {
        for (int i = 0; i < count; i++)
        {
            var bullet = Create(key);
            bullet.OnAcquire();
            bullet.OnRelease();
            Release(key, bullet);
        }
    }
}
```

### 2. 使用值类型作为键

```csharp
// ✅ 好的做法：使用枚举或整数作为键，避免字符串比较
public enum BulletType
{
    Standard,
    Heavy,
    Explosive
}

public class FastBulletPoolSystem : AbstractObjectPoolSystem<BulletType, Bullet>
{
    protected override Bullet Create(BulletType key) => key switch
    {
        BulletType.Standard => new Bullet(),
        BulletType.Heavy => new Bullet(),
        BulletType.Explosive => new Bullet(),
        _ => throw new ArgumentException()
    };
}
```

### 3. 批量操作

```csharp
// ✅ 好的做法：批量获取和释放对象
public class BatchPoolSystem : AbstractObjectPoolSystem<string, PooledObject>
{
    public List<PooledObject> AcquireBatch(string key, int count)
    {
        var objects = new List<PooledObject>(count);
        for (int i = 0; i < count; i++)
        {
            objects.Add(Acquire(key));
        }
        return objects;
    }

    public void ReleaseBatch(string key, IEnumerable<PooledObject> objects)
    {
        foreach (var obj in objects)
        {
            Release(key, obj);
        }
    }
}
```

## 注意事项

1. **对象状态管理**：确保 `OnRelease` 方法彻底重置对象状态，避免状态污染
2. **对象引用**：不要在放回对象池后继续持有对象引用
3. **线程安全**：对象池本身不是线程安全的，如需多线程访问，需要自行加锁
4. **内存泄漏**：确保所有获取的对象最终都放回池中
5. **对象池大小**：合理设置对象池大小，避免内存浪费或频繁创建

## 相关包

- [`system`](./system.md) - 对象池系统继承自 AbstractSystem
- [`architecture`](./architecture.md) - 在架构中注册对象池系统

---

**许可证**: Apache 2.0
