在做系統的時候有意識的用到了抽象工廠這個設計模式,主要解決的是數據庫更換的問題。
下面就以簡單的登錄來逐步的分析一下這個模式。
經典的三層架構
數據庫如下
1.
一般的數據庫連接方式
界面層
1:
Public
Class
Login
2:
Private
Sub
btnLogin_Click(
ByVal
sender
As
System.
Object
,
ByVal
e
As
System.EventArgs)
Handles
btnLogin.Click
3:
Dim
LUser
As
New
Entity.User
4:
Dim
BCheck
As
New
BLL.B_Login
5:
LUser.User_ID = txtName.Text
6:
LUser.User_Pwd = txtPwd.Text
7:
If
BCheck.Check(LUser) =
True
Then
8:
MsgBox(
"登錄成功!"
)
9:
Else
10:
MsgBox(“
"登錄失??!"
)
11:
End
If
12:
End
Sub
13:
14:
Private
Sub
btnCancle_Click(
ByVal
sender
As
System.
Object
,
ByVal
e
As
System.EventArgs)
Handles
btnCancle.Click
15:
End
16:
End
Sub
17:
End
Class
<style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style> <style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style> <style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style>
業務邏輯層
1:
Public
Class
B_Login
2:
Function
Check(
ByVal
User
As
Entity.User)
As
Boolean
3:
Dim
DaUser
As
New
DAL.D_UserInfo
4:
Dim
BlUser
As
New
Entity.User
5:
BlUser = DaUser.Check(User)
6:
If
BlUser.User_Pwd = User.User_Pwd
Then
7:
Return
True
8:
Else
9:
Return
False
10:
End
If
11:
End
Function
12:
End
Class
<style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style> <style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style>
數據持久層
1:
Imports
System.Data.SqlClient
2:
Public
Class
D_UserInfo
3:
Dim
ConnStr
As
String
=
"Data Source=******;Initial Catalog=Student;User ID=sa;Password=******"
4:
Dim
conn
As
SqlConnection =
New
SqlConnection(ConnStr)
5:
Function
Check(
ByVal
User
As
Entity.User)
As
Entity.User
6:
Dim
sql
As
String
=
"select * from UserInfo where UserInfo="
& User.User_ID
7:
Dim
cmd
As
SqlCommand =
New
SqlCommand(sql, conn)
8:
Dim
read
As
SqlDataReader
9:
Try
10:
conn.Open()
11:
read = cmd.ExecuteReader
12:
User.User_ID = read.Item(0)
13:
User.User_Pwd = read.Item(1)
14:
Return
User
15:
Catch
ex
As
Exception
16:
User.User_Pwd =
""
17:
Return
User
18:
End
Try
19:
End
Function
20:
End
Class
<style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style>
2.
簡單工廠
添加一個工廠類和一個接口
接口類
1:
Public
Interface
IUserInfo
2:
Function
Check(
ByVal
IUser
As
Entity.User)
As
Entity.User
3:
End
Interface
<style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style> <style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style>
工廠類
1:
Imports
[
Interface
]
2:
Public
Class
DFactory
3:
'Dim DataBase As String = "Access"
4:
Dim
DataBase
As
String
=
"Sql"
5:
Function
CreateUserInfo()
As
IUserInfo
6:
Dim
DB
As
IUserInfo
7:
Select
Case
DataBase
8:
Case
"Sql"
9:
DB =
New
D_UserInfoSql
10:
'Case "Access"
11:
' DB = New D_UserInfoAccess
12:
End
Select
13:
Return
DB
14:
End
Function
15:
End
Class
<style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style> <style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style>
當然
D_UserInfoSql
實現接口,代碼基本不變
當有新的數據庫使用時候(例如
Access
數據庫)可以將工廠中的注釋部分添上,然后重新寫
Dal
層就可以直接使用,但是這樣的不足是還是需要再次編譯工廠,利用反射可以解決這個問題。
3.
抽象工廠加反射
工廠類
1:
Imports
[
Interface
]
2:
Imports
System.Reflection
3:
Public
Class
DFactory
4:
'抽象工廠加反射
5:
Dim
DBString
As
String
= System.Configuration.ConfigurationSettings.AppSettings(
"DBString"
)
6:
Function
CreateUserInfo()
As
IUserInfo
7:
Return
CType
(
Assembly
.Load(
"DAL"
).CreateInstance(
"DAL.D_UserInfo"
& DBString), IUserInfo)
8:
End
Function
9:
End
Class
<style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style>
數據持久層
1:
Imports
System.Data.SqlClient
2:
Public
Class
D_UserInfoSql :
Implements
[
Interface
].IUserInfo
3:
'Dim ConnStr As String = "Data Source=******;Initial Catalog=Student;User ID=sa;Password=******"
4:
Dim
ConnStr
As
String
= System.Configuration.ConfigurationSettings.AppSettings(
"ConnStr"
)
5:
Dim
conn
As
SqlConnection =
New
SqlConnection(ConnStr)
6:
Public
Function
Check(
ByVal
IUser
As
Entity.User)
As
Entity.User
Implements
[
Interface
].IUserInfo.Check
7:
Dim
sql
As
String
=
"select * from UserInfo where UserInfo="
& IUser.User_ID
8:
Dim
cmd
As
SqlCommand =
New
SqlCommand(sql, conn)
9:
Dim
read
As
SqlDataReader
10:
Try
11:
conn.Open()
12:
read = cmd.ExecuteReader
13:
IUser.User_ID = read.Item(0)
14:
IUser.User_Pwd = read.Item(1)
15:
Return
IUser
16:
Catch
ex
As
Exception
17:
IUser.User_Pwd =
""
18:
Return
IUser
19:
End
Try
20:
End
Function
21:
End
Class
<style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style>
配置文件
1:
<
appSettings
>
2:
<
add
key
="ConnStr"
value
="Data Source=******;Initial Catalog=Student;User ID=sa;Password=******"
></
add
>
3:
<
add
key
="DBString"
value
="Sql"
></
add
>
4:
</
appSettings
>
<style type="text/css"> <!-- .csharpcode, .csharpcode pre {font-size:small; color:black; font-family:consolas,"Courier New",courier,monospace; background-color:#ffffff} .csharpcode pre {margin:0em} .csharpcode .rem {color:#008000} .csharpcode .kwrd {color:#0000ff} .csharpcode .str {color:#006080} .csharpcode .op {color:#0000c0} .csharpcode .preproc {color:#cc6633} .csharpcode .asp {background-color:#ffff00} .csharpcode .html {color:#800000} .csharpcode .attr {color:#ff0000} .csharpcode .alt {background-color:#f4f4f4; width:100%; margin:0em} .csharpcode .lnum {color:#606060} --> </style>
添加兩個
Key
,一個是連接數據庫的字符串,一個是通過反射來產生不同數據庫的
Dal
層的
這樣一來就可以實現設計模式中的“開閉原則”,如果更換數據庫只需要增加類(DAL),而不需要更改,更不需要重新編譯。
PS
:
配置文件必須在界面層
1、
反射的寫法
:
objType=Assembly.Load(AssemblyPath).CreateInstance(className);
其中:
AssemblyPath
指程序集名。
className
指命名空間
.
類名稱。
2、
反射的一個原則
:
一切皆以
UI
層的
bin
文件夾中的
dll
名稱為中心。
(
原因很簡單
:.net
類加載的機制就是默認從本程序集的
bin
文件中找
,
所以
bin
文件夾中一定要有要加載的程序集的
dll)
。
UI
層中
bin
文件夾中
dll
叫什么名字
AssemblyPath
就使用什么名字
,bin
內部類的全名叫什么,
className
就寫成什么全名。
.net
中的引用
:
加入對某個程序集的引用就能在程序集有變化時自動拷貝
dll
。
三層架構之抽象工廠加反射——實現數據庫轉換