单例模式的特点:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其它对象提供这一实例。
Singleton的设计方式大体上分为两种:
1.使用静态方法创建单件,我们将用Pascal(定制)实现
2.利用C#特有机制创建单件,我们将用C#来实现
下面我们看看利用C#特有机制创建单件的过程。为了方便起见我们在以前的SimFactory例子上作一些修改看看Singleton的实现过程。
UML图:
具体代码:
1
using
System;
2
3 namespace Singleton
4 {
5 /**//**//**//// <summary>
6 ///============== Program Description==============
7 ///Name:Singleton.cs
8 ///Objective:Singleton
9 ///Date:2006-04-26
10 ///Written By coffee.liu
11 ///================================================
12 /// </summary>
13 class Class1
14 {
15 /**//**//**//// <summary>
16 /// 应用程序的主入口点。
17 /// </summary>
18 [STAThread]
19 static void Main(string[] args)
20 {
21 Thinking tk1,tk2,tk3;
22 PersonSimFactory PSF=new PersonSimFactory();
23 Person PP=PSF.GetPerson("Yellow");
24 tk1=PP.GetTk;
25 PP.GetInfo();
26 Console.WriteLine(".");
27 PP=PSF.GetPerson("Black");
28 tk2=PP.GetTk;
29 PP.GetInfo();
30 Console.WriteLine(".");
31 PP=PSF.GetPerson("Write");
32 tk3=PP.GetTk;
33 PP.GetInfo();
34 if ((tk1==tk2)&&(tk2==tk3)&&(tk1==tk3))
35 Console.WriteLine("we are the same Thinking");
36
37 }
38 }
39 /**//**//**//// <summary>
40 /// 每个人都有思维
41 /// Thinking类被定为sealed类即不能被其他类继承
42 /// 我们把instance定义成了 static readonly属性,
43 /// 如果类中的static属性被任何方法使用时,.NET Framework将对这个属性进行初始化,
44 /// 于是在初始化Instance属性的同时Thinking类实例得以创建和装载。
45 /// 而私有的构造函数和readonly(只读)保证了Thinking不会被再次实例化,
46 /// 从而实现了Singleton的目的。
47 /// </summary>
48
49 public sealed class Thinking
50 {
51 public static readonly Thinking instance=new Thinking();
52 private Thinking(){}
53
54 public static Thinking Instance
55 {
56 get
57 {
58 return instance;
59 }
60 }
61 public void Say(){
62 Console.WriteLine("I have a Thinking");
63 }
64
65 }
66
67 public class Person
68 {
69 protected Thinking tk;
70 protected string sex,race;
71 public Thinking GetTk
72 {
73 get {return tk;}
74 }
75 public string GetSex()
76 {
77 return sex;
78 }
79 public string GetRace()
80 {
81 return race;
82 }
83 public virtual void GetInfo()
84 {
85 }
86 }
87
88 public class YellowPerson:Person
89 {
90 public YellowPerson()
91 {
92 sex="Man";
93 race="Yellow";
94 }
95 public YellowPerson(string Ysex)
96 {
97 sex=Ysex;
98 race="Yellow";
99 }
100 public override void GetInfo()
101 {
102 Console.WriteLine("the "+race+" Person Info:"+sex);
103 tk=Thinking.Instance;
104 tk.Say();
105 }
106 }
107
108 public class BlackPerson:Person
109 {
110 public BlackPerson()
111 {
112 sex="Man";
113 race="Black";
114 }
115 public BlackPerson(string Bsex)
116 {
117 sex=Bsex;
118 race="Black";
119 }
120 public override void GetInfo()
121 {
122 Console.WriteLine("the "+race+" Person Info:"+sex);
123 tk=Thinking.Instance;
124 tk.Say();
125 }
126 }
127
128 public class WritePerson:Person
129 {
130 public WritePerson()
131 {
132 sex="Man";
133 race="Write";
134 }
135 public WritePerson(string Wsex)
136 {
137 sex=Wsex;
138 race="Write";
139 }
140 public override void GetInfo()
141 {
142 Console.WriteLine("the "+race+" Person Info:"+sex);
143 tk=Thinking.Instance;
144 tk.Say();
145 }
146 }
147 public class PersonSimFactory
148 {
149 public PersonSimFactory(){}
150 public Person GetPerson(string RaceType)
151 {
152 if (RaceType=="Yellow")
153 return new YellowPerson();
154 else
155 if (RaceType=="Black")
156 return new BlackPerson();
157 else
158 if (RaceType=="Write")
159 return new WritePerson();
160 else
161 return new YellowPerson();
162
163 }
164 }
165}
166
2
3 namespace Singleton
4 {
5 /**//**//**//// <summary>
6 ///============== Program Description==============
7 ///Name:Singleton.cs
8 ///Objective:Singleton
9 ///Date:2006-04-26
10 ///Written By coffee.liu
11 ///================================================
12 /// </summary>
13 class Class1
14 {
15 /**//**//**//// <summary>
16 /// 应用程序的主入口点。
17 /// </summary>
18 [STAThread]
19 static void Main(string[] args)
20 {
21 Thinking tk1,tk2,tk3;
22 PersonSimFactory PSF=new PersonSimFactory();
23 Person PP=PSF.GetPerson("Yellow");
24 tk1=PP.GetTk;
25 PP.GetInfo();
26 Console.WriteLine(".");
27 PP=PSF.GetPerson("Black");
28 tk2=PP.GetTk;
29 PP.GetInfo();
30 Console.WriteLine(".");
31 PP=PSF.GetPerson("Write");
32 tk3=PP.GetTk;
33 PP.GetInfo();
34 if ((tk1==tk2)&&(tk2==tk3)&&(tk1==tk3))
35 Console.WriteLine("we are the same Thinking");
36
37 }
38 }
39 /**//**//**//// <summary>
40 /// 每个人都有思维
41 /// Thinking类被定为sealed类即不能被其他类继承
42 /// 我们把instance定义成了 static readonly属性,
43 /// 如果类中的static属性被任何方法使用时,.NET Framework将对这个属性进行初始化,
44 /// 于是在初始化Instance属性的同时Thinking类实例得以创建和装载。
45 /// 而私有的构造函数和readonly(只读)保证了Thinking不会被再次实例化,
46 /// 从而实现了Singleton的目的。
47 /// </summary>
48
49 public sealed class Thinking
50 {
51 public static readonly Thinking instance=new Thinking();
52 private Thinking(){}
53
54 public static Thinking Instance
55 {
56 get
57 {
58 return instance;
59 }
60 }
61 public void Say(){
62 Console.WriteLine("I have a Thinking");
63 }
64
65 }
66
67 public class Person
68 {
69 protected Thinking tk;
70 protected string sex,race;
71 public Thinking GetTk
72 {
73 get {return tk;}
74 }
75 public string GetSex()
76 {
77 return sex;
78 }
79 public string GetRace()
80 {
81 return race;
82 }
83 public virtual void GetInfo()
84 {
85 }
86 }
87
88 public class YellowPerson:Person
89 {
90 public YellowPerson()
91 {
92 sex="Man";
93 race="Yellow";
94 }
95 public YellowPerson(string Ysex)
96 {
97 sex=Ysex;
98 race="Yellow";
99 }
100 public override void GetInfo()
101 {
102 Console.WriteLine("the "+race+" Person Info:"+sex);
103 tk=Thinking.Instance;
104 tk.Say();
105 }
106 }
107
108 public class BlackPerson:Person
109 {
110 public BlackPerson()
111 {
112 sex="Man";
113 race="Black";
114 }
115 public BlackPerson(string Bsex)
116 {
117 sex=Bsex;
118 race="Black";
119 }
120 public override void GetInfo()
121 {
122 Console.WriteLine("the "+race+" Person Info:"+sex);
123 tk=Thinking.Instance;
124 tk.Say();
125 }
126 }
127
128 public class WritePerson:Person
129 {
130 public WritePerson()
131 {
132 sex="Man";
133 race="Write";
134 }
135 public WritePerson(string Wsex)
136 {
137 sex=Wsex;
138 race="Write";
139 }
140 public override void GetInfo()
141 {
142 Console.WriteLine("the "+race+" Person Info:"+sex);
143 tk=Thinking.Instance;
144 tk.Say();
145 }
146 }
147 public class PersonSimFactory
148 {
149 public PersonSimFactory(){}
150 public Person GetPerson(string RaceType)
151 {
152 if (RaceType=="Yellow")
153 return new YellowPerson();
154 else
155 if (RaceType=="Black")
156 return new BlackPerson();
157 else
158 if (RaceType=="Write")
159 return new WritePerson();
160 else
161 return new YellowPerson();
162
163 }
164 }
165}
166
并且这样实现的Thinking类是线程安全的。
下面我们看看如何用Pascal语言,以类似静态方法来实现:
1
program singleton;
2 //============== Program Description ==============
3 // Name:singleton.dpr
4 // Objective:singleton
5 // Date : 2006 - 04 - 27
6 // Written By coffee.liu
7 //================================================
8 {$APPTYPE CONSOLE}
9
10 uses
11 SysUtils;
12 type Thinking = Class public class
13 public
14 Class functionclass Function GetInstance()function GetInstance():Thinking;
15 作为Delphi来说,不能将contructor设为private,如果设为private,编译器将自动将
16 constructor更正为public
17 我们在这里重载NewInstance静态方法来控制构造函数防止其创建出多个实例
18 Class functionclass Function NewInstance()function NewInstance:Tobject;override;
19 procedure FreeInstance;override;
20 public procedure Say;
21 end;
22 type Person=Class protectedclass
23 protected
24 sex:string;
25 race:string;
26 tk:Thinking;
27 Property GetThinking()property GetThinking:Thinking read tk;
28 public Function GetSex()function GetSex():string;
29 public Function GetRace()function GetRace():string;
30 public procedure GetInfo;virtual;abstract;
31
32 end;
33 type YellowPerson=Class (class(Person)
34 constructor YellowPerson();
35 public procedure GetInfo;override;
36 end;
37 type BlackPerson=Class (class(Person)
38 constructor BlackPerson();
39 public procedure GetInfo;override;
40 end;
41 type WritePerson=Class (class(Person)
42 constructor WritePerson();
43 public procedure GetInfo;override;
44 end;
45 type PersonSimFactory=Class constructorclass
46 constructor PersonSimFactory();
47 public Function GetPerson()function GetPerson(RaceType:string):Person;
48 end;
49var
50GlobalThinking:Thinking=nil;
51PSF:PersonSimFactory;
52PP:Person;
53{ Person }
54
55Function Person()function Person.GetRace: string;
56begin
57 result:=race;
58end;
59
60Function Person()function Person.GetSex: string;
61begin
62 result:=sex;
63end;
64
65{ YellowPerson }
66
67constructor YellowPerson.YellowPerson;
68begin
69 sex:='Man';
70 race:='Yellow';
71end;
72procedure YellowPerson.GetInfo;
73 begin
74 inherited;
75 WriteLn('the '+race+' Person Info:'+sex);
76 end;
77{ WritePerson }
78
79procedure WritePerson.GetInfo;
80begin
81 inherited;
82 WriteLn('the '+race+' Person Info:'+sex);
83end;
84
85constructor WritePerson.WritePerson;
86begin
87 sex:='Man';
88 race:='Write';
89end;
90
91{ BlackPerson }
92
93constructor BlackPerson.BlackPerson;
94begin
95 sex:='Man';
96 race:='Black';
97end;
98
99procedure BlackPerson.GetInfo;
100begin
101 inherited;
102 WriteLn('the '+race+' Person Info:'+sex);
103end;
104
105{ PersonSimFactory }
106
107Function PersonSimFactory()function PersonSimFactory.GetPerson(RaceType: string): Person;
108begin
109
110 if RaceType='Yellow' then
111 result:=YellowPerson.YellowPerson
112 else
113 if RaceType='Black' then
114 result:=BlackPerson.BlackPerson
115 else
116 if RaceType='Write' then
117 result:=WritePerson.WritePerson
118 else
119 result:=YellowPerson.YellowPerson;
120
121end;
122
123constructor PersonSimFactory.PersonSimFactory;
124begin
125 inherited;
126end;
127{ Thinking }
128
129procedure Thinking.FreeInstance;
130begin
131 inherited;
132 这里赋值nil是必要的,作为delphi来说一个对象被释放之后,它的实例对应的变量并不会自动设定为nil
133 这里涉及到VMT的实现机理,具体情况请查看相关帮助
134 GlobalThinking:=nil;
135end;
136
137Class functionclass Function Thinking()function Thinking.GetInstance: Thinking;
138begin
139 if not Assigned(GlobalThinking)then
140 GlobalThinking:=Thinking.Create();
141 result:= GlobalThinking;
142end;
143
144Class functionclass Function Thinking()function Thinking.NewInstance: Tobject;
145begin
146 if not Assigned(GlobalThinking)then
147 GlobalThinking:=Thinking(inherited NewInstance);
148 result:=GlobalThinking;
149end;
150procedure Thinking.Say;
151 begin
152 WriteLn('I have a thinking!');
153 end;
154var
155 tk1,tk2,tk3:Thinking;
156begin
157 PSF:=PersonSimFactory.PersonSimFactory;
158 PP:=PSF.GetPerson('Yellow');
159 PP.GetThinking.Say;
160 tk1:=PP.GetThinking;
161 PP.GetInfo;
162 WriteLn('..');
163 PP:=PSF.GetPerson('Black');
164 PP.GetThinking.Say;
165 tk2:=PP.GetThinking;
166 PP.GetInfo;
167 WriteLn('..');
168 PP:=PSF.GetPerson('Write');
169 PP.GetThinking.Say;
170 tk3:=PP.GetThinking;
171 PP.GetInfo;
172 WriteLn('..error.');
173 PP:=PSF.GetPerson('Write11');
174 PP.GetThinking.Say;
175 PP.GetInfo;
176 if (tk1=tk2)and(tk2=tk3)then
177 WriteLn('we are the same thinking!');
178end.
2 //============== Program Description ==============
3 // Name:singleton.dpr
4 // Objective:singleton
5 // Date : 2006 - 04 - 27
6 // Written By coffee.liu
7 //================================================
8 {$APPTYPE CONSOLE}
9
10 uses
11 SysUtils;
12 type Thinking = Class public class
13 public
14 Class functionclass Function GetInstance()function GetInstance():Thinking;
15 作为Delphi来说,不能将contructor设为private,如果设为private,编译器将自动将
16 constructor更正为public
17 我们在这里重载NewInstance静态方法来控制构造函数防止其创建出多个实例
18 Class functionclass Function NewInstance()function NewInstance:Tobject;override;
19 procedure FreeInstance;override;
20 public procedure Say;
21 end;
22 type Person=Class protectedclass
23 protected
24 sex:string;
25 race:string;
26 tk:Thinking;
27 Property GetThinking()property GetThinking:Thinking read tk;
28 public Function GetSex()function GetSex():string;
29 public Function GetRace()function GetRace():string;
30 public procedure GetInfo;virtual;abstract;
31
32 end;
33 type YellowPerson=Class (class(Person)
34 constructor YellowPerson();
35 public procedure GetInfo;override;
36 end;
37 type BlackPerson=Class (class(Person)
38 constructor BlackPerson();
39 public procedure GetInfo;override;
40 end;
41 type WritePerson=Class (class(Person)
42 constructor WritePerson();
43 public procedure GetInfo;override;
44 end;
45 type PersonSimFactory=Class constructorclass
46 constructor PersonSimFactory();
47 public Function GetPerson()function GetPerson(RaceType:string):Person;
48 end;
49var
50GlobalThinking:Thinking=nil;
51PSF:PersonSimFactory;
52PP:Person;
53{ Person }
54
55Function Person()function Person.GetRace: string;
56begin
57 result:=race;
58end;
59
60Function Person()function Person.GetSex: string;
61begin
62 result:=sex;
63end;
64
65{ YellowPerson }
66
67constructor YellowPerson.YellowPerson;
68begin
69 sex:='Man';
70 race:='Yellow';
71end;
72procedure YellowPerson.GetInfo;
73 begin
74 inherited;
75 WriteLn('the '+race+' Person Info:'+sex);
76 end;
77{ WritePerson }
78
79procedure WritePerson.GetInfo;
80begin
81 inherited;
82 WriteLn('the '+race+' Person Info:'+sex);
83end;
84
85constructor WritePerson.WritePerson;
86begin
87 sex:='Man';
88 race:='Write';
89end;
90
91{ BlackPerson }
92
93constructor BlackPerson.BlackPerson;
94begin
95 sex:='Man';
96 race:='Black';
97end;
98
99procedure BlackPerson.GetInfo;
100begin
101 inherited;
102 WriteLn('the '+race+' Person Info:'+sex);
103end;
104
105{ PersonSimFactory }
106
107Function PersonSimFactory()function PersonSimFactory.GetPerson(RaceType: string): Person;
108begin
109
110 if RaceType='Yellow' then
111 result:=YellowPerson.YellowPerson
112 else
113 if RaceType='Black' then
114 result:=BlackPerson.BlackPerson
115 else
116 if RaceType='Write' then
117 result:=WritePerson.WritePerson
118 else
119 result:=YellowPerson.YellowPerson;
120
121end;
122
123constructor PersonSimFactory.PersonSimFactory;
124begin
125 inherited;
126end;
127{ Thinking }
128
129procedure Thinking.FreeInstance;
130begin
131 inherited;
132 这里赋值nil是必要的,作为delphi来说一个对象被释放之后,它的实例对应的变量并不会自动设定为nil
133 这里涉及到VMT的实现机理,具体情况请查看相关帮助
134 GlobalThinking:=nil;
135end;
136
137Class functionclass Function Thinking()function Thinking.GetInstance: Thinking;
138begin
139 if not Assigned(GlobalThinking)then
140 GlobalThinking:=Thinking.Create();
141 result:= GlobalThinking;
142end;
143
144Class functionclass Function Thinking()function Thinking.NewInstance: Tobject;
145begin
146 if not Assigned(GlobalThinking)then
147 GlobalThinking:=Thinking(inherited NewInstance);
148 result:=GlobalThinking;
149end;
150procedure Thinking.Say;
151 begin
152 WriteLn('I have a thinking!');
153 end;
154var
155 tk1,tk2,tk3:Thinking;
156begin
157 PSF:=PersonSimFactory.PersonSimFactory;
158 PP:=PSF.GetPerson('Yellow');
159 PP.GetThinking.Say;
160 tk1:=PP.GetThinking;
161 PP.GetInfo;
162 WriteLn('..');
163 PP:=PSF.GetPerson('Black');
164 PP.GetThinking.Say;
165 tk2:=PP.GetThinking;
166 PP.GetInfo;
167 WriteLn('..');
168 PP:=PSF.GetPerson('Write');
169 PP.GetThinking.Say;
170 tk3:=PP.GetThinking;
171 PP.GetInfo;
172 WriteLn('..error.');
173 PP:=PSF.GetPerson('Write11');
174 PP.GetThinking.Say;
175 PP.GetInfo;
176 if (tk1=tk2)and(tk2=tk3)then
177 WriteLn('we are the same thinking!');
178end.
下面我们再看一个现实中的例子,连接池的问题。许多应用程序需要访问存储在数据库和其他数据源。要访问数据库中的数据,应用程序就需要建立到数据库的连接。然后,应用程序就可以使用连接进行数据访问。建立数据库连接会花相对较长的时间,因为在建立连接的过程中数据库服务器和应用程序之间必须进行协商。数据库连接也会消耗宝贵的系统资源,如CPU处理能力,内存,网络带宽。因此,很值得研究和应用技术来减少建立数据库连接的需要和活动连接数量。在这个前提下我们来看看程序代码:
1
using
System;
2 using System.Drawing;
3 using System.Collections;
4 using System.ComponentModel;
5 using System.Windows.Forms;
6 using System.Data;
7
8 using System.Data.SqlClient;
9 /**/ /// <summary>
10 ///============== Program Description==============
11 ///Name:PoolingTester.cs
12 ///Objective:PoolingTester
13 ///Date:2006-04-26
14 ///Written By coffee.liu
15 ///================================================
16 /// </summary>
17 namespace ConnectionPooling
18 {
19
20 public class PoolingTester : System.Windows.Forms.Form
21 {
22 private System.Windows.Forms.Label label1;
23 private System.Windows.Forms.TextBox txtNumberOfConnections;
24 private System.Windows.Forms.Button btnConnect;
25 private System.Windows.Forms.Button btnDisconnect;
26 private System.Windows.Forms.CheckBox chkPooling;
27 Pooling PL;
28 /**//// <summary>
29 /// Required designer variable.
30 /// </summary>
31 private System.ComponentModel.Container components = null;
32
33 public PoolingTester()
34 {
35 //
36 // Required for Windows Form Designer support
37 //
38 InitializeComponent();
39
40 // Enable the Connect button and
41 // disable the Disconnect button
42 EnableButtons(false);
43 }
44
45 /**//// <summary>
46 /// Clean up any resources being used.
47 /// </summary>
48 protected override void Dispose( bool disposing )
49 {
50 if( disposing )
51 {
52 if (components != null)
53 {
54 components.Dispose();
55 }
56 }
57 base.Dispose( disposing );
58 }
59
60 Windows Form Designer generated code#region Windows Form Designer generated code
61 /**//// <summary>
62 /// Required method for Designer support - do not modify
63 /// the contents of this method with the code editor.
64 /// </summary>
65 private void InitializeComponent()
66 {
67 this.btnDisconnect = new System.Windows.Forms.Button();
68 this.btnConnect = new System.Windows.Forms.Button();
69 this.txtNumberOfConnections = new System.Windows.Forms.TextBox();
70 this.label1 = new System.Windows.Forms.Label();
71 this.chkPooling = new System.Windows.Forms.CheckBox();
72 this.SuspendLayout();
73 //
74 // btnDisconnect
75 //
76 this.btnDisconnect.Location = new System.Drawing.Point(280, 40);
77 this.btnDisconnect.Name = "btnDisconnect";
78 this.btnDisconnect.Size = new System.Drawing.Size(96, 23);
79 this.btnDisconnect.TabIndex = 2;
80 this.btnDisconnect.Text = "Disconnect";
81 this.btnDisconnect.Click += new System.EventHandler(this.btnDisconnect_Click);
82 //
83 // btnConnect
84 //
85 this.btnConnect.Location = new System.Drawing.Point(280, 8);
86 this.btnConnect.Name = "btnConnect";
87 this.btnConnect.Size = new System.Drawing.Size(96, 23);
88 this.btnConnect.TabIndex = 2;
89 this.btnConnect.Text = "Connect";
90 this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);
91 //
92 // txtNumberOfConnections
93 //
94 this.txtNumberOfConnections.Location = new System.Drawing.Point(176, 8);
95 this.txtNumberOfConnections.Name = "txtNumberOfConnections";
96 this.txtNumberOfConnections.TabIndex = 1;
97 this.txtNumberOfConnections.Text = "";
98 //
99 // label1
100 //
101 this.label1.Location = new System.Drawing.Point(8, 8);
102 this.label1.Name = "label1";
103 this.label1.Size = new System.Drawing.Size(168, 23);
104 this.label1.TabIndex = 0;
105 this.label1.Text = "Number of Connections:";
106 //
107 // chkPooling
108 //
109 this.chkPooling.Location = new System.Drawing.Point(8, 40);
110 this.chkPooling.Name = "chkPooling";
111 this.chkPooling.Size = new System.Drawing.Size(264, 24);
112 this.chkPooling.TabIndex = 3;
113 this.chkPooling.Text = "Pool Connections";
114 //
115 // PoolingTester
116 //
117 this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
118 this.ClientSize = new System.Drawing.Size(384, 72);
119 this.Controls.AddRange(new System.Windows.Forms.Control[] {
120 this.chkPooling,
121 this.btnDisconnect,
122 this.btnConnect,
123 this.txtNumberOfConnections,
124 this.label1});
125 this.Name = "PoolingTester";
126 this.Text = "ADO.NET Connection Pooling Test Form";
127 this.ResumeLayout(false);
128
129 }
130 #endregion
131
132 /**//// <summary>
133 /// The main entry point for the application.
134 /// </summary>
135 [STAThread]
136 static void Main()
137 {
138 Application.Run(new PoolingTester());
139 }
140
141 // Connect to database
142 private void btnConnect_Click(object sender, System.EventArgs e)
143 {
144 //create Pooling object
145 this.PL=Pooling.Instance;
146 PL.Connect(Convert.ToInt32(txtNumberOfConnections.Text), chkPooling.Checked);
147 EnableButtons(true);
148 }
149
150 // Disconnect from the database
151 private void btnDisconnect_Click(object sender, System.EventArgs e)
152 {
153 //create Pooling object
154 this.PL=Pooling.Instance;
155 PL.Disconnect();
156 EnableButtons(false);
157 }
158
159 // Enable the Connect and Disconnect buttons depending on
160 // whether or not it is connected to the database
161 private void EnableButtons(bool Connected)
162 {
163 btnConnect.Enabled = !Connected;
164 btnDisconnect.Enabled = Connected;
165 }
166
167
168 }
169 sealed class Pooling
170 {
171 private static bool balancer=false;
172 private Pooling(){}
173 public static readonly Pooling instance=new Pooling();
174
175 public static Pooling Instance
176 {
177 get
178 {
179 return instance;
180 }
181 }
182 private ArrayList mConnectionArray = null;
183 private const string mcConnString =
184 "Data Source=(local);" +
185 "Integrated Security=SSPI;" +
186 "Initial Catalog=Northwind";
187 public void Disconnect()
188 {
189
190 balancer=true;
191 foreach (SqlConnection cn in mConnectionArray)
192 {
193 cn.Close();
194 }
195 }
196 public void Connect(int NumberOfConnections, bool PoolConnections)
197 {
198 lock (typeof(Pooling))
199 {
200 balancer=false;
201 string ConnString = mcConnString + ";Pooling=" + PoolConnections;
202
203 mConnectionArray = new ArrayList(NumberOfConnections);
204 for (int Idx = 0; Idx < NumberOfConnections; ++Idx)
205 {
206 SqlConnection cn = new SqlConnection(ConnString);
207 cn.Open();
208 mConnectionArray.Add(cn);
209 }
210 }
211 }
212 }
213}
214
2 using System.Drawing;
3 using System.Collections;
4 using System.ComponentModel;
5 using System.Windows.Forms;
6 using System.Data;
7
8 using System.Data.SqlClient;
9 /**/ /// <summary>
10 ///============== Program Description==============
11 ///Name:PoolingTester.cs
12 ///Objective:PoolingTester
13 ///Date:2006-04-26
14 ///Written By coffee.liu
15 ///================================================
16 /// </summary>
17 namespace ConnectionPooling
18 {
19
20 public class PoolingTester : System.Windows.Forms.Form
21 {
22 private System.Windows.Forms.Label label1;
23 private System.Windows.Forms.TextBox txtNumberOfConnections;
24 private System.Windows.Forms.Button btnConnect;
25 private System.Windows.Forms.Button btnDisconnect;
26 private System.Windows.Forms.CheckBox chkPooling;
27 Pooling PL;
28 /**//// <summary>
29 /// Required designer variable.
30 /// </summary>
31 private System.ComponentModel.Container components = null;
32
33 public PoolingTester()
34 {
35 //
36 // Required for Windows Form Designer support
37 //
38 InitializeComponent();
39
40 // Enable the Connect button and
41 // disable the Disconnect button
42 EnableButtons(false);
43 }
44
45 /**//// <summary>
46 /// Clean up any resources being used.
47 /// </summary>
48 protected override void Dispose( bool disposing )
49 {
50 if( disposing )
51 {
52 if (components != null)
53 {
54 components.Dispose();
55 }
56 }
57 base.Dispose( disposing );
58 }
59
60 Windows Form Designer generated code#region Windows Form Designer generated code
61 /**//// <summary>
62 /// Required method for Designer support - do not modify
63 /// the contents of this method with the code editor.
64 /// </summary>
65 private void InitializeComponent()
66 {
67 this.btnDisconnect = new System.Windows.Forms.Button();
68 this.btnConnect = new System.Windows.Forms.Button();
69 this.txtNumberOfConnections = new System.Windows.Forms.TextBox();
70 this.label1 = new System.Windows.Forms.Label();
71 this.chkPooling = new System.Windows.Forms.CheckBox();
72 this.SuspendLayout();
73 //
74 // btnDisconnect
75 //
76 this.btnDisconnect.Location = new System.Drawing.Point(280, 40);
77 this.btnDisconnect.Name = "btnDisconnect";
78 this.btnDisconnect.Size = new System.Drawing.Size(96, 23);
79 this.btnDisconnect.TabIndex = 2;
80 this.btnDisconnect.Text = "Disconnect";
81 this.btnDisconnect.Click += new System.EventHandler(this.btnDisconnect_Click);
82 //
83 // btnConnect
84 //
85 this.btnConnect.Location = new System.Drawing.Point(280, 8);
86 this.btnConnect.Name = "btnConnect";
87 this.btnConnect.Size = new System.Drawing.Size(96, 23);
88 this.btnConnect.TabIndex = 2;
89 this.btnConnect.Text = "Connect";
90 this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);
91 //
92 // txtNumberOfConnections
93 //
94 this.txtNumberOfConnections.Location = new System.Drawing.Point(176, 8);
95 this.txtNumberOfConnections.Name = "txtNumberOfConnections";
96 this.txtNumberOfConnections.TabIndex = 1;
97 this.txtNumberOfConnections.Text = "";
98 //
99 // label1
100 //
101 this.label1.Location = new System.Drawing.Point(8, 8);
102 this.label1.Name = "label1";
103 this.label1.Size = new System.Drawing.Size(168, 23);
104 this.label1.TabIndex = 0;
105 this.label1.Text = "Number of Connections:";
106 //
107 // chkPooling
108 //
109 this.chkPooling.Location = new System.Drawing.Point(8, 40);
110 this.chkPooling.Name = "chkPooling";
111 this.chkPooling.Size = new System.Drawing.Size(264, 24);
112 this.chkPooling.TabIndex = 3;
113 this.chkPooling.Text = "Pool Connections";
114 //
115 // PoolingTester
116 //
117 this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
118 this.ClientSize = new System.Drawing.Size(384, 72);
119 this.Controls.AddRange(new System.Windows.Forms.Control[] {
120 this.chkPooling,
121 this.btnDisconnect,
122 this.btnConnect,
123 this.txtNumberOfConnections,
124 this.label1});
125 this.Name = "PoolingTester";
126 this.Text = "ADO.NET Connection Pooling Test Form";
127 this.ResumeLayout(false);
128
129 }
130 #endregion
131
132 /**//// <summary>
133 /// The main entry point for the application.
134 /// </summary>
135 [STAThread]
136 static void Main()
137 {
138 Application.Run(new PoolingTester());
139 }
140
141 // Connect to database
142 private void btnConnect_Click(object sender, System.EventArgs e)
143 {
144 //create Pooling object
145 this.PL=Pooling.Instance;
146 PL.Connect(Convert.ToInt32(txtNumberOfConnections.Text), chkPooling.Checked);
147 EnableButtons(true);
148 }
149
150 // Disconnect from the database
151 private void btnDisconnect_Click(object sender, System.EventArgs e)
152 {
153 //create Pooling object
154 this.PL=Pooling.Instance;
155 PL.Disconnect();
156 EnableButtons(false);
157 }
158
159 // Enable the Connect and Disconnect buttons depending on
160 // whether or not it is connected to the database
161 private void EnableButtons(bool Connected)
162 {
163 btnConnect.Enabled = !Connected;
164 btnDisconnect.Enabled = Connected;
165 }
166
167
168 }
169 sealed class Pooling
170 {
171 private static bool balancer=false;
172 private Pooling(){}
173 public static readonly Pooling instance=new Pooling();
174
175 public static Pooling Instance
176 {
177 get
178 {
179 return instance;
180 }
181 }
182 private ArrayList mConnectionArray = null;
183 private const string mcConnString =
184 "Data Source=(local);" +
185 "Integrated Security=SSPI;" +
186 "Initial Catalog=Northwind";
187 public void Disconnect()
188 {
189
190 balancer=true;
191 foreach (SqlConnection cn in mConnectionArray)
192 {
193 cn.Close();
194 }
195 }
196 public void Connect(int NumberOfConnections, bool PoolConnections)
197 {
198 lock (typeof(Pooling))
199 {
200 balancer=false;
201 string ConnString = mcConnString + ";Pooling=" + PoolConnections;
202
203 mConnectionArray = new ArrayList(NumberOfConnections);
204 for (int Idx = 0; Idx < NumberOfConnections; ++Idx)
205 {
206 SqlConnection cn = new SqlConnection(ConnString);
207 cn.Open();
208 mConnectionArray.Add(cn);
209 }
210 }
211 }
212 }
213}
214
看看Pascal的实现:
1
unit PoolingTester1;
2
3 interface
4
5 uses
6 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7 Dialogs, StdCtrls,ADODB, DB;
8
9 type
10 TForm1 = class(TForm)
11 Button1: TButton;
12 procedure Button1Click(Sender: TObject);
13 private
14 { Private declarations }
15 public
16 { Public declarations }
17 end ;
18 const mcConnString = ' Provider=SQLOLEDB.1;Integrated Security=SSPI; '
19 + ' Persist Security Info=False;User ID=sa;Initial Catalog=Northwind ' ;
20
21 type Pooling = class
22 private
23 mConnectionArray :TList;
24 public
25 procedure Disconnect();
26 procedure Connect(NumberOfConnections: integer ;PoolConnections:boolean);
27 Class Function GetInstance():Pooling;
28 class Function NewInstance():Tobject;override;
29 procedure FreeInstance;override;
30
31 end ;
32 var
33 Form1: TForm1;
34 CriticalSection:TRTLCriticalSection;
35 GlobalPooling:Pooling = nil;
36 implementation
37
38 {$R * .dfm}
39
40 { Pooling }
41 procedure Pooling.Connect(NumberOfConnections: integer ;
42 PoolConnections: boolean);
43 var
44 i: integer ;
45 ADOcnArr:array of TADOConnection;
46 ConnString:string;
47 begin
48 EnterCriticalSection(CriticalSection); // 进入临界区
49 mConnectionArray: = TList. Create ;
50 setlength(ADOcnArr,NumberOfConnections);
51 for i: = 0 to NumberOfConnections - 1 do
52 begin
53 ConnString: = mcConnString + ' ;Pooling= ' + booltostr(PoolConnections,true);
54 ADOcnArr [ i ] : = TADOConnection. Create (Application);
55 ADOcnArr [ i ] .ConnectionString: = ConnString;
56 ADOcnArr [ i ] .LoginPrompt: = false;
57 ADOcnArr [ i ] .Connected: = true;
58 mConnectionArray. Add (ADOcnArr [ i ] );
59 end ;
60 LeaveCriticalSection(CriticalSection); // 离开临界区
61 end ;
62
63 procedure Pooling.Disconnect;
64 var
65 i: integer ;
66 begin
67 for i: = 0 to mConnectionArray. Count - 1 do
68 begin
69 TADOConnection(mConnectionArray.Items [ i ] ).Connected: = false;
70 end ;
71 end ;
72
73 procedure Pooling.FreeInstance;
74 begin
75 inherited;
76 GlobalPooling: = nil;
77 end ;
78
79 class function Pooling.GetInstance: Pooling;
80 begin
81 if not Assigned(GlobalPooling) then
82 GlobalPooling: = Pooling. Create ;
83 result: = GlobalPooling;
84
85 end ;
86
87 class function Pooling.NewInstance: Tobject;
88 begin
89 if not Assigned(GlobalPooling) then
90 GlobalPooling: = Pooling(inherited NewInstance);
91 result: = GlobalPooling;
92 end ;
93
94
95 procedure TForm1.Button1Click(Sender: TObject);
96 begin
97 try
98 InitializeCriticalSection(CriticalSection); // 初始化临界区
99 GlobalPooling: = Pooling. Create ;
100 GlobalPooling.Connect( 20 ,true);
101 finally
102 GlobalPooling.Disconnect;
103 end ;
104 end ;
105
106 end .
2
3 interface
4
5 uses
6 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7 Dialogs, StdCtrls,ADODB, DB;
8
9 type
10 TForm1 = class(TForm)
11 Button1: TButton;
12 procedure Button1Click(Sender: TObject);
13 private
14 { Private declarations }
15 public
16 { Public declarations }
17 end ;
18 const mcConnString = ' Provider=SQLOLEDB.1;Integrated Security=SSPI; '
19 + ' Persist Security Info=False;User ID=sa;Initial Catalog=Northwind ' ;
20
21 type Pooling = class
22 private
23 mConnectionArray :TList;
24 public
25 procedure Disconnect();
26 procedure Connect(NumberOfConnections: integer ;PoolConnections:boolean);
27 Class Function GetInstance():Pooling;
28 class Function NewInstance():Tobject;override;
29 procedure FreeInstance;override;
30
31 end ;
32 var
33 Form1: TForm1;
34 CriticalSection:TRTLCriticalSection;
35 GlobalPooling:Pooling = nil;
36 implementation
37
38 {$R * .dfm}
39
40 { Pooling }
41 procedure Pooling.Connect(NumberOfConnections: integer ;
42 PoolConnections: boolean);
43 var
44 i: integer ;
45 ADOcnArr:array of TADOConnection;
46 ConnString:string;
47 begin
48 EnterCriticalSection(CriticalSection); // 进入临界区
49 mConnectionArray: = TList. Create ;
50 setlength(ADOcnArr,NumberOfConnections);
51 for i: = 0 to NumberOfConnections - 1 do
52 begin
53 ConnString: = mcConnString + ' ;Pooling= ' + booltostr(PoolConnections,true);
54 ADOcnArr [ i ] : = TADOConnection. Create (Application);
55 ADOcnArr [ i ] .ConnectionString: = ConnString;
56 ADOcnArr [ i ] .LoginPrompt: = false;
57 ADOcnArr [ i ] .Connected: = true;
58 mConnectionArray. Add (ADOcnArr [ i ] );
59 end ;
60 LeaveCriticalSection(CriticalSection); // 离开临界区
61 end ;
62
63 procedure Pooling.Disconnect;
64 var
65 i: integer ;
66 begin
67 for i: = 0 to mConnectionArray. Count - 1 do
68 begin
69 TADOConnection(mConnectionArray.Items [ i ] ).Connected: = false;
70 end ;
71 end ;
72
73 procedure Pooling.FreeInstance;
74 begin
75 inherited;
76 GlobalPooling: = nil;
77 end ;
78
79 class function Pooling.GetInstance: Pooling;
80 begin
81 if not Assigned(GlobalPooling) then
82 GlobalPooling: = Pooling. Create ;
83 result: = GlobalPooling;
84
85 end ;
86
87 class function Pooling.NewInstance: Tobject;
88 begin
89 if not Assigned(GlobalPooling) then
90 GlobalPooling: = Pooling(inherited NewInstance);
91 result: = GlobalPooling;
92 end ;
93
94
95 procedure TForm1.Button1Click(Sender: TObject);
96 begin
97 try
98 InitializeCriticalSection(CriticalSection); // 初始化临界区
99 GlobalPooling: = Pooling. Create ;
100 GlobalPooling.Connect( 20 ,true);
101 finally
102 GlobalPooling.Disconnect;
103 end ;
104 end ;
105
106 end .
在这个例子中我们可以看到Pooling这个连接池类是个Singleton类。即无论PoolingTester被实例化多少次,我们Pooling只会被初始化一次。以上思路可以用在Web应用程序中,由于IIS本身是作为COM+应用程序安装的,就COM+而言,同一个Web应用程序中的所有网页都在一个进程中运行。因此,它们也可共享相同的连接库。