21

The two pattern seems to achieve the same thing. What are the different use cases in real world? Thanks

4

7 回答 7

33

Flyweight是当你有许多不同种类的单一事物时。

单身是当你有一个单一的东西。

例如,您可以使用享元模式来表示键盘字符。一个对象为a,一个对象为b,等等。它们都是字符,但字符类型不同。

相反,您可以使用单例来表示键盘。只能有一个。

于 2013-05-25T15:09:52.697 回答
19

单例通常用于表示只有其中之一的对象,例如键盘、计算机屏幕、主存储器。它可以代表更抽象的事物,例如消息调度中心或协调器。整个应用程序的数据库链接。

对象集合与单个对象

您可以将SingletonFlyweight都视为拥有生产对象的工厂。一个关键的区别是 Singleton 工厂总是返回相同的对象。相比之下,享元工厂是参数化的。创建函数接受一个参数。根据参数的值,将返回不同的享元对象。

您可能有一个单例表示正在文字处理器中处理的当前页面。然而,页面上的单个字符可以表示为Flyweights

这里与单例的相似之处在于,每次出现的字符“A”都将引用同一个对象。因此,将“A”作为参数提供给享元工厂将始终返回相同的对象。因此,每次创建“A”对象时都会出现类似单例的行为,都会返回相同的对象。

与Singleton工厂的区别在于元工厂允许创建整个类的相关对象。

可变性

单例通常是可变的。然而,对于享元,我们倾向于在享元之外保持可变状态。因此,例如,如果我们有代表文档中字符的享元对象,那么字符位置通常会与享元对象分开存储。

虽然我不排除它,但我想不出您想让享元对象本身可变的任何情况。想象一下,您有一个享元代表字符“B”,然后您将其更改为“A”。然后文档中的“B”将变为“A”。那将是非常不可取的。

同样,如果享元代表颜色。如果你创建了一个红色并且它是绿色的,那会令人困惑,因为它的底层享元对象在代码的其他地方被更改为绿色。

例子

来自 Cocoa (Objective-C) 的示例:

UIApplication.sharedApplication.statusBarHidden = YES

这显然是一个对象,您可以更改其状态。

UIColor *red = [UIColor redColor]

在这种情况下,我们是否每次都得到一个新对象并不明显。因为颜色是不可变的,所以这个 API 的维护者可以自由地实现红、蓝、绿、黄、灰等常见颜色作为享元对象。这意味着有一个公共对象池,当您调用构造函数时它们会被重用。

对用户来说,是否在幕后使用享元模式没有区别。这就是为什么我会声称不变性是享元对象的理想属性的原因。

还要注意在这种情况下参数化是如何隐含的。您可以通过使用不同的命名构造函数来选择颜色。yellowColorblueColor

于 2013-05-25T15:12:24.987 回答
7

它们是不相关的:

Flyweight 尽可能重用(显然是不可变的)类的实例,而不是创建具有相同“值”的类的新实例,从而节省 CPU 和内存。

单例是指只有一个(通常是可变的)类的实例。它通常用于多线程环境中,以方便所有线程使用单个实例并“看到”相同的状态。

于 2013-05-25T15:13:18.337 回答
3

当对象的内在和外在状态存在明确分离时,使用享元。内部状态可以在其他外部对象之间共享。例如,文档的标题可以归类为对象的固有状态,并且可以共享。但是文档中的其余数据可能非常动态并由用户(外部数据)填充。为了表示内在数据,可以在享元工厂内创建和维护享元对象。享元工厂对象将用作享元(标题对象)的集合,并且可以在我们的案例中更早地填充并在文档的各种实例之间共享。

于 2013-10-27T07:51:10.267 回答
1

不要忘记单例是一种创造模式,而享元是一种结构模式。因此,两种模式的目标是完全不同的

于 2014-05-23T15:21:04.870 回答
1

元结构模式本质上消除了实现某个目标所需的重复对象。例如,假设您正在输入一篇文章(或者可能是一篇关于堆栈溢出的文章),它最终由(英文)字母表中相同的 26 个字母组成,重复了很多次。有 1000 个单独的对象,每个对象代表字母“E”,或者只有一个对象代表字母“E”,被引用 1000 次,效率会更高吗?(提示,一般是后者)

如何实现每个对象(即 26 个字母)的创建是一个单独的问题,但是通常通过利用“类似单例”特性的工厂方法(创建模式)来实现。

  • 初始化一个空的字符集合。
  • 需要字母“E”吗?
  • 如果它已经存在,则从集合中检索该对象,否则创建一个新字母“E”并将其存储在集合中,以便下次重新使用。

这是通过一个成熟的单例对象完成的,还是只是一个只有工厂方法才能访问的私有变量?可能是也可能不是。但无论哪种方式,单例模式都是一种创建模式,描述了在任何给定时间点仅存在一个对象的单个实例的方法,并且不关心特定的用例,例如“删除实现所需的对象的重复”一个特定的目标”。

于 2018-08-03T02:00:19.907 回答
0

它们是两种完全不同的“模式类型”。单例是一种“创造”模式。创建模式是更高阶的常见“对象创建”方法。另一方面,享元是一种“结构模式”。结构模式必须更多地处理接口和实现,而不是“对象创建”。描述差异的另一种更简单的方法是第一个模式类型“创建模式”更多地基于名词。第二种“结构模式”类型更基于动词。

于 2017-12-22T16:40:47.250 回答