C#设计模式-享元模式

前言

最近开始花点心思研究下设计模式,主要还是让自己写的代码可重用性高、保证代码可靠性。所谓设计模式,我找了下定义:是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

为什么要提倡“Design Pattern(设计模式)”?

根本原因是为了代码复用,增加可维护性。因此这次我们来学习下设计模式,最后会通过C#语言来实现这些设计模式作为例子,深刻理解其中的精髓。

定义

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

之前讲到的单例模式,一个类只有一个唯一的对象,也就是说,不管new多少次,只需要创建这个类的一个对象,如果不采用单例模式,每new一次,就会创建一个对象,便会产生大量重复的对象,而这些对象要消耗很大的资源的时候,是会产生资源互抢的延迟的。这个时候享元模式就能帮忙解决这类的问题。

特点

享元模式的意图是通过共享有效支持大量细粒度的对象,来提供应用程序的性能,节省系统中重复创建对象实例的性能消耗,这个怎么理解呢?其实就是以下几点的含义:

1、当我们系统中某个对象类型的实例较多的情况。

2、并且要求这些实例进行分类后,发现真正有区别的分类很少的情况。

例如我们的生活中很多的场景,我们在使用拼音输入的法的时候,如果说我们每个字都是new一个对象实例的操作的话,那么内存中的实例就太可怕,这个时候,我们是不是可以考虑将这些重复的字体在内存中只是创建一次,而是通过复用对象的形式,来组织一些可能有多个字符重复的内容呢?

优缺点

优点:

一、

降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。

缺点:

一、

为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑更复杂,使系统复杂化。

二、

享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。

实现思路

享元模式就是把部分和整体的关系用树形结构来表示,从而使客户端能够把一个个的部分对象和由它们组合起来的整体对象采用同样的方式来对待。享元模式主要由3部分组成:享元类,具体的享元类,享元工厂类。

#region 客户端调用
    /// <summary>
    /// 客户端调用
    /// </summary>
    class Client
    {
        static void Main(string[] args)
        {
            // 初始化享元工厂
            FlyweightFactory factory = new FlyweightFactory();

            // 判断是否已经创建了对象1,如果已经创建就直接使用创建的对象
            Flyweight fa = factory.GetFlyweight(0);
            if (fa != null)
            {
                // 把外部状态作为享元对象的方法调用参数
                fa.Operation();
            }
            // 判断是否已经创建了字母B
            Flyweight fb = factory.GetFlyweight(1);
            if (fb != null)
            {
                fb.Operation();
            }
            // 判断是否已经创建了字母C
            Flyweight fc = factory.GetFlyweight(2);
            if (fc != null)
            {
                fc.Operation();
            }
            // 判断是否已经创建了字母D
            Flyweight fd = factory.GetFlyweight(3);
            if (fd != null)
            {
                fd.Operation();
            }
            else
            {
                Console.WriteLine("驻留池中不存在对象4");
                // 这时候就需要创建一个对象并放入驻留池中
                ConcreteFlyweight d = new ConcreteFlyweight("第四个对象");
                factory.flyweights.Add(d);
            }

            Console.Read();
        }
    }
    #endregion

    #region 享元工厂,负责创建和管理享元对象
    /// <summary>
    /// 享元工厂,负责创建和管理享元对象
    /// </summary>
    public class FlyweightFactory
    {
        public List<Flyweight> flyweights = new List<Flyweight>();

        public FlyweightFactory()
        {
            flyweights.Add(new ConcreteFlyweight("第一个对象"));
            flyweights.Add(new ConcreteFlyweight("第二个对象"));
            flyweights.Add(new ConcreteFlyweight("第三个对象"));
        }

        public Flyweight GetFlyweight(int key)
        {
            Flyweight flyweight;
            if (key >= flyweights.Count)
            {
                Console.WriteLine("驻留池中不存在对象" + (key + 1));
                flyweight = new ConcreteFlyweight("第" + (key + 1) + "个对象");
            }
            else
            {
                flyweight = flyweights[key];
            }
            return flyweight;
        }
    }
    #endregion

    #region 抽象享元类,提供具体享元类具有的方法
    /// <summary>
    ///  抽象享元类,提供具体享元类具有的方法
    /// </summary>
    public abstract class Flyweight
    {
        public abstract void Operation();
    }
    #endregion

    #region 具体的享元对象
    /// <summary>
    /// 具体的享元对象
    /// </summary>
    public class ConcreteFlyweight : Flyweight
    {
        private string intrinsicstate;

        // 构造函数
        public ConcreteFlyweight(string innerState)
        {
            this.intrinsicstate = innerState;
        }
        /// <summary>
        /// 享元类的实例方法
        /// </summary>
        /// <param name="extrinsicstate">外部状态</param>
        public override void Operation()
        {
            Console.WriteLine("调用了具体的对象: {0}", intrinsicstate);
        }
    }
    #endregion

采用享元模式实现的简单数据库连接池

DbConnectionPool 类有两个重要的方法; getConnection(), 从对象池中获取一个对象, returnConnection(), 把对象还给对象池。我们以两个哈希表实现对象池,一个称为freeConnections, 另一个称为busyConnections. busyConnections 哈希表包含所有正在使用的对象而freeConnections哈希表包含了所有未被使用且可随时使用的对象。

public interface DbConnectionPool
    {

        //设定连接池中存放连接的数目
        public void SetMaxConns(int numConnections);
        //设定打开或者关闭连接池
        public void SetConnWitch(string Switch);
        //产生连接池
        public void initConnPool();
        //从连接池获取连接
        public Connection getConnection();
        //将连接返回给连接池
        public void returnConnection();
        //销毁连接池
        public void destroyConnPool();

    }
public  class GdDbConnectionPool:DbConnectionPool
    {
        private static string connectionString =
            @"server=(local);Trusted Connection=yes;database=myDB";
        //默认连接池的大小
        static const int defaultMaxConnections = 10;
        //存放目前空闲的连接,空闲池
        private List<Connnection> freeConnections;
        //存放目前正在使用的连接
        private List<Connnection> busyConnections;
        //设定连接池的大小
        private int maxConnections;

        //构造函数
        public GdDbConnectionPool(int numConnections)
        {
            maxConnections = numConnections;
            freeConnections = null;
            busyConnections = null;
        }

        #region 实现获取数据库连接的操作
        /// <summary>
        /// 实现获取数据库连接的操作
        /// </summary>
        /// <returns></returns>
        public Connection getConnection()
        {
            if (freeConnections == null)
            {
                return "连接池还没有创建";
            }

            object o = null;
            lock (this)
            {
                try
                {
                    foreach (DictionaryEntry myEntry in freeConnections)
                    {
                        o = myEntry.Key;
                        unlocked.Remove(o);
                        if (Validate(o))
                        {
                            locked.Add(o, now);
                            return o;
                        }
                        else
                        {
                            Expire(o);
                            o = null;
                        }
                    }
                }
            }
            //获取空闲池连接
            Connection conn = (Connection)freeConnections.get(0);
            freeConnections.remove(o);
            busyConnections.add(o);
            return o;
        }
        #endregion

        #region 产生连接池
        /// <summary>
        /// 产生连接池
        /// </summary>
        public void initConnPool()
        {
            freeConnections = new freeConnections(maxConnections);
            busyConnections = new busyConnections(maxConnections);
            for (int i = 0; i < maxConnections; i++)
            {
                freeConnections.add();
            }
        }
        #endregion

        #region 从繁忙池中销毁已经返回的连接
        /// <summary>
        /// 从繁忙池中销毁已经返回的连接
        /// </summary>
        public void returnConnection()
        {
            busyConnections conn = (Connection)busyConnections.get();
            if (conn = null)
                throw new Exception("没有发现繁忙池中有连接");
            busyConnections.remove();
            freeConnections.add(conn);

        }
        #endregion

    }

在企业级计算的多线程世界中同步是一个极其重要的概念。它被广泛用于数据库,消息队列以及Web 服务器等闻名应用上。任何开发多线程应用程序的开发人员都必须对他们的同步概念特别清楚。不是为了让每个对象都是线程安全的而导致系统不堪重负,而是应该关注死锁情况并在程序设计之初就解决尽可能多的死锁问题。理解同步带来的性能瓶颈问题同样很重要,因为它将影响应用程序的总体性能。

总结

前面单例模式的最后,我举了个我项目中用到的一个例子,其实那也就是数据库程序连接池的示例,如果采用单例模式,整个系统就只使用一个数据库连接,当用户并发量很大的时候,系统就会变得很慢,因为建立数据库连接时一个耗费资源的活动,对于一次或几次的数据库连接,感觉不到什么影响,而对于大型门户网站,频繁的进行数据库连接操作必然会占了很多资源,网站的相应速度就会很慢,甚至导致服务器奔溃,理论上是如此,然而我的一个项目目前就用到这个单例模式,用户的并发量估计会达到好几千,因此在考虑是否需要改进,而这种对比也只是理论上的比较,没有具体的经历和数据来确定这种单例就会导致系统卡顿,因此如果对这方面有一定研究的朋友可以给我一些数据来告诉到底会不会出现这类问题。

时间: 2025-01-02 18:00:13

C#设计模式-享元模式的相关文章

设计模式——享元模式

Flyweight 直译为蝇量.就其表示的模式来说,翻译成享元,确实是不错的 package designpattern.structure.flyweight; public interface Flyweight { void action(int arg); } package designpattern.structure.flyweight; public class FlyweightImpl implements Flyweight { public void action(int

8. 星际争霸之php设计模式--享元模式

题记==============================================================================本php设计模式专辑来源于博客(jymoz.com),现在已经访问不了了,这一系列文章是我找了很久才找到完整的,感谢作者jymoz的辛苦付出哦! 本文地址:http://www.cnblogs.com/davidhhuan/p/4248186.html============================================

[工作中的设计模式]享元模式模式FlyWeight

一.模式解析 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持大量的细粒度对象. 享元模式:主要为了在创建对象时,对共有对象以缓存的方式进行保存,对外部对象进行单独创建 模式要点: 1.享元模式中的对象分为两部分:共性部分和个性化部分,共性部分就是每个对象都一致的或者多个对象可以共享的部分,个性化部分指差异比较大,每个类均不同的部分 2.共性部分的抽象就是此模

设计模式-享元模式

***********************************************声明****************************************************** 原创作品,出自 "晓风残月xj" 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj). 由于各种原因,可能存在诸多不足,欢迎斧正! *******************************************

iOS设计模式——享元模式

公共交通(如公共汽车)已有一百多年的历史了.大量去往相同方向的乘客可以分担保有和经营车辆(如公共汽车)的费用.公共汽车有多个站台,乘客沿着路线在接近他们目的地的地方上下车.到达目的地的费用仅与行程有关.跟保有车辆相比,乘坐公共汽车要便宜得多.这就是利用公共资源的好处. 在面向对象软件设计中,我们利用公共对象不仅能节省资源还能提高性能.比方说,某个人物需要一个类的一百万个实例,但我们可以把这个类的一个实例让大家共享,而把某些独特的信息放在外部,节省的资源可能相当可观(一个实例与一百万个实例的差别)

设计模式——享元模式详解

0. 前言 写在最前面,本人的设计模式类博文,建议先看博文前半部分的理论介绍,再看后半部分的实例分析,最后再返回来复习一遍理论介绍,这时候你就会发现我在重点处标红的用心,对于帮助你理解设计模式有奇效哦~本文原创,转载请注明出处为SEU_Calvin的博客. 春运买火车票是一件疯狂的事情,同一时刻会有大量的查票请求涌向服务器,服务器必须做出应答来满足我们的购票需求.试想,这些请求包含着大量的重复,比如从A地到B地的车票情况,如果每次都重复创建一个车票查询结果的对象,那么GC任务将非常繁重,影响性能

小菜学设计模式——享元模式

背景 如果一个应用程序中使用了大量的对象,而大量的这些对象造成了恨得的存储开销时就应该考虑这个新是设计模式:享元模式. 1.使用意图 最大限度地减少了尽可能与其他类似的对象多的数据共享内存的使用,换句话说就是通过共享对象达到系统内维护的对象数量减少从而降低了系统的开销.因为是细粒度的控制,所以享元模式不是控制整个实例共享,那为何不用单例呢?而是只是共享对象的部分,不共享的部分称为对象的外部状态,需要外部动态修改这个共享对象. 2.生活实例 围棋的棋子,如果用编程去实现的话,势必要new出很多实例

深入浅出设计模式——享元模式(Flyweight Pattern)

模式动机 面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数.当对象数量太多时,将导致运行代价过高,带来性能下降等问题.享元模式正是为解决这一类问题而诞生的.享元模式通过共享技术实现相同或相似对象的重用. 在享元模式中可以共享的相同内容称为内部状态(Intrinsic State),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有

PHP设计模式——享元模式

声明:本系列博客参考资料<大话设计模式>,作者程杰. 享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件:它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件.通常物件中的部分状态是可以分享.常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元. UML类图: 角色分析: 享元工厂角色(FWFactory):创建并管理BlogModel对象. 所有具体享元父接口角色(BolgModel):接受并作用与外部状态. 具体享元角色(JobsBlog)