设计模式之享元模式

名词解释:

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

必要元素:

1.一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在);
2.所有具体享元类的父类或接口,通过这个接口,Flyweight可以接受并作用于外部状态;
3.继承Flyweight父类或者实现Flyweight接口,并为内部状态增加存储空间;
4.指那些不需要共享的Flyweight子类,因为Flyweight接口共享成为可能,但是并不强制共享(即那些不能共享的部分)。

上例子:

Flyweight享元抽象类:

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

Flyweight具体共享类:

  class ConcreteFlyweight:Flyweight
    {
        public override void Operation(int extrinsicstate)
        {
            Console.WriteLine("具体Flyweight:"+extrinsicstate);
        }
    }

 class UnsharedConcreteFlyweight:Flyweight
    {
        public override void Operation(int extrinsicstate)
        {
            Console.WriteLine("不共享的具体Flyweight:"+extrinsicstate);
        }
    }

享元工厂:

  class FlyweightFactory
    {
        private Dictionary<string, Flyweight> flyweights = new Dictionary<string, Flyweight>();
        public FlyweightFactory()
        {
            flyweights.Add("X", new ConcreteFlyweight());
            flyweights.Add("Y", new ConcreteFlyweight());
            flyweights.Add("Z", new ConcreteFlyweight());
        }

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

调用:

            //外部状态
          int extrinsicstate = 22;

            FlyweightFactory factory = new FlyweightFactory();

            Flyweight fx = factory.GetFlyweight("X");
            fx.Operation(--extrinsicstate);

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

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

            Flyweight uf = new UnsharedConcreteFlyweight();
            uf.Operation(--extrinsicstate);

            Console.Read();    

 通过享元类父类和子类(共享和非共享部分)以及享元类工厂,构成了享元模式,这样在使用的时候就不会创建多次对象,有效的利用资源。

 例子2(假设有一个网站类,而网站有很多种类型):

抽象类:

  /// <summary>
    /// 网站抽象类
    /// </summary>
    abstract class WebSite
    {
        public abstract void Use();
    }

具体网站类:

 /// <summary>
    /// 具体网站类
    /// </summary>
    class ConcreteWebSite:WebSite
    {
        private string name = "";
        public ConcreteWebSite(string name)
        {
            this.name = name;
        }

        public override void Use()
        {
            Console.WriteLine("网站分类:"+name);
        }
    }

网站工厂类:

 /// <summary>
    /// 网站工厂
    /// </summary>
    class WebSiteFactory
    {
        private Dictionary<string, WebSite> flyweights = new Dictionary<string, WebSite>();
        /// <summary>
        /// 获得网站分类
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public WebSite GetWebSite(string key)
        {
            if (!flyweights.ContainsKey(key))
            {
                flyweights.Add(key, new ConcreteWebSite(key));
            }
            return flyweights[key];
        }

        public int GetWebSiteCount()
        {
            return flyweights.Count;
        }
    }

使用:

           WebSiteFactory factory = new WebSiteFactory();

            WebSite fx = factory.GetWebSite("产品展示");
            fx.Use();

            WebSite fy = factory.GetWebSite("产品展示");
            fy.Use();

            WebSite fz = factory.GetWebSite("产品展示");
            fz.Use();

            WebSite fl = factory.GetWebSite("博客");
            fl.Use();

            WebSite fm = factory.GetWebSite("博客");
            fm.Use();

            WebSite fn = factory.GetWebSite("博客");
            fn.Use();

            Console.WriteLine("共有网站{0}个",factory.GetWebSiteCount());
            Console.Read();    

这样设计基本实现了享元模式的共享对象的目的,也就是说不管创建几个网站,只要是某一类型(博客或者其他),都是完全相同的,但是问题又来了,不同公司的网站应该有不同的账号,所以我们只是体现了共享的部分,还有非共享部分等待我们实现。
实例2(集成非共享代码):

 外部状态类(User类):

   /// <summary>
    /// 用户类(外部状态)
    /// </summary>
    class User
    {
        private string name;

        public string Name
        {
            get { return name; }
        }

        public User(string name)
        {
            this.name = name;
        }
    }

抽象网站类:

  /// <summary>
    /// 网站抽象类
    /// </summary>
    abstract class WebSite
    {
        public abstract void Use(User user);
    }

方法增加了参数,参数为外部状态对象User。


具体网站类:

  /// <summary>
    /// 具体网站类
    /// </summary>
    class ConcreteWebSite:WebSite
    {
        private string name = "";
        public ConcreteWebSite(string name)
        {
            this.name = name;
        }

        public override void Use(User user)
        {
            Console.WriteLine("网站分类:"+name+" 用户:"+user.Name);
        }
    }

变化也是User函数添加User对象参数。

工厂:无变化。

使用:

        WebSiteFactory factory = new WebSiteFactory();

            WebSite fx = factory.GetWebSite("产品展示");
            fx.Use(new User("Colors"));

            WebSite fy = factory.GetWebSite("产品展示");
            fy.Use(new User("Blue"));

            WebSite fz = factory.GetWebSite("产品展示");
            fz.Use(new User("Listen"));

            WebSite fl = factory.GetWebSite("博客");
            fl.Use(new User("Colors.Blue"));

            WebSite fm = factory.GetWebSite("博客");
            fm.Use(new User("Listen.Fly"));

            WebSite fn = factory.GetWebSite("博客");
            fn.Use(new User("李莫愁"));

            Console.WriteLine("共有网站{0}个",factory.GetWebSiteCount());
            Console.Read();

这样虽然是同一个类型的网站,但是有了User这个外部状态对象,所以就可以把内部状态与外部状态很好的结合。

 

总结:

 如果一个应用程序使用了大量的对象,而大量的对象造成了很大的存储开销时就应该考虑使用享元模式;对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元对象。在实际应用中,使用了享元模式实例总数就大大减少了。

 

 

posted @ 2013-09-24 21:08  wangyafei_it  阅读(293)  评论(0编辑  收藏  举报