###享元模式
享元模式最适合于解决因创建大量类似对象而累及性能的问题。这种模式在Javascript中尤其有用,因为复杂的Javascript代码可能很快就会用光浏览器的所有可用内存。通过把大量独立对象转化为少量共享对象,可以降低运行Web应用程序所需的资源数量。对于那些可能一连用上几天也不会重新加载的大型应用系统,任何减少内存用量的技术都有非常显著的效果。而对于那些不会在浏览器中打开那么长时间的小型网页,内存的节约就没那么重要。
示例:汽车登记
内在状态和外在状态,用工厂进行实例化内在状态,封装在管理器中的外在状态。
example
用单例来做封装这些数据的管理器优化方法是以复杂性为代价的。原有的只是一个类,而现在却变成了一个类和两个单例对象。
1、管理外在状态:
使用管理器对象进行管理。这种对象有一个集中管理的数据库,用于存放外在状态及其所属的享元对象。汽车登记那个实力就采用了这种方案。其优点在于简单、容易维护。
使用组合模式进行管理。可以使用对象自身的层次体系来保存信息,而不需要另外使用一个集中管理的数据库。组合对象的叶节点全都可以是享元对象,这样一来这些享元对象可以在组合对象层次体系中的多个地方被共享。
2、示例:Web日历
创建一个Web日历,演示用组合对象保存外在状态的具体做法。
没有把日期对象转换为享元的问题:你不得不为每一年创建365个CalendarDay对象。如果对象数目太多了,会给浏览器带来资源压力。更有效的做法是无论日历要显示多少年,都只用了一个CalendarDay对象来代表所有日期。所有把日期对象转换为享元进行优化。
example
3、外在数据保存在哪里
组合对象的结构本身就已经包含了所有的外在数据。由于月份对象中的日期对象依次存放在一个数组中,所以它知道每一个日期对象的状态,从CalendarDay构造函数中剔除的两种数据都已经存在于CalendarMonth对象中。
这就是组合模式与享元模式配合得如此完美的原因。组合对象通常拥有大量叶对象,它还保存着许多可作为外在数据处理的数据。叶对象通常只包含极少的内在数据,所以很容易被转化为共享资源。
4、示例:
工具提示对象
在Javascript对象需要创建HTML内容这种情况下,享元模式特别有用。那种会生成DOM元素的对象如果数目众多的话,会占用过多内存,使网页陷入泥沼。采用享元模式后,只需创建少许这种对象即可,所有需要这种对象的地方都可以共享它们。工具提示就是一个典型的例子。
5、存实例供以后重用
模式对话框是享元模式的另一个适用场合。与工具提示一样,对话框对象也封装着数据和HTML内容。
因为运行期间需要用到的实例数目无法确定,所以不能对实例的个数加以限制,只能要用多少就创建多少,然后把它们保存起来供以后使用。
DialogBox的例子
6、享元模式的适用场合:
网页中必须使用了大量资源密集型对象。如果只会用到少许这类对象,这种优化并不划算。
对象中所保存的数据至少有一部分能被转化为外在数据。此外,将这些数据存储在对象外部所占用的资源应该相对较少,否则这种做法对于性能的提示实际上毫无意义。那种大量包含基础性代码和HTML内容的对象可能比较适合这种优化。
将外在数据分离出去后,独一无二的对象的数目相对较少。
7、实现享元模式的一般步骤:
将所有外在数据从目标类剥离。具体做法是尽可能多地删除该类的属性,所删除的应该是那种因实例而异的属性。构造参数也要这样处理。这些参数应该被添加到该类的各个方法。
创建一个用来控制该类的实例化的工厂。用一个对象字面量保存每一个这类对象的引用,并以用来生成这些对象的参数的唯一性组合作为它们的索引。另一种方法是对象池技术。
创建一个用来保存外在数据的管理器。外在数据被保存在管理器内的一个数据结构中。管理器随后会根据需要将这些数据提供给共享对象的方法,其效果就如同该类有许多实例一样。
8、享元模式之利:
可以把网页的资源符合降低几个数量级。即使享元模式的应用无法将实例的个数削减到一个,你仍能够从中获益不少。
这种节省不需要大量修改原有代码。在创建了管理器、工厂和享元之后,就需要对代码进行的修改只不过是从直接实例化目标类改为调用管理器对象的某个方法。
9、享元模式之弊:
如果把它用在不必要的地方,其结果反而有损代码的运行效率。这种模式在优化代码的同时,也提高了其复杂程度,这会给调试和维护造成困难。
它之所以会妨碍调试,是因为现在可能出错的地方变成了三个:管理器、工厂和享元。
这种优化也会使维护变得更加困难。现在你面对的不是由封装着数据的对象构成的清晰架构,而是一堆又碎又乱的东西。其中的数据至少分两处保存。最好注释标明内在数据和外在数据。
只有在必要的时候才应该进行这种优化。必须在运行效率和可维护性之间进行权衡。如果拿不准是否需要使用享元模式,那么你很可能并不需要它。享元模式适合的是系统资源已经用得差不多而且明显需要进行某种优化这样一类场合。
这种模式对Javascript程序员特别有用,因为它可以用来减少网页上所要使用的DOM元素的数量,要知道这些元素需要耗费许多内存。结合使用这种模式与组合模式等组织型可以开发出功能丰富的复杂Web应用系统,它们可以平稳的运行在任何现代Javascript环境中。