说明:
相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放。我们只是为了学习而简单做了介绍。

1. 概述

面向对象技术可以很好地解决系统一些灵活性或可扩展性或抽象性的问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。比如:
例子1:图形应用中的图元等对象、字处理应用中的字符对象等。

2.解决方案:

享元模式(Flyweight):对象结构型模式运用共享技术有效地支持大量细粒度的对象。

它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。

4. 适用性

1)一个应用程序使用大量相同或者相似的对象,造成很大的存储开销。

2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。

3)如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。

4) 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

5)使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式

5.结构

6.构建模式的组成

1) 抽象享元类(Flyweight):
描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。
2) 具体享元类(ConcreteFlyweight):实现Flyweight接口 ,并为内部状态( 如果有的话 )增加存储空间
。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。
3) 非共享具体享元类(UnsharedConcreteFlyweight):— 并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
4) 享元工厂类(FlyweightFactory):创建并管理flyweight对象, 确保合理地共享flyweight。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象
 
flyweight的时候,享元工厂角色(Flyweight Factory对象)会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
5)客户(Client):维持一个对flyweight的引用。计算或存储一个(多个)flyweight的外部状态。

7.
效果

享元模式的优点:
1)享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
2)享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
享元模式的缺点:
1)享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
2)为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

8.实现

享元模式可以分成单纯享元模式和复合享元模式两种形式。

【单纯享元模式】

  在单纯的享元模式中,所有的享元对象都是可以共享的。

源代码:

  1. <?php
  2. /**
  3. * 单纯享元模式 
  4. * @author guisu
  5. */
  6. /**
  7. * 抽象享元角色
  8. */
  9. abstract class Flyweight {
  10. /**
  11. * 示意性方法
  12. * @param string $state 外部状态
  13. */
  14. abstract public function operation($state);
  15. }
  16. /**
  17. * 具体享元角色
  18. */
  19. class ConcreteFlyweight extends Flyweight {
  20. private $_intrinsicState = null;
  21. /**
  22. * 构造方法
  23. * @param string $state  内部状态
  24. */
  25. public function __construct($state) {
  26. $this->_intrinsicState = $state;
  27. }
  28. public function operation($state) {
  29. echo 'ConcreteFlyweight operation, Intrinsic State = ' . $this->_intrinsicState
  30. . ' Extrinsic State = ' . $state . '<br />';
  31. }
  32. }
  33. /**
  34. * 享元工厂角色
  35. */
  36. class FlyweightFactory {
  37. private $_flyweights;
  38. public function __construct() {
  39. $this->_flyweights = array();
  40. }
  41. public function getFlyweigth($state) {
  42. if (isset($this->_flyweights[$state])) {
  43. return $this->_flyweights[$state];
  44. } else {
  45. return $this->_flyweights[$state] = new ConcreteFlyweight($state);
  46. }
  47. }
  48. }
  49. class Client{
  50. static function main (){
  51. $flyweightFactory = new FlyweightFactory();
  52. $flyweight = $flyweightFactory->getFlyweigth('state A');
  53. $flyweight->operation('other state A');
  54. $flyweight = $flyweightFactory->getFlyweigth('state B');
  55. $flyweight->operation('other state B');
  56. }
  57. }
  58. ?>

【复合享元模式】
复合享元模式对象是由一些单纯享元使用合成模式加以复合而成
复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。

  1. <?php
  2. /**
  3. * 复合享元模式
  4. *
  5. */
  6. /**
  7. * 抽象享元角色
  8. */
  9. abstract class Flyweight {
  10. /**
  11. * 示意性方法
  12. * @param string $state 外部状态
  13. */
  14. abstract public function operation($state);
  15. }
  16. /**
  17. * 具体享元角色
  18. */
  19. class ConcreteFlyweight extends Flyweight {
  20. private $_intrinsicState = null;
  21. /**
  22. * 构造方法
  23. * @param string $state  内部状态
  24. */
  25. public function __construct($state) {
  26. $this->_intrinsicState = $state;
  27. }
  28. public function operation($state) {
  29. echo 'ConcreteFlyweight operation, Intrinsic State = ' . $this->_intrinsicState
  30. . ' Extrinsic State = ' . $state . '<br />';
  31. }
  32. }
  33. /**
  34. * 不共享的具体享元,客户端直接调用
  35. */
  36. class UnsharedConcreteFlyweight extends Flyweight {
  37. private $_flyweights;
  38. /**
  39. * 构造方法
  40. * @param string $state  内部状态
  41. */
  42. public function __construct() {
  43. $this->_flyweights = array();
  44. }
  45. public function operation($state) {
  46. foreach ($this->_flyweights as $flyweight) {
  47. $flyweight->operation($state);
  48. }
  49. }
  50. public function add($state, Flyweight $flyweight) {
  51. $this->_flyweights[$state] = $flyweight;
  52. }
  53. }
  54. /**
  55. * 享元工厂角色
  56. */
  57. class FlyweightFactory {
  58. private $_flyweights;
  59. public function __construct() {
  60. $this->_flyweights = array();
  61. }
  62. public function getFlyweigth($state) {
  63. if (is_array($state)) { //  复合模式
  64. $uFlyweight = new UnsharedConcreteFlyweight();
  65. foreach ($state as $row) {
  66. $uFlyweight->add($row, $this->getFlyweigth($row));
  67. }
  68. return $uFlyweight;
  69. } else if (is_string($state)) {
  70. if (isset($this->_flyweights[$state])) {
  71. return $this->_flyweights[$state];
  72. } else {
  73. return $this->_flyweights[$state] = new ConcreteFlyweight($state);
  74. }
  75. } else {
  76. return null;
  77. }
  78. }
  79. }
  80. class Client{
  81. static function main (){
  82. $flyweightFactory = new FlyweightFactory();
  83. $flyweight = $flyweightFactory->getFlyweigth('state A');
  84. $flyweight->operation('other state A');
  85. $flyweight = $flyweightFactory->getFlyweigth('state B');
  86. $flyweight->operation('other state B');
  87. /* 复合对象*/
  88. $uflyweight = $flyweightFactory->getFlyweigth(array('state A', 'state B'));
  89. $uflyweight->operation('other state A');
  90. }
  91. }
  92. ?>

9.
与其他相关模式

客户端要引用享元对象,是通过工厂对象创建或者获得的,客户端每次引用一个享元对象,都是可以通过同一个工厂对象来引用所需要的享元对象。因此,可以将享元工厂设计成单例模式,这样就可以保证客户端只引用一个工厂实例。因为所有的享元对象都是由一个工厂对象统一管理的,所以在客户端没有必要引用多个工厂对象。不管是单纯享元模式还是复合享元模式中的享元工厂角色,都可以设计成为单例模式,对于结果是不会有任何影响的。

Composite模式:Flyweight模式通常和Composite 模式结合起来,用共享叶结点的有向无环图实现一个逻辑上的层次结构。复合享元模式实际上是单纯享元模式与合成模式的组合。单纯享元对象可以作为树叶对象来讲,是可以共享的,而复合享元对象可以作为树枝对象, 因此在复合享元角色中可以添加聚集管理方法。通常,最好用Flyweight实现State
和Strategy 对象。

10.总结

1)  享元模式是一个考虑系统性能的设计模式,通过使用享元模式可以节约内存空间,提高系统的性能。 
2)  享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享 元池中不存在,则创       建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
3)   享元模式以共享的方式高效地支持大量的细粒度对象,享元对象能做到共享的关键是区分内部状态(Internal State)和外部状态(External State)。
       (1)   内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态可以共享。
 
       (2)   外部状态是随环境改变而改变的、不可以共享的状态。享元对象的外部状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候 再传入到享元对               象内部。一个外部状态与另一个外部状态之间是相互独立的。
 
 
 
参考:http://blog.csdn.net/hguisu/article/details/7535792。

设计模式(十二): Flyweight享元模式 -- 结构型模式的更多相关文章

  1. Flyweight 享元(结构型)

    一:描述:(该模式实际应用较少) Flyweight 享元模式是对大量细粒度的元素进行共享和重用.减少对象的创建减轻内存: 注和单例模式不同的是:享元模式的各个对象佣有各自的行为并可实例化,单例模式的 ...

  2. 设计模式(十二)享元模式(Flyweight Pattern)

    一.引言 在软件开发过程,如果我们需要重复使用某个对象的时候,如果我们重复地使用new创建这个对象的话,这样我们在内存就需要多次地去申请内存空间了,这样可能会出现内存使用越来越多的情况,这样的问题是非 ...

  3. 设计模式11: Flyweight 享元模式(结构型模式)

    Flyweight 享元模式(结构型模式) 面向对象的代价 面向对象很好的解决了系统抽象性的问题,同时在大多数情况下也不会损及系统的性能.但是,在某些特殊应用中,由于对象的数量太大,采用面向对象会给系 ...

  4. 二十、Flyweight 享元模式

    原理: 代码清单: BigChar public class BigChar { //字符名称 private char charname; //大型字符 # . \n 组成 private Stri ...

  5. Flyweight享元模式(结构型模式)

    1.面向对象的缺点 虽然OOP能很好的解决系统抽象的问题,并且在大多数的情况下,也不会损失系统的性能.但是在某些特殊的业务下,由于对象的数量太多,采用面向对象会给系统带来难以承受的内存开销.示例代码如 ...

  6. 设计模式之美:Structural Patterns(结构型模式)

    结构型模式涉及到如何组合类和对象以获得更大的结构. 结构型类模式采用继承机制来组合接口实现. 结构型对象模式不是对接口和实现进行组合,而是描述了如何对一些对象进行组合,从而实现新功能的一些方法. 因为 ...

  7. 代理模式/proxy模式/结构型模式

    代理模式proxy 定义 为其他对象提供一种代理,并以控制对这个对象的访问.最简单的理解,买东西都是要去商店的,不会去工厂. java实现三要素 proxy(代理)+subject(接口)+realS ...

  8. 设计模式之(十二)享元模式(Flyweight)

    享元模式思想 就以小时候导锅来说吧(导锅是我家乡的方言,就是用细沙把一个模型锅的形状拓下来,然后把铝水倒进模型中,就导好一个锅了.小时候很喜欢看的,可惜现在看不到了.上个图片回忆下)了解了这个过程后就 ...

  9. 十二、享元(Flyweight)模式--结构模式(Structural Pattern)

    Flyweight在拳击比赛中指最轻量级,即"蝇量级",有些作者翻译为"羽量级".这里使用"享元 模式"更能反映模式的用意. 享元模式以共享 ...

随机推荐

  1. python network programming tutorial

    关于网络编程以及socket 等一些概念和函数介绍就不再重复了,这里示例性用python 编写客户端和服务器端. 一.最简单的客户端流程: 1. Create a socket 2. Connect ...

  2. 日积月累:ProguardGui进行jar包代码混淆

    前面文章<Proguard进行源代码混淆>讲解过怎么使用Proguard工具对Android的源代码进行混淆的方法(感兴趣的朋友可以访问:http://blog.csdn.net/p106 ...

  3. <微软的软件测试之道>读书笔记3

    一.自动化的标准步骤: 1.环境初始化,并检查环境是否处于正确的状态,能否开始测试 2.执行步骤 3.判断结果,并将结果保存到其它地方以供检查分析 4.环境清理,清理本用例产生的垃圾(临时文件.环境变 ...

  4. (2)入门指南——(2)jQuery可以做什么(What jQuery does)

    The jQuery library provides a general-purpose abstraction layer for common web scripting, and is, th ...

  5. java Serializable和Externalizable序列化反序列化详解--转

    一.什么是序列化? “对象序列化”(Object Serialization)是 Java1.1就开始有的特性. 简单地说,就是可以将一个对象(标志对象的类型)及其状态转换为字节码,保存起来(可以保存 ...

  6. 在PHP中使用CURL,“撩”服务器只需几行——php curl详细解析和常见大坑

    在PHP中使用CURL,"撩"服务器只需几行--php curl详细解析和常见大坑 七夕啦,作为开发,妹子没得撩就"撩"下服务器吧,妹子有得撩的同学那就左拥妹子 ...

  7. ASP.NET数据绑定控件简介

    •数据绑定分为数据源和数据绑定控件两部分(①数据绑定控件通过数据源获取和修改数据②数据绑定控件通过数据源隔离数据提供者和数据使用者)数据绑定控件→数据源→数据库•数据源:SqlDataSource(连 ...

  8. UGUI之UI的深度问题

    学过NGUI的都知道,NGUI的深度是通过值来控制的.Panel也是UI也是,如果空间太多,布局复杂UI深度的值会变得很混乱.所以在NGUI中设置UI深度时一定要多加思考.然而在UGUI控制显示顺序的 ...

  9. PartialViewResult用法

    后台代码 ) { IList<TestModel> lstTestModel = this.GetModelList(categoryid); return PartialView(lst ...

  10. HTTP Content-type 对照表

    文件扩展名 Content-Type(Mime-Type) 文件扩展名 Content-Type(Mime-Type) .*( 二进制流) application/octet-stream .tif ...