php专区

 首页 > php专区 > PHP进阶 > 设计模式 > 设计模式之享元模式(Flyweight Pattern)

设计模式之享元模式(Flyweight Pattern)

分享到:
【字体:
导读:
         摘要:面向对象很好地解决了系统抽象性的问题,同时在大多数情况下,也不会损及系统的性能。但是,在 某些特殊的应用中下,由于对象的数量太大...

设计模式之享元模式(Flyweight Pattern)
面向对象的代价

面向对象很好地解决了系统抽象性的问题,同时在大多数情况下,也不会损及系统的性能。但是,在
某些特殊的应用中下,由于对象的数量太大,采用面向对象会给系统带来难以承受的内存开销。比如:
图形应用中的图元等对象、字处理应用中的字符对象等。 
    
                        
动机(Motivate):


采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价--------主要指内存需求方面的代价。
如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?


意图(Intent):


运用共享技术有效地支持大量细粒度的对象。  -------《设计模式》GOF

                  
适用性:   

当以下所有的条件都满足时,可以考虑使用享元模式:


1、   一个系统有大量的对象。

2、   这些对象耗费大量的内存。

3、   这些对象的状态中的大部分都可以外部化。

4、   这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。

5、   软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。



满足以上的这些条件的系统可以使用享元对象。最后,使用享元模式需要维护一个记录了系统已有的所有享元的表,而这需要耗费资源。因此,应当在有足够多的享元实例可供共享时才值得使用享元模式。


生活中的例子:

享元模式使用共享技术有效地支持大量细粒度的对象。公共交换电话网(PSTN)是享元的一个例子。有一些资源例如拨号音发生器、振铃发生器和拨号接收器是必须由所有用户共享的。当一个用户拿起听筒打电话时,他不需要知道使用了多少资源。对于用户而言所有的事情就是有拨号音,拨打号码,拨通电话。 
                    

代码实现


Flyweight在拳击比赛中指最轻量级,即“蝇量级”,这里翻译为“享元”,可以理解为共享元对象(细粒度对象)的意思。提到Flyweight模式都会一般都会用编辑器例子来说明,这里也不例外,但我会尝试着通过重构来看待Flyweight模式。考虑这样一个字处理软件,它需要处理的对象可能有单个的字符,由字符组成的段落以及整篇文档,根据面向对象的设计思想和Composite模式,不管是字符还是段落,文档都应该作为单个的对象去看待,这里只考虑单个的字符,不考虑段落及文档等对象,于是可以很容易的得到下面的结构图:
                  

 1 // "Charactor"
 2 public abstract class Charactor
 3 {
 4     //Fields
 5     protected char _symbol;
 6 
 7     protected int _width;
 8 
 9     protected int _height;
10 
11     protected int _ascent;
12 
13     protected int _descent;
14 
15     protected int _pointSize;
16 
17     //Method
18     public abstract void Display();
19 }
20 
21 // "CharactorA"
22 public class CharactorA : Charactor
23 
24     // Constructor 
25     public CharactorA()
26     {
27       this._symbol = 'A';
28       this._height = 100;
29       this._width = 120;
30       this._ascent = 70;
31       this._descent = 0;
32       this._pointSize = 12;
33     }
34 
35     //Method
36     public override void Display()
37     {
38         Console.WriteLine(this._symbol);
39     }
40 }
41 
42 // "CharactorB"
43 public class CharactorB : Charactor
44 {
45     // Constructor 
46     public CharactorB()
47     {
48         this._symbol = 'B';
49         this._height = 100;
50         this._width = 140;
51         this._ascent = 72;
52         this._descent = 0;
53         this._pointSize = 10;
54     }
55 
56     //Method
57     public override void Display()
58     {
59         Console.WriteLine(this._symbol);
60     }
61 }
62 
63 // "CharactorC"
64 public class CharactorC : Charactor
65 {
66     // Constructor 
67     public CharactorC()
68     {
69         this._symbol = 'C';
70         this._height = 100;
71         this._width = 160;
72         this._ascent = 74;
73         this._descent = 0;
74         this._pointSize = 14;
75     }
76 
77     //Method
78     public override void Display()
79     {
80         Console.WriteLine(this._symbol);
81     }
82 }


好了,现在看到的这段代码可以说是很好地符合了面向对象的思想,但是同时我们也为此付出了沉重的代价,那就是性能上的开销,可以想象,在一篇文档中,字符的数量远不止几百个这么简单,可能上千上万,内存中就同时存在了上千上万个Charactor对象,这样的内存开销是可想而知的。进一步分析可以发现,虽然我们需要的Charactor实例非常多,这些实例之间只不过是状态不同而已,也就是说这些实例的状态数量是很少的。所以我们并不需要这么多的独立的Charactor实例,而只需要为每一种Charactor状态创建一个实例,让整个字符处理软件共享这些实例就可以了。
                     
现在我们看到的ABC三个字符是共享的,也就是说如果文档中任何地方需要这三个字符,只需要使用共享的这三个实例就可以了。然而我们发现单纯的这样共享也是有问题的。虽然文档中的用到了很多的A字符,虽然字符的symbol等是相同的,它可以共享;但是它们的pointSize却是不相同的,即字符在文档中中的大小是不相同的,这个状态不可以共享。为解决这个问题,首先我们将不可共享的状态从类里面剔除出去,即去掉pointSize这个状态(只是暂时的J),:
        

 1 // "Charactor"
 2 public abstract class Charactor
 3 {
 4     //Fields
 5     protected char _symbol;
 6 
 7     protected int _width;
 8 
 9     protected int _height;
10 
11     protected int _ascent;
12 
13     protected int _descent;
14 
15     //Method
16     public abstract void Display();
17 }
18 
19 // "CharactorA"
20 public class CharactorA : Charactor
21 {
22     // Constructor 
23     public CharactorA()
24     {
25         this._symbol = 'A';
26         this._height = 100;
27         this._width = 120;
28         this._ascent = 70;
29         this._descent = 0;
30     }
31 
32     //Method
33     public override void Display()
34     {
35         Console.WriteLine(this._symbol);
36     }
37 }
38 
39 // "CharactorB"
40 public class CharactorB : Charactor
41 {
42     // Constructor 
43     public CharactorB()
44     {
45         this._symbol = 'B';
46         this._height = 100;
47         this._width = 140;
48         this._ascent = 72;
49         this._descent = 0;
50     }
51 
52     //Method
53     public override void Display()
54     {
55         Console.WriteLine(this._symbol);
56     }
57 }
设计模式之享元模式(Flyweight Pattern)


  • 打酱油

  • 震惊

  • 呵呵


  • 鄙视
标签标签:PHP ,CSS数据库 ,优化
分享到:
设计模式中的外观模式(Facade Pattern)
设计模式中的外观模式(Facade Pattern) 动机(Motivate):     在软件开发系统中,客户程序经常会与复杂系统的内部子系统之间产生耦合,而导致客户程序随着子系统的变化而变化。那么如何简化客户程序与子系统之间的交互接口?如何将复杂系统的内部子系统与客户程序之间的依赖解耦? 意图(Intent):    为子系...
设计模式之-建造者模式(Builder)
设计模式之-建造者模式(Builder) Builder模式的缘起:     假设创建游戏中的一个房屋House设施,该房屋的构建由几部分组成,且各个部分富于变化。如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正.....动机(Motivation):     在软件系统中,有时候面临一个"复杂对象"的创建工作,其通...
  •         php迷,一个php技术的分享社区,专属您自己的技术摘抄本、收藏夹。
  • 在这里……