最近开始花点心思研究下设计模式,主要仍是让本身写的代码可重用性高、保证代码可靠性。所谓设计模式,我找了下定义:是一套被反复使用、多数人知晓的、通过分类编目的、代码设计经验的总结。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构同样。数据库
为何要提倡“Design Pattern(设计模式)”?设计模式
根本缘由是为了代码复用,增长可维护性。所以此次咱们来学习下设计模式,最后会经过C#语言来实现这些设计模式做为例子,深入理解其中的精髓。安全
享元模式:它使用共享物件,用来尽量减小内存使用量以及分享资讯给尽量多的类似物件;它适合用于只是因重复而致使使用没法使人接受的大量内存的大量物件。一般物件中的部分状态是能够分享。常见作法是把它们放在外部数据结构,当须要使用时再将它们传递给享元。服务器
以前讲到的单例模式,一个类只有一个惟一的对象,也就是说,无论new多少次,只须要建立这个类的一个对象,若是不采用单例模式,每new一次,就会建立一个对象,便会产生大量重复的对象,而这些对象要消耗很大的资源的时候,是会产生资源互抢的延迟的。这个时候享元模式就能帮忙解决这类的问题。数据结构
享元模式的意图是经过共享有效支持大量细粒度的对象,来提供应用程序的性能,节省系统中重复建立对象实例的性能消耗,这个怎么理解呢?其实就是如下几点的含义:多线程
一、当咱们系统中某个对象类型的实例较多的状况。并发
二、而且要求这些实例进行分类后,发现真正有区别的分类不多的状况。ide
例如咱们的生活中不少的场景,咱们在使用拼音输入的法的时候,若是说咱们每一个字都是new一个对象实例的操做的话,那么内存中的实例就太可怕,这个时候,咱们是否是能够考虑将这些重复的字体在内存中只是建立一次,而是经过复用对象的形式,来组织一些可能有多个字符重复的内容呢?函数
优势:
1、性能
下降了系统中对象的数量,从而下降了系统中细粒度对象给内存带来的压力。
缺点:
1、
为了使对象能够共享,须要将一些状态外部化,这使得程序的逻辑更复杂,使系统复杂化。
2、
享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
享元模式就是把部分和总体的关系用树形结构来表示,从而使客户端可以把一个个的部分对象和由它们组合起来的总体对象采用一样的方式来对待。享元模式主要由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 服务器等闻名应用上。任何开发多线程应用程序的开发人员都必须对他们的同步概念特别清楚。不是为了让每一个对象都是线程安全的而致使系统不堪重负,而是应该关注死锁状况并在程序设计之初就解决尽量多的死锁问题。理解同步带来的性能瓶颈问题一样很重要,由于它将影响应用程序的整体性能。
总结
前面单例模式的最后,我举了个我项目中用到的一个例子,其实那也就是数据库程序链接池的示例,若是采用单例模式,整个系统就只使用一个数据库链接,当用户并发量很大的时候,系统就会变得很慢,由于创建数据库链接时一个耗费资源的活动,对于一次或几回的数据库链接,感受不到什么影响,而对于大型门户网站,频繁的进行数据库链接操做必然会占了不少资源,网站的相应速度就会很慢,甚至致使服务器奔溃,理论上是如此,然而个人一个项目目前就用到这个单例模式,用户的并发量估计会达到好几千,所以在考虑是否须要改进,而这种对比也只是理论上的比较,没有具体的经历和数据来肯定这种单例就会致使系统卡顿,所以若是对这方面有必定研究的朋友能够给我一些数据来告诉到底会不会出现这类问题。