享元模式(Flyweight Pattern)

来源:互联网 发布:fft算法的dsp实现 编辑:程序博客网 时间:2024/05/15 09:04

享元模式在编辑器系统中大量使用。一个文本编辑器往往会提供很多种字体,而通常的做法就是将每一个字母做成一个享元对象。享元对象的内蕴状态就是这个字母,而字母在文本中的位置和字模风格等其他信息则是外蕴状态。比如,字母a可能出现在文本的很多地方,虽然这些字母a的位置和字模风格不同,但是所有这些地方使用的都是同一个字母对象。这样一来,字母对象就可以在整个系统中共享。

在单纯享元模式中,所有的享元对象都是可以共享的。单纯享元模式所涉及的角色如下:

抽象享元(Flyweight)角色:此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口。那些需要外蕴状态(External State)的操作可以通过调用商业方法以参数形式传入。

具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享的。

享元工厂(FlyweightFactory)角色:本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个复合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。

客户端(Client)角色:本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外蕴状态。

单纯享元模式的示意性源代码 

// Flyweight pattern -- Structural example  
using System;
using System.Collections;

// "FlyweightFactory"
class FlyweightFactory
{
    
// Fields
    private Hashtable flyweights = new Hashtable();

    
// Constructors
    public FlyweightFactory()
    
{
        flyweights.Add(
"X"new ConcreteFlyweight());
        flyweights.Add(
"Y"new ConcreteFlyweight());
        flyweights.Add(
"Z"new ConcreteFlyweight());
    }


    
// Methods
    public Flyweight GetFlyweight(string key)
    
{
        
return ((Flyweight)flyweights[key]);
    }

}


// "Flyweight"
abstract class Flyweight
{
    
// Methods
    abstract public void Operation(int extrinsicstate);
}


// "ConcreteFlyweight"
class ConcreteFlyweight : Flyweight
{
    
private string intrinsicstate = "A";
    
// Methods
    override public void Operation(int extrinsicstate)
    
{
        Console.WriteLine(
"ConcreteFlyweight: intrinsicstate {0}, extrinsicstate {1}",
          intrinsicstate, extrinsicstate);
    }

}


/**/
/// <summary>
/// Client test
/// </summary>

public class Client
{
    
public static void Main(string[] args)
    
{
        
// Arbitrary extrisic state
        int extrinsicstate = 22;

        FlyweightFactory f 
= new FlyweightFactory();

        
// Work with different flyweight instances
        Flyweight fx = f.GetFlyweight("X");
        fx.Operation(
--extrinsicstate);

        Flyweight fy 
= f.GetFlyweight("Y");
        fy.Operation(
--extrinsicstate);

        Flyweight fz 
= f.GetFlyweight("Z");
        fz.Operation(
--extrinsicstate);
    }

}

 

享元模式应当在什么情况下使用

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

  • 一个系统有大量的对象。
  • 这些对象耗费大量的内存。
  • 这些对象的状态中的大部分都可以外部化。
  • 这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。
  • 软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。

满足以上的这些条件的系统可以使用享元对象。

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

享元模式的优点和缺点

享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:

  • 享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
  • 享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。