FlyWeight

与现实生活中一样,并非所有对象都易于创建,有些对象可能会占用过多内存。FlyWeight 设计模式可以帮助我们尽可能多地与类似对象共享数据,从而最大限度地减少内存占用。

这种设计模式在大多数 PHP 应用程序中用途有限,但还是值得了解一下,以备不时之需。

假设我们有一个带有 draw 方法的 Shape 接口:

<?php

interface Shape
{
    public function draw();
}

让我们创建一个实现该接口的 Circle 类。在实现该接口时,我们可以用 X 和 Y 坐标设置圆的位置。我们还创建了设置圆的半径和绘制圆(打印出这些信息)的函数。请注意颜色特征是如何在类外设置的。

这有一个非常重要的原因。在我们的示例中,颜色与状态无关;它是圆的固有部分。然而,圆的位置和大小与状态无关,因此是外在的。外在状态信息会在需要使用 FlyWeight 对象的功能时传递给它,而内在选项则独立于 FlyWeight 的每个进程。当我们介绍这个工厂是如何制造出来的时候,这一点会更有意义。

这是重要信息:

  • 外在的:状态属于对象的外部上下文,在使用时输入到对象中。

  • 内在的:自然属于对象的状态,因此应该是永久的、不可变的(内部的)或上下文无关的。

考虑到这一点,让我们将 Shape 接口的实现放在一起。这是我们的 Circle 类:

Unresolved include directive in modules/ROOT/pages/ch04/ch4-04.adoc - include::example$/Chapter 4/Flyweight/Circle.php[]

有了这个,我们现在可以构建我们的 ShapeFactory,它实际上实现了 FlyWeight 模式。具有我们选择的颜色的对象在需要时被实例化,然后被存储以供以后使用:

Unresolved include directive in modules/ROOT/pages/ch04/ch4-04.adoc - include::example$/Chapter 4/Flyweight/ShapeFactory.php[]

让我们在我们的 index.php 文件中演示一下它是如何工作的。

为了实现这一点,我们在随机位置创建 100 个具有随机颜色的对象:

Unresolved include directive in modules/ROOT/pages/ch04/ch4-04.adoc - include::example$/Chapter 4/Flyweight/index.php[]

现在,让我们看一下输出。您可以看到我们已经绘制了 100 个圆圈,但我们只需要实例化少数几个圆圈,因为我们正在缓存相同颜色的对象以供以后使用:

Creating a green circle.
Drawing circle which is green at [29, 26] of radius 100.
Creating a black circle.
Drawing circle which is black at [17, 64] of radius 100.
Drawing circle which is black at [81, 86] of radius 100.
Drawing circle which is black at [0, 73] of radius 100.
Creating a red circle.
Drawing circle which is red at [10, 15] of radius 100.
Drawing circle which is red at [70, 79] of radius 100.
Drawing circle which is red at [13, 78] of radius 100.
Drawing circle which is green at [78, 27] of radius 100.
Creating a blue circle.
Drawing circle which is blue at [38, 11] of radius 100.
Creating a orange circle.
Drawing circle which is orange at [43, 57] of radius 100.
Drawing circle which is blue at [58, 65] of radius 100.
Drawing circle which is orange at [75, 67] of radius 100.
Drawing circle which is green at [92, 59] of radius 100.
Drawing circle which is blue at [53, 3] of radius 100.
Drawing circle which is black at [14, 33] of radius 100.
Creating a white circle.
Drawing circle which is white at [84, 46] of radius 100.
Drawing circle which is green at [49, 61]
Drawing circle which is orange at [57, 44] of radius 100.
Drawing circle which is orange at [64, 33] of radius 100.
Drawing circle which is white at [42, 74] of radius 100.
Drawing circle which is green at [5, 91] of radius 100.
Drawing circle which is white at [87, 36] of radius 100.
Drawing circle which is red at [74, 94] of radius 100.
Drawing circle which is black at [19, 6] of radius 100.
Drawing circle which is orange at [70, 83] of radius 100.
Drawing circle which is green at [74, 64] of radius 100.
Drawing circle which is white at [89, 21] of radius 100.
Drawing circle which is red at [25, 23] of radius 100.
Drawing circle which is blue at [68, 96] of radius 100.
Drawing circle which is green at [74, 6] of radius 100.

您可能已经注意到这里的一些事情。我存储我们重用的 FlyWeight 对象的缓存的方式是连接 Circle_ 和颜色,例如 Circle_green。显然,这在这个用例中是有效的,但是有更好的方法来做到这一点;在 PHP 中,实际上可以获得给定对象的唯一 ID。 我们将在下一个模式中介绍这一点。