singleton模式简介

singleton模式就是所谓的“单例模式”,“单件模式”。

该模式顾名思义,按字面意思理解就是程序中有且只能有一个实例,单例模式非常方便处理程序中的临时验证数据,如验证码、地址访问限制等,省去了其他多余的步骤,节省了时间和不必要的操作。

单例模式:在程序中有且只有一个实例,并提供一个全局访问点供外部调用获取实例,我们就用一个验证码模块来具体描述单例模式的好处。

首先我们来声明验证码信息的类,如下:

using System;
using System.Text;

namespace BTS.PFTService.Guard
{
/// <summary>
/// 验证码信息。
/// </summary>
public class ValidationCodeInfo
{
/// <summary>
/// 获取客户端标识。
/// </summary>
public string ClientId { get; private set; }

/// <summary>
/// 获取验证码创建时间。
/// </summary>
public DateTime CreateTime { get; private set; }

/// <summary>
/// 获取验证码信息。
/// </summary>
public string ValidationCode { get; private set; }

/// <summary>
/// 初始化 ValidationCodeInfo 的新实例。
/// </summary>
public ValidationCodeInfo()
{
//初始化ClientId,创建Guid进行base64加密。
ClientId = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString()));

//初始化创建时间。
CreateTime = DateTime.Now;

//创建验证码信息。
var random = new Random();

//合法随机显示字符列表。
var strLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

var strvalidationCode
= new StringBuilder();

//随即生成验证码字符串。
for (var i = 0; i < 4; i++)
{
strvalidationCode.Append(strLetters.Substring(random.Next(
0, strLetters.Length - 1), 1));
}
var strValidationCode
= strvalidationCode.ToString();
//初始化验证码内容属性。
ValidationCode = strValidationCode;
}
}
}

有了验证码信息,那么接下来就创建一个验证码限制校验类(单例),代码如下:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Timers;
using System.Web;
using System.Threading;
using Timer = System.Timers.Timer;

namespace BTS.PFTService.Guard
{
/// <summary>
/// 提供基于验证码限制的防盗取功能。
/// </summary>
public class ValidationRestrictGuard
{
//验证码限制唯一实例。
private static ValidationRestrictGuard _instance;

//实例同步对象。
private static readonly object _instancelocker = new object();

/// <summary>
/// _validationCodeDic读写锁同步处理对象。
/// </summary>
private static readonly ReaderWriterLock readerWriterLock = new ReaderWriterLock();

/// <summary>
/// 获取 ValidationRestrictGuard 的唯一实例。
/// 该属性则是全局唯一访问点。
/// </summary>
public static ValidationRestrictGuard Instance
{
get
{
if(_instance==null)
{
lock (_instancelocker)
{
if (_instance == null)
{
_instance
= new ValidationRestrictGuard();
}
}
}
return _instance;
}
}

/// <summary>
/// 验证码信息存储集合。key:客户端标识,value:验证码信息。
/// </summary>
private readonly Dictionary<string, string> _validationCodeDic;

/// <summary>
/// 用于保存验证码信息的列表。
/// </summary>
private readonly Queue<ValidationCodeInfo> _validationCodeInfoQueue;

/// <summary>
/// 验证指定的验证码是否有效。
/// </summary>
/// <param name="clientId">客户端标识。</param>
/// <param name="code">验证码信息。</param>
/// <returns>验证通过返回 true,否则返回 false。</returns>
public bool CheckValidationCode(string clientId,string code)
{
//获取读锁。
readerWriterLock.AcquireReaderLock(30000);

string validationcode;

//验证码信息集合validationCodeDic无数据。
if (_validationCodeDic.Count == 0)
{
//释放读锁。
readerWriterLock.ReleaseReaderLock();
return false;
}
else if(_validationCodeDic.TryGetValue(clientId,out validationcode))
{
if(validationcode.ToLower()==code.ToLower())
{
//释放读锁
readerWriterLock.ReleaseReaderLock();
return true;
}
}

//释放读锁
readerWriterLock.ReleaseReaderLock();
return false;

}

/// <summary>
/// 创建并获取客户端标识。
/// </summary>
/// <returns>客户端标识。</returns>
public string CreateValidationCode()
{

//获取写锁。
readerWriterLock.AcquireWriterLock(30000);

var validationCodeInfo
= new ValidationCodeInfo();
_validationCodeDic.Add(validationCodeInfo.ClientId,validationCodeInfo.ValidationCode);
_validationCodeInfoQueue.Enqueue(validationCodeInfo);

//释放写锁。
readerWriterLock.ReleaseWriterLock();
return validationCodeInfo.ClientId;
}

/// <summary>
/// 呈现验证码到当前请求中。
/// </summary>
/// <param name="context">Http请求。</param>
/// <returns>操作成功返回 true,否则返回 false。</returns>
public bool ReponseValidationCode(HttpContext context)
{
//获取客户端标识。
var vCodeClientID = context.Request["VCodeClientID"];

//验证码信息变量。
string strValidationCode;

//获取读锁。
readerWriterLock.AcquireReaderLock(30000);

if(_validationCodeDic.TryGetValue(vCodeClientID,out strValidationCode))
{
//释放读锁。
readerWriterLock.ReleaseReaderLock();

//设置输出流图片格式。
context.Response.ContentType = "image/gif";

var bitmap
= new Bitmap(150, 35);
var graphics
= Graphics.FromImage(bitmap);
graphics.FillRectangle(
new SolidBrush(Color.White), 0, 0, 220, 60);
var font
= new Font(FontFamily.GenericSerif, 25, FontStyle.Bold, GraphicsUnit.Pixel);
var random
= new Random();

//将验证码内容绘制到图片上。
for (var i = 0; i < strValidationCode.Length; i++)
{
graphics.DrawString(strValidationCode[i].ToString(), font,
new SolidBrush(Color.Black), i * 38, random.Next(0, 10));
}

//生成干扰线条。
var pen1 = new Pen(new SolidBrush(Color.Blue), 1);
var pen2
= new Pen(new SolidBrush(Color.SandyBrown), 1);
var pen3
= new Pen(new SolidBrush(Color.Yellow), 1);
var pen4
= new Pen(new SolidBrush(Color.SpringGreen), 1);
var pen5
= new Pen(new SolidBrush(Color.Pink), 1);
for (var i = 0; i < 10; i++)
{
switch (i)
{
case 2:
case 1:
graphics.DrawLine(pen1,
new Point(random.Next(0, 150), random.Next(0, 35)), new Point(random.Next(0, 150), random.Next(0, 35)));
break;
case 4:
case 3:
graphics.DrawLine(pen2,
new Point(random.Next(0, 150), random.Next(0, 35)), new Point(random.Next(0, 150), random.Next(0, 35)));
break;
case 6:
case 5:
graphics.DrawLine(pen3,
new Point(random.Next(0, 150), random.Next(0, 35)), new Point(random.Next(0, 150), random.Next(0, 35)));
break;
case 8:
case 7:
graphics.DrawLine(pen4,
new Point(random.Next(0, 150), random.Next(0, 35)), new Point(random.Next(0, 150), random.Next(0, 35)));
break;
default:
graphics.DrawLine(pen5,
new Point(random.Next(0, 150), random.Next(0, 35)), new Point(random.Next(0, 150), random.Next(0, 35)));
break;
}
}
bitmap.Save(context.Response.OutputStream, ImageFormat.Gif);

//释放对象资源。
bitmap.Dispose();
graphics.Dispose();
return true;
}

//释放读锁。
readerWriterLock.ReleaseReaderLock();
return false;
}

/// <summary>
/// 清理已过期的验证码信息集合。
/// </summary>
private void CleanupValidationCode()
{
//获取写锁。
readerWriterLock.AcquireWriterLock(30000);

if(_validationCodeInfoQueue.Count>0)
{
//判断队列中是否有过期验证码。
while (DateTime.Now - _validationCodeInfoQueue.Peek().CreateTime > TimeSpan.FromMinutes(10))
{
_validationCodeDic.Remove(_validationCodeInfoQueue.Dequeue().ClientId);
if(_validationCodeInfoQueue.Count==0)
{

//释放写锁
readerWriterLock.ReleaseWriterLock();
return;
}
}
}
//释放写锁
readerWriterLock.ReleaseWriterLock();
}

/// <summary>
/// 定时清理事件。
/// </summary>
private void TimerClean(object sender, ElapsedEventArgs e)
{
CleanupValidationCode();
}

/// <summary>
/// ValidationRestriceGuard构造函数初始化。
/// </summary>
private ValidationRestrictGuard()
{
_validationCodeDic
= new Dictionary<string, string>();
_validationCodeInfoQueue
= new Queue<ValidationCodeInfo>();

//定时清理验证码集合信息。
var timer = new Timer(60000);
timer.Elapsed
+= TimerClean;
timer.AutoReset
= true;
timer.Enabled
= true;
timer.Start();
}

}
}

这样,一个验证码模块单例设计就完成了,是不是灰常方便呢?

顺便补充一点,ValidationRestrictGuard的构造函数一定要是private,否则后果你懂得...

posted @ 2011-08-24 13:47  John.HuJY  阅读(1113)  评论(4编辑  收藏  举报