Flyweight模式之我见

今天看了板桥里人的《设计模式之Flyweight(享元) FlyWeight模式
》一文,发现其中的理解有些偏差,因此在这里谈一谈自己的看法。

Flyweight的目的是为了减少内存的消耗而出现的一种模式。因此他是一种解决实现问题的模式,而不是用来解决建模问题的。

在文章的例子中说class CD是接口 Flyweight,而class Artist是ConcreteFlyweight。那就完全错了。
按照Flyweight模式,Flyweight和ConcreteFlyweight是继承关系。
而文中却成了聚合关系。
Flyweight模式中,最重要的是将对象分解成extrinsic和intrinsic两部分
在Flyweight Interface中,应该是和context有关的操作,而在例子中,看不到任何和context有关的操作。

可见作者是将flyweight模式和object pool等同起来了。但实际上两者是由本质区别的。object pool中的对象并没有extrinsic,也不知道context的存在。比如最常见的string pool。pool中的string可以用在任何地方。

希望板桥里人先生本着对读者负责的精神,能够修改上文。

以上。

[该贴被oxygen于2007年05月28日 19:40修改过]

Flyweight是为解决包含相同信息多个实例反复创建的性能开销,是一个提高性能的模式,常见EJB等J2EE中使用的Object Cache和Object Pool都属于这种Flyweight具体应用表现。

您的理解完全错误。

1. Flyweight是减少内存的使用量的一种模式,间接的可能会提高性能。两者没有必然联系。

2. Flyweight和Object pool完全不同。FlyWeight内部用到的共享机制在实现上和object cache有点像,但是有本质上的区别。不要把两者混为一谈。请仔细读一下GoF的原著。

3. Flyweight未必会减少实例的创建次数。反而可能会增加实例的创建次数。(尤其对于非JAVA语言)

4. Flyweight内部的共享机制和object pool的区别。
4.1 原理不同
object pool的原理是复用(一个对象被反复使用,但同时只有一个“人”在使用),flyweight的原理是共享(同时被多个“人”使用)。
object pool有一个很重要的特点,那就是pool中的对象是同质的。也就是说,对于使用者来说,可以用pool中的任何一个object。就好像当我们需要connection时可以从connection pool中任意的拿一个出来使用,而Flyweight的每一个实例的内部属性都不同,完全是异质的。flyweight使用时,是去FlyweightFactory中找一个特定的对象出来(如果没有的话,就创建一个)。flyweight的出发点是共享。而object pool中的对象是不能共享的。
4.2 运用的场合不同
object pool对应的场景是对象被频繁创建,使用,然后销毁这样一种情况。也就是说,每个对象的生命期都很短。同一时刻内,系统中存在的对象数也比较小。而Flyweight对应的情况是在同一时刻内,系统中存在大量对象。

5. Flyweight内部共享机制和object cache的区别。
5.1 原理不同
cache的原理是程序的局部访问性原理。对一小部分经常使用到的对象/数据提供一个高速的存储。而大部分数据放在一个低速的存储中。因此有cache算法和命中率的问题。flyweight的共享机制中,并没有高速和低速的问题。也不存在命中率的问题。可能会有一个查找算法的问题。
5.2 运用场合的不同。
cache运用在一小部分对象会被经常访问到的情况。比如说论坛中置顶的帖子。
flyweight用在同时使用到大量对象的情况。比如在屏幕上绘制一张有100万个电子元器件的电路图。这个时候每个对象都被用到一次,且只被用到一次。

6 在这里再提一下Buffer这个概念。
Buffer的原理是减小访问的波动性。在软件开发上用的比较少。这里就不说了。

您尽然把差别如此之大的东西混为一谈。我也不得不说一声佩服。
看来你完全不明白什么是Flyweight模式。
而且理论基础及其薄弱。

基本原理不懂也就算了,把用途都完全不同的东西混为一谈,您是怎么帮人做咨询,教学生的?
好好学一些基础知识吧。

在这里借用一句您经常说的话,不要再误人子弟了。
[该贴被oxygen于2007年05月30日 20:18修改过]

多谢楼上详细描述。虽然最后几句话不好听,是不是有点水平的人都是这样?

不过,楼上对于Flyweight模式很多硬性定义(在与POOL的对比中)已经超过GOF原著的中定义,我不知道这些超过定义是来自楼上的经验,还是引自哪些经典,请赐教。

更重要的是:Flyweight是模式,是抽象,POOL和Cache是具象,这是两个层次的概念,进行详细比较有意义吗?

[该贴被banq于2007年05月31日 14:47修改过]

哪些超出了原著的中定义?请列举。
我会告诉你出处的。

2个从基本原理,到运用场合都不同的东西,解决的问题也截然不同,怎么个具象和抽象呢?

你说这是具象和抽象的关系,能具体说说怎么个具象法吗?

难道就是在改善性能吗?
而且我也已经说过了,flyweight和性能没有必然联系。

在这里引用一下原著中flyweight的意图
Use sharing to support large numbers of fine-grained objects efficiently。

pool里有sharing吗?
cache里有sharing吗?

pool和large numbers of objects也没什么关系,这个我前面已经详细说过了。

原著里通篇都没有提到“performance”一词,只在注释里提到一次。说的是外部特性的管理,和flyweight也没什么关系。
我不知道你的这些结论是怎么得到的。

我之所以指责您,
是应为您以传道授业者自居,却在传授错误的知识。
这是我无法忍受的。

言辞上有所冒犯,在这里向您道歉。

这是不是叫做以自身之长驳他人之短哈 ?

FlyWeight pattern is to reduce weight.
What is the weight for an object?
its attributes.

IF there are plenty of objects existing in memory, for example , MS Word,or Tanks in Red Alert, and most of them have some constant or not mutated attributes, then they can be extracted out into one object which is called flyweight object. Because the dublicated attributes used to appear in so many objects and now they are replaced by a reference to a common flyweight object, the total
memory consumption are reduced. that is why the weight is flied.


for the EJB, if it is stateless session bean, then it is almost too light to use flyweight.
if it is stateful session bean, then it consumes more memory.
But the problem is that the EJB container doesnt preview what kind of attributes user will need for the stateful session bean,
that is to say, it is impossible for EJB container to dynamically check all the deployed stateful beans and then re-organize their code structures. in Theory, it is feasible and it could be a competent sale point to beat Weblogic.

but in real life, EJB container can have sth like hashmap or hashtable is already good for us.

讨论就是摆观点,至于对和错,如果无法从经典中得到直接证明,就不能定对和错;对于实践性观点,可以使用代码是否运行,运行性能如何来证明。

我再一些英文资料是看到将Flyweight和Cache/Poll区分,我个人觉得没有意义,其实大道至简,Flyweight模式从字面上就可以知晓,将Weight实现Fly,就是将重的东西飞起来,轻量起来,那么什么是weight呢?无疑耗费内存,影响性能的东西是weight,那么怎么fly飞起来呢?就是将之事先创建在内存中或重用(这只是两种手段,手段方式可以多样,重要结果是fly)。

很多模式著作使用微观例子如Charactre字符等这些例子说明,给人造成的感觉好像Flyweight只限于个别场所,这又忽视了模式的高度性 通用性 和抽象性。

在我们代码中特别是service,主要功能集中其中,代码很长,每次创建就很耗费内存,也就是很weight,那么我们通过使用Pool事先(在服务器启动时)创建这些weight,这就让weight实现fly在内存中了。EJB服务器中对无态session bean和实体Bean都有POOL机制,我们可以在JBoss等服务器配置这个POOL的大小(在jboss/server/default/conf/standardjboss.xml等文件)

Cache则又是一种对很weight的实体进行fly轻量化的处理方式,大数据对象不必每次都从数据库中读取加载到内存中,很耗费内存和浪费性能,所以缓存在内存中。

谈到cache和Pool我们可以想到具体代码产品,而Flyweight是抽象概念,这两者我认为是继承实现关系,之所以是继承,前面已经说了,遵循的都是将weight进行fly的宗旨,但是必须指出,这是我个人观点,说好听一点是创新,或者说不拘泥,现在GOF四人中已经走了一个人,所以,除非他们四人都说这不是继承,不是一回事,才能证明我错的,否则用对和错来衡量纯理论的尺度本身就有问题。

我们的分歧就在这里:我认为cache和Pool作为Flyweight具体实现,是继承关系,当然继承不代表完全相同,抽象和具体还是有区别的。楼主认为则可能认为是完全不相关的或者至少没有继承关系,我想我们各自保留观点吧。

有关POOL及对象生命周期 单例相关话题:
http://www.jdon.com/jivejdon/thread/31851.html

jsp+javabean能否满足100人使用?
http://www.jdon.com/jivejdon/thread/30437.html
[该贴被banq于2007年06月06日 16:29修改过]

比较佩服oxygen 的分析,准确描述了Flyweight模式,和cache,pool的对比也很不错,看完对这些东西有了更深的理解,以前没有把他们放到一起对比过。
banq对Flyweight语义的延伸也说的在理,经过解释也能理解。
不过我觉得模式的作用之一, 就是大家都理解一个特定模式语义,这样我们能提高交流的效率和准确度。 比如说交流的双方都理解flyweight的本来语义,那么只要其中一人说“我们在这里要使用flyweight." 那对方立刻就能明白要说话的这个人要表达的意思。 这种一致的理解在交流的时候是很有价值的。 所以我想最好不要随意延伸一些基本模式的本来原始的语义。虽然很多时候这样的延伸是有道理的。

[该贴被Edgra于2007年06月05日 16:29修改过]

I agree with oxygen. he is right
here flyweight is mainly used for thousands of objects in memory in a certain moment. that is to say, all these objects almost have the same lifecycle.

Pool and Cache are used for group of objects which need to be created and destroyed during a period and each of them have different lifecycle.

设计模式是解决问题的方法的抽象
oxygen 和 banq 是所说的是抽象的实现
我们要面对我们要解决的问题才能知道 有个咋样的实现
正如面向接口编程 我们交流时说是用FLYWEIGHT 难道不看具体的对象 !

>我们交流时说是用FLYWEIGHT 难道不看具体的对象
是的,交流时只要说FLYWEIGHT 就可以,因为模式是大家公认的一个抽象名词,比如,甲和乙说需要一个桌子,乙就已经很明白甲的意思,无需再问是四条腿木头桌子和三条腿石头桌子,因为如果每一次交流都交流得很细时,双方都很累,甲方说:不如我自己做这个桌子了。

所以,模式类似约定的一个词语,它有一个主要意思,如果我们给模式加入很多约束,象数学公式那样,有很多细致的规定,包括context等等都规定很多,那么就失去模式作为交流沟通的一个重要功能,因为模式毕竟不能用数学公式那么严谨表达,很多时候就是望文生义的。

这篇文章挺不错的,个人感觉Oxygen解释的挺有道理。问题就是这样讨论的嘛,这也是我喜欢来Jdon逛的原因。大家都可以自由的表达想法

很佩服 oxygen 的钻研精神 和 认真的态度。 oxygen适合去做科研。

不过想说:

从定义上:
Q1
FlyWeight Use sharing to support large numbers of fine-grained objects efficiently.

The Flyweight pattern describes
how to share objects to allow their use at fine granularities without prohibitive
cost.

fine-grained 的翻译 应当是 “均匀粒度”,也就是字母(对象)出现的频率相差不大。


Q2:
Cost/Performance:
严格上讲, 两者不是一种东西。
不过 国内的教材 通常把两者放在一起。

假设内存足够,limit cost 并不能提高性能。
但在实际上, 内存是有限的, 都是通过 limit cost 来提高性能

[该贴被IceWater于2007年07月07日 00:05修改过]