最近在园子的首页经常会看到一些有关设计模式的文章。23种设计模式要完全掌握可不一件容易的事.最早了解的种设计模式是Singleton模式(单件模式),主要是因为它简单。套用别人的代码大概是这样子:
public class Singleton
{
private static Singleton m_instance = new Singleton();
public static Singleton Instance
{
get { return m_instance; }
}
protected Singleton() { }
public void WL(string p_strMsg)
{
Console.WriteLine(p_strMsg);
Thread.Sleep(1000);
}
}
上面简单的代码就实现了Singleton模式了。但今天在写代码的时候在有一个问题一直没能想明白。当在一个系统当中,同时有多个客户访问了这个对象,或者说对象当中的某一个方法。那对象能否同时为多个客户服务呢?还是要等待(类似于访问互斥资源的需要lock)?用下面的代码进行测试: {
private static Singleton m_instance = new Singleton();
public static Singleton Instance
{
get { return m_instance; }
}
protected Singleton() { }
public void WL(string p_strMsg)
{
Console.WriteLine(p_strMsg);
Thread.Sleep(1000);
}
}
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 for (int i = 0; i < 100; i++)
6 {
7 Thread thread = new Thread(new ThreadStart(ThreadFunc));
8 thread.Name = "Thread " + i.ToString();
9 thread.Start();
10 }
11 RL();
12 }
13 public static void ThreadFunc()
14 {
15 for (int i = 0; i < 1000; i++)
16 {
17 Singleton.Instance.WL("Thread Name:" + Thread.CurrentThread.Name + " Count:" + i.ToString() + " Object HashCode:" + Singleton.Instance.GetHashCode().ToString());
18 //Thread.Sleep(300);
19 }
20 }
21 private static void RL()
22 {
23 Console.ReadLine();
24 }
25
26 }
2 {
3 static void Main(string[] args)
4 {
5 for (int i = 0; i < 100; i++)
6 {
7 Thread thread = new Thread(new ThreadStart(ThreadFunc));
8 thread.Name = "Thread " + i.ToString();
9 thread.Start();
10 }
11 RL();
12 }
13 public static void ThreadFunc()
14 {
15 for (int i = 0; i < 1000; i++)
16 {
17 Singleton.Instance.WL("Thread Name:" + Thread.CurrentThread.Name + " Count:" + i.ToString() + " Object HashCode:" + Singleton.Instance.GetHashCode().ToString());
18 //Thread.Sleep(300);
19 }
20 }
21 private static void RL()
22 {
23 Console.ReadLine();
24 }
25
26 }
从宏观上看,一个对象被一个客户占有,至少在执行一个原子函数时,应该是不能被别外一个客户使用的,而当这个原子函数的执行时间很长(网络超时)。那其它的客户不都要停止工作了?但从微观上,单CPU的计算机同时一时刻只能有一个作业在执进,而这时Singleton的对象又是怎么样被执行的?如果说它能随意地让每个客户共享的话,那在我们的项目中就不需要每次执行都去实例化对象,对相同的类在一个AppDomain只存在一个实例,这样就可以减少在实例化对象上的性能损耗和.NET 拖管堆的压力。而这种方案是否可行??执行上面的测试,结果是可行的,我创建了100线程,每个线程都执行了WL()方法,在方法里面让线程等待3秒,而在当这个线程等待时,另外一个线程还是可以工作的。
有一种场景,在Provider模式中(.NET 2.0和CS经常用到的一种模式)的。在使用这些的Provider的时候,不可避免的都会遇到对象的实例化问题,用反射的方法进行实例化(Activator.CreateInstance(string p_strType),也分不清这种方法算不算反向技术?),如果每次使用都去实例化,从理论上都会对性能造成一定的影响。而今天在考虑这个问题的时候首先想到的就是用Singleton模式,还有一种方法叫对象池?记得在看《.NET框架程序设计》的时候提到了对象的生命周期和对象池方法。
忘了怎么样在书里面是怎么样去实现对象池了。不过目前有一个想法就是用IDisposable这个接口来做文章。所有的对象都继承这个类,然后实现Dispose方法,这个方法不去Dispose对象,只是将对象的Used标志记成false,然后放回池里面:
public interface IPoolDispose : IDisposable
{
bool Used { get;set;}
}
{
bool Used { get;set;}
}
对象定义如下:
public class ObjectPool : IPoolDispose
{
private int m_intUsed = 0;
public void WL()
{
m_intUsed++;
Console.WriteLine(this.GetHashCode() + "我被使用了: " + m_intUsed.ToString() + "次");
Thread.Sleep(30); //对象等待时间
}
private bool m_bUsed = false;
public bool Used
{
get { return m_bUsed; }
set { m_bUsed = value; }
}
public void Dispose()
{
Used = false;
}
}
至于缓存,我想可以放在一个静态的ArrayList,或者将ArrayList缓存缓存中。这边还需要一个类工厂负责创建并返回类实例: {
private int m_intUsed = 0;
public void WL()
{
m_intUsed++;
Console.WriteLine(this.GetHashCode() + "我被使用了: " + m_intUsed.ToString() + "次");
Thread.Sleep(30); //对象等待时间
}
private bool m_bUsed = false;
public bool Used
{
get { return m_bUsed; }
set { m_bUsed = value; }
}
public void Dispose()
{
Used = false;
}
}
public class ClassFactory
{
static ArrayList array = new ArrayList();
public static ObjectPool CreateObject()
{
foreach (IPoolDispose pool in array)
{
if (pool.Used == false)
{
pool.Used = true;
return (ObjectPool)pool;
}
}
ObjectPool m_object = new ObjectPool();
if (array.Count < 10)
array.Add(m_object);
return m_object;
}
}
用下面的代码运行测试: {
static ArrayList array = new ArrayList();
public static ObjectPool CreateObject()
{
foreach (IPoolDispose pool in array)
{
if (pool.Used == false)
{
pool.Used = true;
return (ObjectPool)pool;
}
}
ObjectPool m_object = new ObjectPool();
if (array.Count < 10)
array.Add(m_object);
return m_object;
}
}
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
Thread thread = new Thread(new ThreadStart(ThreadFunc2));
thread.Name = "Thread " + i.ToString();
thread.Start();
}
RL();
}
public static void ThreadFunc2()
{
ObjectPool m_objectPool = ClassFactory.CreateObject();
using (m_objectPool)
{
m_objectPool.WL();
}
}
private static void RL()
{
Console.ReadLine();
}
}
会发现,如果上面的对象等待时间设得比较长的话,就会创建很多对象,而且很多对象都只使用了一次。而如果设置得很短的话,比如0。就类似于Singleton模式了,一百个线程都使用一个实例,这个实例就被使用了100次。 {
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
Thread thread = new Thread(new ThreadStart(ThreadFunc2));
thread.Name = "Thread " + i.ToString();
thread.Start();
}
RL();
}
public static void ThreadFunc2()
{
ObjectPool m_objectPool = ClassFactory.CreateObject();
using (m_objectPool)
{
m_objectPool.WL();
}
}
private static void RL()
{
Console.ReadLine();
}
}
以上两种方法都可以实现对象的复用,减少对象的实例次数?Singleton甚至只需要实例一次。而这两种方法有什么不一样的地方,各自的优缺点都在哪里呢?有可能给系统带来什么样的影响呢?
源码: 下载