从“四人组中的模式”一章中,当FlyWeight
大多数对象状态可以被设为外部时,FlyWeight 模式适用。
是什么extrinsic state
意思?我觉得这种模式是用来共享对象的。如果要共享对象,那么该对象怎么可能有任何状态呢?
从“四人组中的模式”一章中,当FlyWeight
大多数对象状态可以被设为外部时,FlyWeight 模式适用。
是什么extrinsic state
意思?我觉得这种模式是用来共享对象的。如果要共享对象,那么该对象怎么可能有任何状态呢?
让我们以文字处理器为例:
字处理器处理字符对象。Character 对象的状态是字符内容、字体、样式、位置等(就字处理器而言)。不同的文档使用不同的字符实例。假设我们只处理az字符,不同的文档使用来自az的字母池,但可能会应用不同的字体/样式。因此,如果我们将字符的内容与字体/样式分开,我们可以共享这些字符,这是有道理的,因为与使用的不同字符实例相比,不同类型的字符总数更少(在我们的例子中为 26 个,否则为常量)在不同的文件中。共享这些字符实例意味着明智地共享字符实例内容并将诸如字体/样式之类的上下文应用到这些字符外部。字符内容是内在状态,字体/样式是外在状态。在上面的示例中,将状态分为内在和外在状态可以节省大量存储空间。
extrinsic - 属于对象上下文(外部)或对该实例唯一的状态
内在 - 自然属于“FlyWeight”对象的状态,因此应该是永久的或不可变的(内部的)或上下文无关的。
无论该项目符号列表中的具体措辞如何,理解该消息很重要:享元适用于状态的重要部分可以在许多对象之间共享的情况,因为它是对所有对象都相同的一些数据。通常,共享状态本质上是不可变的(即“普遍真理”)。带有字体的示例非常清楚地说明了这一点;日常 Java 中的一个示例是java.util.regex.Pattern
享元,vs Matcher
. 重用它并保持本地外部状态的客户端对象。许多Matcher
s 可以并行存在,都在内部重用已编译的正则表达式。
这句话比你的问题更清楚:
共享的享元越多,节省的存储空间就越大。节省会随着共享状态的数量而增加。当对象同时使用大量的内在和外在状态,并且外在状态可以计算而不是存储时,最大的节省就会发生。然后您可以通过两种方式节省存储空间:共享降低了内在状态的成本,并且您可以用外在状态来换取计算时间。
Gang of Four 的享元设计模式引入了内在和外在状态的概念:
这里的关键概念是内在和外在状态之间的区别。内在状态存储在享元中;它由独立于享元上下文的信息组成,因此可以共享。外部状态取决于享元的上下文并随其变化,因此无法共享。客户端对象负责在需要时将外部状态传递给享元。
换句话说,一个对象的状态可以相对于一组对象分解为内在状态和外在状态,其中内在状态是该组所有对象的状态的交集,外在状态是对象的状态和内在状态的区别。由于该组的每个对象中的固有状态都是重复的,因此可以通过将对象组替换为单个享元来节省空间存储单个内在状态的对象。然而享元对象不能存储组对象的多个外部状态,因此外部状态存储在外部,并在来自客户端对象的每个请求中传递给享元对象。这种优化的通信协议通常被称为无状态协议,因为享元对象不存储外部状态。无状态协议的示例包括 IP 和 HTTP(以及更普遍的任何 REST 协议,其中内在状态称为资源状态,外在状态称为应用程序状态)。
例如,让我们使用三个对象及其各自的客户端:
o1 ← c1
o2 ← c2
o3 ← c3
我们可以针对三个对象分解每个对象的状态:
状态 1 =内在状态∪外在状态 1
状态 2 =内在状态∪外在状态 2
状态 3 =内在状态∪外在状态 3在哪里:
内在状态=状态 1 ∩状态 2 ∩状态 3
外在状态 1 =状态 1 \内在状态
外在状态 2 =状态 2 \内在状态
外在状态 3 =状态 3 \内在状态
在这里,内在状态被复制了。因此将其存储在单个享元对象中(并将外部状态移动到客户端)可以节省空间:
o ← c1, c2, c3