设计模式:单例模式(至少有一种你没有见过)
背景返回目录
本文中的例子多是从《clr via c#》中抄袭而来,读过这本书最后一章的朋友,应该见过各种实现了。
各种实现返回目录
第一种:简单版本返回目录
代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace DesignPatternStudy.Creations.Singletons 8 { 9 class SimpleSingleton 10 { 11 private static readonly SimpleSingleton _instance; 12 13 private SimpleSingleton() { } 14 15 static SimpleSingleton() 16 { 17 _instance = new SimpleSingleton(); 18 } 19 20 public static SimpleSingleton Singleton 21 { 22 get 23 { 24 return _instance; 25 } 26 } 27 } 28 }
说明:静态构造方法是线程安全的,因此可以保证单例。如果单例类型有其它静态方法,调用这些方法会导致单例被初始化。
第二种:嵌套类返回目录
代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace DesignPatternStudy.Creations.Singletons 8 { 9 class NestedSingleton 10 { 11 private NestedSingleton() { } 12 13 public static NestedSingleton Singleton 14 { 15 get 16 { 17 return Nested._instance; 18 } 19 } 20 21 public static void OtherStaticMethod() 22 { 23 Console.WriteLine("不会产生单例!"); 24 } 25 26 private class Nested 27 { 28 public static readonly NestedSingleton _instance; 29 30 static Nested() 31 { 32 _instance = new NestedSingleton(); 33 } 34 } 35 } 36 }
说明:解决了“简单版本”的问题,调用单例类型的静态方法不会导致单例被实例化。
第三种:双校验+悲观锁返回目录
代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace DesignPatternStudy.Creations.Singletons 8 { 9 class DoubleCheckSingleton 10 { 11 private static readonly Object _lock = new Object(); 12 private static DoubleCheckSingleton _instance; 13 14 private DoubleCheckSingleton() { } 15 16 public static DoubleCheckSingleton Singleton 17 { 18 get 19 { 20 if (_instance != null) 21 { 22 return _instance; 23 } 24 25 lock (_lock) 26 { 27 if (_instance == null) 28 { 29 _instance = new DoubleCheckSingleton(); 30 } 31 } 32 33 return _instance; 34 } 35 } 36 } 37 }
说明:设计模式的作者使用的语言是 C++,C++ 没有和 C# 静态构造方法同样语义的机制,因此使用了这种双校验机制。
第四种:双校验+乐观锁返回目录
代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Threading; 7 8 namespace DesignPatternStudy.Creations.Singletons 9 { 10 class CASSingleton 11 { 12 private static CASSingleton _instance; 13 14 private CASSingleton() 15 { 16 Console.WriteLine("CASSingleton"); 17 } 18 19 public static CASSingleton Singleton 20 { 21 get 22 { 23 if (_instance != null) 24 { 25 return _instance; 26 } 27 28 Interlocked.CompareExchange(ref _instance, new CASSingleton(), null); // 相当于:update xxx_table set version = new_version where version = old_version 29 30 return _instance; 31 } 32 } 33 } 34 }
说明:乐观锁在某些情况下是比悲观锁好用,在本例中有一点要求:构造方法的执行必须没有副作用,因为内部可能创建多个实例,外部只会看到一个。
备注返回目录
看完大师的书籍,觉得自己好渺小,继续努力吧。
上篇文章我们主要讲了HttpApplicatiion管道事件,那么我么如何处理这些管道事件呢,以及请求在ASP.NET是如何执行的呢,我们来了解一下IHttpHandler和IHttpModule
引言:
处理HttpApplicatiion事件
HttpApplication提供了基于事件的扩展机制,允许程序员借助于处理管道中的事件进行处理过程扩展。由于HttpApplication对象是ASP.NET基础架构来创建和维护,那么如何才能获得这个对象引用,以便于注册HttpApplication对象的事件处理,在ASP.NET中提供了两种方式来 解决这个问题:IHttpModule和global.aspx,这两种方式的核心都是IHttpModule几口,下面我们就主要讲IHttpModule。
正文:
IHttpModule的用途以及用法
在ASP.NET中,定义在System.Web命名空间下的IHttpModule接口专门用了定义HttpApplication对象的事件处理。
实现IHttpModule接口的类成为HttpModule。IHttpModule接口的定义如下,仅仅包含两个成员:
public interface IHttpModule { void Dispose() void Init(HttpApplication context) }
其中,Dispose方法用于回收Module所使用的非托管资源,如果没有的话,直接返回即可。
最重要的是第二个方法Init,可以看到这个方法接受一个HttpApplication类型的参数,在ASP.NET中,每当创建一个HttpApplication对象实例,将遍历注册的HttpModule类型,通过反射依次创建 么个注册HttpModule类型的一个实例对象,并将这个HttpApplication实例通过Init方法传递给各个HttpModule,这样HttpModule对象就可以在第一时间完成针对HttpApplication对象的事件注册了。
例如,希望写一个PostAuthenticateRequest事件的HttpModule,那么就可以完成以下注册
pulic class xxx:IHttpModule { void Dispose() void Init(HttpApplication app) { app.PostAuthencateRequest+=new EventHandler(app_PostAuthencateRequest) } }
当然,实现IHttpModule接口只是实现HttpModule的一部分,在ASP.NET中所使用的HttpModule还要在网站配置文件中进行注册才能真正生效,并在ASP.NET中使用,这一点我们就不在讲解了,下面看一下IHttpHandler。
IHttpHandler
在ASP.NET中,请求的真正处理就是在处理程序这个环节,也就是在HttpApplication19个标准事件的PreRequestHandlerExcute和PostRequestHandlerExcute之间,PreRequestHandlerExcute负责同志程序员,处理程序就要开始工作了,PostRequestHandlerExcute事件同志程序员ASP.NET服务器的处理程序已经完成。那么HttpApplication的作用是什么呢?我们可以把它看做请求到达处理程序和离开处理程序的一个管道,这个管道提供了统一处理所有请求的机制,使得我们可以在请求被真正处理之前和处理之后进行预处理和处理后的工作。
处理程序负责完成实际的请求处理工作,对于网站开发人员来说,大多数的开发工作是围绕着处理程序展开的。(其实我们可以看到,我们的页面类也就是Page实现了IHttphandler接口)实际上,接触到HttpApplication事件处理的时候并不多,处理程序在不同的网站开发技术中有不同的名字,在ASP.NET中,为HttpHandler。
在ASP.NET中,所有的处理程序类必须实现IHttpHandler接口或者实现IHttpAsyncHandler接口,我们可以很明显看出区别来,一个是同步接口,一个是异步处理模式的接口。那么我们通常使用的是同步模式的接口。下面我们简单介绍一下
这两个接口都定义在System.Web下,IHttphandler接口的定义如下
public interface IHttpHandler { void ProcessRequest(HttpContext context) bool IsRequest{get;} }
ProcessRequest是这个接口的主要方法,接收一个HttpContext类型的请求上下文对象,通过这个对象,处理程序可以得到关于处理请求所需的信息,通过这个参数的Response属性可以得到管理回应的对象,可以向客户端返回服务器的处理结果。
IsRequest属性表示当这个处理程序对象在使用之后,是否还可以被缓存起来,在以后的请求处理中用。
当然,同样的是我们也要注册处理程序,每一种处理处理程序用来处理一类的请求,处理程序与请求之间的匹配关系可以在网站的配置文件中通过配置参数来进行设置。