摘要:本文深入浅出的讲述了设计模式中的享元模式 , 并给出了简单的示例 , 例子浅显易懂 , 并附带源代码。 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

       享元 模式属于结构型模式,其意图是运用共享技术有效地支持大量细粒度的对象。有些应用程序得益于在其整个设计过程中采用面向对象技术,但是简单化的实现代价极大。flyweight是一个共享对象,它可以同时在多个场景中使用,并且每个场景中Flyweight队作为一个独立的对象,这一点与非共享对象的实例没有区别,Flyweight不能对他所运行的场景作出任何假设,这里的关键概念是内部状态和外部状态之间的区别。内部状态存储于Flyweight中,它包含了独立Flyweight场景的信息,这些信息使得Flyweight可以被共享,而外部状态取决于 Flyweight场景,并根据场景而变化,因此不可共享,用户对象负责在必要的时候将外部状态传递给FlyweightFlyweight模式对那些通常因为数量太大而难以用对象来表示的概念或者实体建立模型。

       适用性:Flyweight模式的有效性很大程度上取决于如何使用它以及在何处使用它,当以下情况都成立时使用Flyweight模式。

l         一个应用程序使用了大量的对象,

l         完全有余使用了大量的对象,造成了很大的存储开销。

l         对象的大多数状态都可以变为外部状态。

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

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

 

参与者:       

       Flyweight: 描述一个接口,通过这个接口 flyweight 可以接受并作用于外部状态。

       ConcreteFlyweight(MyImage) :实现 flyweight 接口,并为内部状态增加存储空间。 ConcreteFlyweight 对象必须是可以共享的,它所存储的状态必须是内部的。即:它必须独立于 ConcreteFlyweight 对象的场景 .

UnsharedConcreteFlyweight: 并非所有的 Flyweight 子类都需要被共享。 Flyweight 接口使共享成为可能,但它并不强制共享,在 Flyweight 对象结构的某些层次, UnsharedConcreteFlyweight 对象通常将 ConcreteFlyweight 对象作为子节点。

FlyweightFactory(MyImageFactory) :创建并管理 Flyweight 对象。确保合理的共享 Flyweight 。当用户请求一个 flyweight 时, FlyweightFactory 对象提供一个已经创建的实例或者创建一个。

Client :维持一个对 Flyweight 的引用。计算或者存储一个(多个) flyweight 的外部状态。 Flyweight 执行时所需要的状态必定是内部的或者外部的状态,内部状态存储于 ConcreteFlyweight 对象中,而外部对象则由 Client 对象存储或计算,当用户调用 flyweight 对象的操作时,将该状态传递给他。用户不应直接对 ConcreteFlyweight 类进行实例化,而只能从 FlyweightFactory 对象得到 ConcreteFlyweight 对象,这可以保证对他们适当的进行共享。

本人认为 Flyweight 模式的核心就是把大量共享的对象收集在一起使用简单工厂模式进行管理,避免由于大量的小对象导致系统的内存过渡消耗。下面是一个简单的例子,例子不是很好,并不能显示 Flyweight 模式的所有特征。

客户端需要图片,从 MyImageFactory 中取得,如果 MyImageFactory 存储的 Image 中没有需要的图片 , 便创建一个,并把创建的图片存储在保留 Flyweight 的数组中,以便于下次直接获取。

相应的代码:

MyImage 的代码:

       package flyweight;

import java.awt.*;

import java.awt.p_w_picpath.*;

import java.io.*;

public class MyImage{

    private Image p_w_picpath ;

    public MyImage(String file){

       Toolkit toolkit = Toolkit.getDefaultToolkit();  

       File f = new File(file);

       if (f.exists()){

           p_w_picpath = toolkit.getImage(file);

       }

       else {

           System. out .println( "File unable to load!" );

       }

    }

    public void draw(Graphics g, int x, int y,String name,ImageObserver obs){

       g.drawImage( p_w_picpath ,x,y,30,30,obs);

       g.drawString(name,x,y+40);

    }

}

MyImageFactory 的代码:

package flyweight;

public class MyImageFactory{

    MyImage[] p_w_picpaths ;

    public MyImageFactory(){

       p_w_picpaths = new MyImage[3];

       for ( int i=0;i<3;i++)

           p_w_picpaths [i]= new MyImage( "flyweight/lili" +i+ ".gif" );

    }

    public MyImage getMyImage( int i){

       return p_w_picpaths [i];

    }

}

 

 

Client 代码:

package flyweight;

import javax.swing.*;

import java.awt.*;

public class Client extends JFrame{

       private MyImageFactory factory;

       private String[] names;

       public Client(){

              super("Flyweight sample");

              factory = new MyImageFactory();

              setSize(220,300);

              setVisible(true);

              repaint();

              names = new String[]{"pig","dog","cat"};

       }

       public void resize(){

              repaint();

       }

       public void paint(Graphics g){

              g.clearRect(0,0,getWidth(),getHeight());

              String name;

              for(int i=0;i<5;i++){

                     for(int j=0;j<5;j++){

                            int number=(int)(Math.random()*3%3);

                            MyImage myImage = factory.getMyImage(number);

                            number=(int)(Math.random()*3%3);

                            name = names[number];

                            myImage.draw(g,10+i*40,45+j*45,name,this);

                     }

              }

       }

       public static void main(String[] args){

              new Client();

       }

}

总结: Flyweight 的目标是尽量减少大量可以被共享的对象的数目,并把可变的与不可变得状态使用内部状态 (Flyweight) 与外部状态区分开来。