分層
分層是為了減少層與層之間的依賴,增加程序的可讀性,讓整個系統結構清晰明確,還可大大降低維護成本,但是分層也有一定的缺點,有些可以直接訪問數據庫的層,卻要通過負責訪問數據庫的層進行訪問,這樣,在訪問數據庫過程中就多出一個環節,增加了系統的開銷,有時候要在表示層增加某個功能,為了降低耦合,就不得不自上而下,在每一層裡面增加這個功能所需的服務類,這樣就增加了開發成本
分層越多越好嗎?答案是否定的,引用一句話“我們也要 時刻謹記:不能盲目分層,不應分層而分層不應模式而模式。這是很重要的。不然只能增加開發的負擔(在今後的實踐中更好的體會)。”應該是說要根據實際的情況進行分層,畢竟不是絕對的,因為有些系統不分層比分層有點更多一些。
基本的分層主要用的是三層架構:
表示層(UI)
主要用於與用戶的交互,負責傳達用戶的指令以及數據給BLL層,並把用戶需要的數據顯示出來,通俗的講就是用戶能見到的界面,如窗體程序。
業務邏輯層(BLL)
對數據的邏輯處理,比如把訪問數據庫得到的數據,轉換成用戶向看到的數據,並提交給表示層進行顯示。
數據訪問層(DAL)
對數據庫進行訪問,提供增刪改查等操作。
下面是我的包圖,每個包就是一個層,其中增加了實體層(Model)、接口層(IDAL)和工廠層(Factory)
實體層(Model)
實際上就是對應的數據庫裡面的每一張表,一個表就建一個類,一個類裡面的屬性則是對應表裡面的字段,比如表BaseData_Info
在實體層中,就可以這樣建立一個類:
Public Class BaseDataEntity Inherits Entity Private FixedUserHalfHourCost As Single '固定用戶半小時花費 Public Property FixdUserHalfHourCost_ As Single Get Return FixedUserHalfHourCost End Get Set(value As Single) FixedUserHalfHourCost = value End Set End Property Private CasualUserAnHourCost As Single '臨時用戶一小時花費 Public Property CasualUserAnHourCost_ As Single Get Return CasualUserAnHourCost End Get Set(value As Single) CasualUserAnHourCost = value End Set End Property Private IncreasingUnitTime As Single '單位遞增時間 Public Property IncreasingUnitTime_ As Single Get Return IncreasingUnitTime End Get Set(value As Single) IncreasingUnitTime = value End Set End Property Private AtleastOnlineTime As Single '最少在線時間 Public Property AtleastOnlineTime_ As Single Get Return AtleastOnlineTime End Get Set(value As Single) AtleastOnlineTime = value End Set End Property Private ReadyTime As Single '准備時間 Public Property ReadyTime_ As Single Get Return ReadyTime End Get Set(value As Single) ReadyTime = value End Set End Property Private AtleastMoney As Single '最少金額 Public Property AtleastMoney_ As Single Get Return AtleastMoney End Get Set(value As Single) AtleastMoney = value End Set End Property End Class
有什麼用呢?當你需要注冊一個用戶時候,你得從表示層(UI)把數據傳遞給用於訪問數據庫的數據訪問層(DAL),但是,你不可能把用戶注冊的信息:學號,姓名,卡號,注冊日期,注冊時間,班級。。。。。。等等把參數傳遞給函數,進行增加行操作吧?
’你該不會真的這麼傳值吧?被嚇到了 AddUser(StudentID,StudentName,CardID,RegisterDate,RegisterTime,Class。。。。。。) ’而如果你把這些數據封裝成一個類,如上述,你只需要傳遞一個類就行了 AddUser(UserInfo)
對於數據庫的訪問,基本上什麼語言都離不開這麼幾步:
1. 連接數據庫
2. 執行sql語句
3. 返回sql語句的執行結構
而連接數據庫的字符串,大家可以參考數據庫連接字符串大全
執行sql語句可以參考sql語句大全
下面是一個簡單的數據庫訪問例子:
ImportsSystem.Data.SqlClient ’引用sql客戶端 Public Class SelectDAL Public Overloads Function SelectInfo(ByVal Table As String) '查詢整張表 Dim DataS As New DataSet Try Dim SelectStr As String = "select * from " & Table '查詢語句 Dim ConnectStr As String ="Data Source=服務器名/服務器地址;Initial Catalog=數據庫名; UserID=sa;Password=123"'數據庫連接字符串 Dim DBConnection As New SqlConnection(ConnectStr) '初始化數據庫連接對象 DBConnection.Open() '連接數據庫 'Dim DBCmd As New SqlCommand(SelectStr,DBConnection) '執行查詢語句 Dim Adapter As New SqlDataAdapter(SelectStr,DBConnection) '把查詢結果保存到緩存中 Adapter.Fill(DataS, Table) '把緩存中的表以Table為名保存到DataSet中 Catch ex As Exception Throw New ArgumentOutOfRangeException(""& ex.Message) End Try Return DataS End Function
其中連接數據庫要用到的對象是SqlConnection,執行查詢語句以及返回結果用的是SqlDataAdapter對象。
數據庫的連接有很多種方式,如本地、遠程等。只要參考參考數據庫連接字符串,依據自身情況進行選擇使用就可以達到目的。
對於反射,一開始我非常的茫然,在設計模式裡面敲了例子之後,查了很多資料,也不知道怎麼應用到收費系統中,確實笨到家了。不過,後來看到了高人的博客,才會了。看下圖:
假如說你有BLL和DAL2個層,你希望在BLL裡面的一個類A使用DAL裡面的BalanceDAL類,你可以通過引用DAL從而達到目的,但是,據說為了減少BLL與DAL的耦合性,所以在BLL和DAL之間加了個接口層叫IDAL。如下圖
可以看到框中的是上面DAL裡面BalanceDAL的接口,這個接口裡面包含了具體類(BalanceDAL)的所有方法,所以我們只要調用接口,就相當於調用了具體類(BalanceDAL),但是,前提是你必須把接口和具體類接通,就好比電視機和遙控器,遙控器是電視機接口,要想遙控器能控制接口,電視機裡面應該要有一個能夠接收並處理紅外線新號的裝置,當你使用遙控器的時候,遙控器跟電視機是聯通的,他們之間通過了紅外線聯通。事實上,接口與具體類之間的關系,只是兩者之間創建了一條管道,接口中沒有具體的功能,但卻有那個具體類使用的一個方法(就像遙控器上的按鍵),如果遙控器跟電視機之間沒有聯通,那麼你按一下遙控器,是不會實現開機或者調頻等功能的,所以,要使用接口,必須讓接口與具體實現的類進行聯通,這裡有兩步走,第一步是引用,第二步是創建實例。看下圖:
在DAL的引用裡把IDAL打上勾就行了也就相當於在這兩個層之間架起了橋梁,接下來,我們讓DAL來實現這個接口,也就是在DAL裡面創建具體類之後,寫上關鍵字+你要實現的接口,然後回車,它就會自動列出你在接口裡寫的方法,然後再方法裡,你去具體的實現吧。
然後,我們需要在橋梁上面加管道,加了管道,就是把接口的方法和具體類的方法連接起來,使得我在BLL層裡面調用接口的方法,就相當於調用了具體類的方法,但是我BLL並不知道具體類到底是怎麼實現的,據說,這就是降低了BLL層與DAL層之間的耦合,因為我只關心接口IDAL就行了。如下代碼,看BLL裡是如何使用接口
Imports System.Reflection ’反射的引用 Public ClassBalanceBLL FunctionBalanceQuery(ByVal CardID AsString) IfCardID = "" Then ThrowNewArgumentOutOfRangeException("","請輸入卡號:") EndIf DimIBalance As IDAL.IBalance '余額接口 IBalance = CType(Assembly.Load("DAL").CreateInstance("DAL.BalanceDAL"),IDAL.IBalance) '得到余額類 DimDS As NewDataSet Try DS = IBalance.SelectBalanceInfo(CardID) '查詢並返回數據集結果 IfDS.Tables(0).Rows.Count < 1 Then Throw NewArgumentOutOfRangeException("","沒有這個卡號的余額記錄") EndIf Catchex As Exception ThrowNewArgumentOutOfRangeException("",ex.Message) EndTry ReturnDS EndFunction
這裡,我們首先引用了反射,然後創建接口(IBalance),再然後就是通過反射,把DAL層裡的BalanceDAL具體類的實例反射過來給接口,這樣,我們就相當於在接口和具體類之間連接了管道,然後我們就可以使用具體類的方法了:IBalance.SelectBalanceInfo(CardID)'查詢並返回數據集結果
後來發現,把DAL層裡面的類反射到BLL層裡面,也就相當於在BLL層裡面生產了DAL層的類,然後反射得到具體類的那些代碼,我便抽象出了一個層,名曰Factory層,只要BLL引用工廠,便可以通過工廠返回具體類了。這也就是反射+工廠的應用吧。
好像寫的有點長,本來還有重載、配置文件、異常處理、存儲過程等比較實用點的技術要寫的,算了,放到下一篇吧。希望對大家有幫助。
雖說面向對象比較復雜,但是總體的感覺,它就是把很多復雜的東西分類、分塊、分層、分......然後用線把他們竄起來,你不必完全的記住所有的分塊,但你可以順著那些圖紙毫不保留的了解到細節,只要去習慣這樣的思維方式,相信也不太難的。
作者:csdn博客 羅智福