我一直在研究设计模式,并遇到了飞行重量模式。我一直在尝试寻找在我的应用程序中使用该模式的机会,但是我在查看如何使用它方面遇到了麻烦。另外,当我阅读其他人的代码时,有哪些迹象表明正在使用飞行重量模式?
根据定义,它说:
使用共享可以有效地支持大量细粒度的对象。
如果我没看错,Dictionary和Hashtables可能是飞行重量的实例,这是正确的吗?
提前致谢。
我一直在研究设计模式,并遇到了飞行重量模式。我一直在尝试寻找在我的应用程序中使用该模式的机会,但是我在查看如何使用它方面遇到了麻烦。另外,当我阅读其他人的代码时,有哪些迹象表明正在使用飞行重量模式?
根据定义,它说:
使用共享可以有效地支持大量细粒度的对象。
如果我没看错,Dictionary和Hashtables可能是飞行重量的实例,这是正确的吗?
提前致谢。
Answers:
Java库中就是一个例子。Java具有原始类型(例如int
32位整数)和它们的包装器(例如Integer
wraps int
)。有一些方法可以将“装箱” int
到中,Integer
然后取消装箱Integer
到中int
。包装器是必需的,因为基本类型不是对象,因此不能例如用作Map
s中Collection
的键或放在s中。
装箱方法将一系列轻量级对象用作Integer
s 的一种缓存,对应于int
-128和127之间的值。由于这些值是最有可能用作键或放置在集合中的值,因此减少了分配和内存使用。(如果有5000000 Integer
s表示值0浮动,则使用的内存是重用flyweight实例的5000000倍)。
图形。通常,光栅图像(是大多数消费者级计算机图形的基础)是CPU便宜的,但使用内存昂贵(因为内存便宜但CPU昂贵,所以很好)。如果要在渲染较大的UI时多次重复该光栅图像(从Windows GUI应用程序中的图标到文字处理器中的字体字符,再到3D游戏中表面上的纹理),则很有意义一次将图像加载到内存中,然后使用非常简单的对象指向它,而这些对象很便宜,并且它们本身不会占用大量内存。Sprite只是3D点和指向要使用的图像的第一个像素的内存指针,它只是图形空间中应在其中显示图像的点。可能还包括要使用的精灵图片文件部分的尺寸,以图形或内存的方式。更改这些信息(例如更改图像或Sprite的位置)都是非常便宜的,并且无需每次都加载新图像就可以完成此信息,从而大大提高了底层程序的性能,可操纵和显示该程序的适当部分。适当的图像以呈现完整的UI“场景”。
Character
Smalltalk中的ASCII范围实例是flyweights。
当您评估时Character space
,将Character class >> #value:
执行:
value: anInteger
"Answer the Character whose value is anInteger."
anInteger > 255 ifTrue: [^self basicNew setValue: anInteger].
^ CharacterTable at: anInteger + 1.
类变量CharacterTable
的初始化如下:
initialize
"Create the table of unique Characters, and DigitsValues."
"Character initializeClassificationTable"
CharacterTable ifNil: [
"Initialize only once to ensure that byte characters are unique"
CharacterTable := Array new: 256.
1 to: 256 do: [:i | CharacterTable
at: i
put: (self basicNew setValue: i - 1)]].
self initializeDigitValues
因此,当您创建一个String时,ASCII范围Character
将来自CharacterTable
而不是每次都被新创建。
使用flyweight模式的目的是避免不必要的对象初始化,从而节省空间。根据GOF的定义,对象可以具有两种状态,固有状态和外部状态:
- 本征状态:存放在举重装置中;它包含与flyweights上下文无关的信息,从而使其可共享。
- 外在状态:取决于飞重的上下文并随其变化,因此不能共享。客户对象负责在需要时将外部状态传递给flyweight。
假设我们要开发一个简单的文本编辑器应用程序,其中每一列都包含文本的所有行,并且该行可以包含字符。
这里的难题是如何设计Character类。的char c
字符类内应是主要(本征状态)对象。但是,一个char可以具有Font和Size(外部状态)。因此,我们需要将其外部状态存储在行(客户端)上,并在需要时进行访问。为此,将创建两个存储字体和大小的列表。
通过遵循Flyweight模式,Character现在可以重用,并且可以从包含所有ASCII符号(Character
对象)的特定对象列表(Flyweight池)中引用对象。
这是我直观描述的内容:
对于打印“ hello”,只Character
需要4个对象,而不是5个。一旦更改了字体,就不需要新的对象了。请注意,如果我们将非本征状态存储在Character类上,则这是不可能的,例如,
class Character
{
char c;
int Size;
Font font;
....
}
在大型数据集上应用此模式将导致对应用程序的内存复杂性和对象可重用性的重大优化。