有没有人有使用举重模式的特定示例?[关闭]


21

我一直在研究设计模式,并遇到了飞行重量模式。我一直在尝试寻找在我的应用程序中使用该模式的机会,但是我在查看如何使用它方面遇到了麻烦。另外,当我阅读其他人的代码时,有哪些迹象表明正在使用飞行重量模式?

根据定义,它说:

使用共享可以有效地支持大量细粒度的对象。

如果我没看错,Dictionary和Hashtables可能是飞行重量的实例,这是正确的吗?

提前致谢。


7
关于举重的一些轶事:我曾经不得不使用第三方API创建大型excel文件(最多50万条记录,超过100列)。单元的样式变得非常占用内存。因此,无论何时需要样式,都将检查哈希表是否已经存在相同的样式,然后仅提供对该样式的引用。此修改使导出成为可能。我认为现在在excel中拥有这么多数据是疯狂的。但是控制器具有要保留的分析宏。
猎鹰

9
评论:我希望那些写模式和面向对象的书籍和文章的人来到普通程序员的现实世界,并停止使用律师风格的英语!
NoChance 2011年

1
“我曾经创造大量的Excel文件(最多50万条记录,超过100列)” -这是没有太大的相比有什么一些交易商能够创造;-)
quant_dev

阅读了这些示例中的几个示例后,我认为在内存中压缩数据将是实现此技术的绝妙场所。谢谢您的帮助!
杰里米E

GWT中的表格单元格是举重。
2013年

Answers:


19

Java库中就是一个例子。Java具有原始类型(例如int32位整数)和它们的包装器(例如Integerwraps int)。有一些方法可以将“装箱” int到中,Integer然后取消装箱Integer到中int。包装器是必需的,因为基本类型不是对象,因此不能例如用作Maps中Collection的键或放在s中。

装箱方法将一系列轻量级对象用作Integers 的一种缓存,对应于int-128和127之间的值。由于这些值是最有可能用作键或放置在集合中的值,因此减少了分配和内存使用。(如果有5000000 Integers表示值0浮动,则使用的内存是重用flyweight实例的5000000倍)。



1
那么C#中的字符串内部存储池是flyweight模式正确的另一个示例吗?
杰里米E

1
@Jeremy E:是的,在我看来,您可以在flyweight模式的应用程序中调用字符串,尽管对于字符串而言,它不仅涉及内存消耗,还涉及运行时效率。
猎鹰

带有Objective-C标签的指针将其发挥到了极致。装箱的整数(最多56位)和许多字符串(最多6个字符)甚至都没有分配为对象,而是将所有信息打包到对象指针本身中。
gnasher729

9

图形。通常,光栅图像(是大多数消费者级计算机图形的基础)是CPU便宜的,但使用内存昂贵(因为内存便宜但CPU昂贵,所以很好)。如果要在渲染较大的UI时多次重复该光栅图像(从Windows GUI应用程序中的图标到文字处理器中的字体字符,再到3D游戏中表面上的纹理),则很有意义一次将图像加载到内存中,然后使用非常简单的对象指向它,而这些对象很便宜,并且它们本身不会占用大量内存。Sprite只是3D点和指向要使用的图像的第一个像素的内存指针,它只是图形空间中应在其中显示图像的点。可能还包括要使用的精灵图片文件部分的尺寸,以图形或内存的方式。更改这些信息(例如更改图像或Sprite的位置)都是非常便宜的,并且无需每次都加载新图像就可以完成此信息,从而大大提高了底层程序的性能,可操纵和显示该程序的适当部分。适当的图像以呈现完整的UI“场景”。


3

CharacterSmalltalk中的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而不是每次都被新创建。


3

使用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;

    ....
}

在大型数据集上应用此模式将导致对应用程序的内存复杂性和对象可重用性的重大优化

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.