在 C# 中实现对象池






3.37/5 (10投票s)
对象池模式是非常有用的面向对象模式。它们非常适合创建开销很大的大型或重量级对象。

引言
对象池模式是非常有用的面向对象模式。它们非常适合创建开销很大的大型或重量级对象。 例如,您可以将 GDI 对象存储在某个对象池中,并在需要时重复使用它们。 这种模式可以大大提高代码速度,而不会增加对象堆的开销。
在这里,对象创建和缓存的责任被分配给一个类,通常是一个单例类。
背景
对象池(也称为资源池)用于管理对象缓存。 有权访问对象池的客户端可以通过简单地向池请求一个已经实例化的对象来避免创建新对象。 通常,池将是一个增长的池,即如果池为空,则池本身将创建新对象,或者我们可以拥有一个限制创建对象数量的池。
理想的做法是将所有当前未使用的可重用对象保存在同一个对象池中,以便可以通过一个连贯的策略来管理它们。 为了实现这一点,可重用池类被设计为一个单例类。
实现
首先,让我们有一些重量级对象需求。 让我们假设我们正在开发一个支持文本格式的文本编辑器应用程序。
现在,格式化将允许我更改文本中每个字符的字体、颜色、大小等。 如果必须支持这种格式粒度,那么我可以将每个字符视为一个单独的对象。 这些对象可以显示在屏幕上; 因此,它们将包含各种 GDI 对象。 因此,创建这些对象对我来说开销很大,而且是重量级的对象。
我创建了一个名为 Character
的类,它表示文本中必须显示的单个字符。 由于此类必须显示在屏幕上,因此它实现了接口 IDrawable
,该接口定义了绘制对象的职责。 现在,我们发现需要一个 Character
对象池,因为可以将字符添加到文本和删除。 当我们删除字符时,我们不会销毁它们,而是将它们发送到池中,以便一旦我们插入更多字符,我们不必创建新对象,而是可以重用池中的对象。
因此,我创建了一个名为 CharPool
的类,它是 Character
对象的对象池。 此类被设计为单例类(前面解释过),因此它的构造函数是 private
,这迫使其他类调用其 static
Instance 属性来获取 CharPool
类的一个实例。 池最初将创建 15 个“Character”对象并维护它们,无论何时池中没有对象,它都会创建一个新对象并返回。
现在,我扩展了 Panel
类以实现一个 Canvas
类,它是我的文本编辑器,并将保存文本(一组 Character
对象)。 为了保持示例简单,我在 mainform
上创建了一个键盘面板,以提供输入,而不是从标准键盘提供输入。
MainForm
将包含 Canvas
(在其中显示文本)和 CharPool
(其中包含 Character
对象)。 现在,MainForm
负责从池中获取 Character
对象并添加到画布,以及从画布中删除对象以将其替换回池中。
设计

使用示例
运行示例,您将能够看到一个带有画布和一个键盘面板的应用程序。 请注意,池计数表示 15(最初在池中创建了 15 个对象)。 现在按下键盘面板上的任何字符,例如“A”,您看到了什么? 字符“A”显示在屏幕上,您注意到池计数了吗?是的,它减少了一个,画布上的对象来自池中,尝试插入更多对象,看看当池中没有对象时,它将创建新对象。 现在通过按键盘面板上的“退格”按钮删除其中一个对象,该对象将被发送回池中,并在您添加另一个字符时重复使用。
希望这能解释对象池的使用。
历史
- 2005 年 12 月 2 日:首次发布