前面寫了這么多,很大程度上就是為了這一章做準備。面向對象或者領域驅動,最重要的一點就是要忘記數據庫!我花了很長很長的時間,才理解了這一點,從而真正的邁向一個嶄新的天地;而后,我又花了很長很長的時間,才勉強做到這一點;我希望,有一天,這將不再是一個問題,我不需要考慮這一點……

  為什么業務層這么薄

  三層架構流行起來之后,我們很清楚的知道UI層負責頁面交互并調用下一層,也知道DAL層就是和數據庫打交道。但BLL層?什么才算是“業務邏輯”?有各種各樣的解釋,但這些不都是sql做的么?對于絕大多數的應用系統而言,除了對數據庫進行“增刪改查”以外,實在不知道還能做些什么?更何況,不是還有超級強大的存儲過程么!

  所以,很多系統,即使勉強弄出一個業務層,也“薄”得不像話,像一層塑料薄膜一樣,讓人有一種把它立即撕掉的強烈的沖動。

  為什么會是這樣呢?

  這得從.NET陣營從歷史說起。.NET陣營的同學知道三層架構,多半是從PetShop開始,這被奉為三層架構的經典,很多項目甚至是直接復制其架構。在當時,它是一種了不起的進步。那時候,還是從ASP向ASP.NET轉型的過程,很多asp項目,sql代碼都還是寫在html里面的!所以,UI和DAL的分離,無疑具有明細的示范效應。

  但微軟的步子,不大不小,剛好扯著蛋。

  步子小一點,做成兩層架構,估計一點問題都沒有,大家都能接受;步子再大一點,就得上ORM,可惜微軟當時還沒條件支持。所以就搞出了這么個不明不白稀里糊涂的概念出來,折磨了我好久好久……

  長期以來,.NET的陣營,在應用級層面,其實是“面向數據庫”的。從DataSet、DataGrid、DataSourceBinder之類的,都可以看出來。即使是Entity Framework,最開始也是從數據庫的表向.NET的類進行映射。這些,都極大的制約了.NET陣營同學面向對象的思維拓展。

  好在我終于跳出來了。

  面向數據庫

  為了說明,我們舉一個最簡單的例子。

  需求是:記錄文章(Article)的瀏覽數(ViewCount)。每當文章被閱讀(View)一次,瀏覽數加一。

  看到這個需求,你首先想到的是什么?是不是:

SQL代碼
  1. Update Article set ViewCount = ViewCount + 1;  

  如果是這樣的話,恭喜你,你還牢牢的守住了“面向數據庫”的陣地。

C#代碼
  1. /*  
  2.    
  3. 面向數據庫并不是不可接受的,面向對象也并不一定比面向數據庫“高級”。  
  4. 這只是兩條道路的選擇,如果你愿意看一看另外一條路的風景,就請繼續;否則,就此打住吧。  
  5.    
  6. */    

  面向對象

  那么,面向對象或者領域驅動應該是怎么做的呢?

C#代碼
  1. public void View()    
  2. {    
  3.     //從數據庫中取出Article    
  4.     Article article = session.Load<Article>(articleId);    
  5.          
  6.     //改變Article的ViewCount屬性    
  7.     article.ViewCount += 1;    
  8.      
  9.     //將改變后的Article再存入數據庫    
  10.     session.Save(article);    
  11. }    

  有什么感覺?眼前一亮,還是不可思議?想得更深一點的,是不是覺得這是多此一舉,一句sql就能解決的問題,搞得這么復雜?

  我當年,考慮最多的,最不能接受的,是性能問題。

  • 這必須利用ORM,即使不考慮ORM生成的sql高不高效,就這生成sql的開銷,應該就不低吧?

  • 這樣做,取數據,打開一次數據庫連接;存數據,又打開一次數據庫連接。就算有連接池,但能省一點就省一點不是更好?

  所以,如果你也和我一樣,倒回去看我之前的博客吧!

  這樣做,還有其他很多具體的技術問題,我們后續博客會逐一展開說明。

  為什么

  我們還是回到大方向上來,為什么要這么做?換言之,“面向數據庫”有什么問題,或者說“面向對象”有什么好處?

  我覺得,“抽象”、“解耦”、“復用”之類的說法,都還沒有觸及根本。最根本的原因,還在于我們的大腦,我們的大腦不適應于把這個世界抽象成一張一張的表,而更適應于一個一個的對象。隨著系統日趨復雜,這種現象就表現得越明顯。

  我曾經參與過一個項目,它的數據庫結構打印出來,得用地圖那么大一張紙(我不知道算A幾了),密密麻麻的全是表,各種線條交錯其中,我看著就頭皮發麻。部門里面像個寶貝一樣把這張表供著,因為公司沒法打印也沒法復印?。。ㄎ也恢浪麄冏铋_始是怎么得來的,估計肯定麻煩)

  如果你一邊讀一邊在想,就會發現,“不對呀,有多少表就有多少類,類圖不是一樣復雜嗎?”

  是的,而且由于抽象,類很可能比表還要多。但是,有于抽象,在我們進行架構、設計、溝通的時候,可以暫時的拋棄很多細節。比如,我們可以說,“文章被評論之后,文章作者的積分加10分”,這個時候,我們就不考慮文章有很多種:博客、新聞、問答、評論……,也不考慮積分增加是直接改積分總分呢,還是添加一條積分記錄,或者還要同步……。如果只有表,你怎么說?

  當然,表的結構也可以設計成類似于繼承的樣子(類的繼承關系也最終會映射成表結構),但是,在交流溝通中,你如何表明這種抽象關系呢?

  單純從程序的角度上說,使用ORM,面向對象,還增加了系統的復雜性。畢竟多了一道工作,而且把對象映射到數據庫不是一件簡單的工作,尤其是你還要考慮性能問題的時候。

  那為什么我們還要這樣做?委托,換言之,把復雜性往其他地方推。我記得我反復講過這一點,架構的一個重要工作,就是把復雜性進行拆分和推諉。拆分估計大家好理解,但“推諉”是個什么意思,推給誰呢?管它呢,我只做我分類的事,其他的,UI推給BLL,BLL推給DAL,DAL推給DBA,DBA推給采購部……

  寫在這里很搞笑,但事實就是這樣的。在性能篇,我說,你要寫高性能的代碼,你就是搶了人家的飯碗,就這個意思。UI都把DBA的活兒干了,人家吃什么?你代碼都寫成01001010101010二進制了,別說做匯編的,估計做CPU的都活不下去了。

  我們這里,就是把復雜度推給了Map團隊、ORM工具開發商和DBA。

  因為我們要和客戶談需求啊,典型的是領域驅動,要和客戶/領域專家找到“共同的語言”,這共同的語言是什么?是表結構?估計如果開發的是一個財務會計系統,這還是可行的——估計早期的系統大多就是財務報表類系統?說不定還真是這樣。為什么面向對象從Java開始流行,Java是虛擬機,可以用在微波爐報警器之類上面的,底層數據結構可以完全脫離數據庫??!.NET做什么起家的,就報表??!呵呵。

  總之,發展到今天,隨著系統復雜性的增加。在系統的架構設計中,我們不得不將現實世界首先映射成一個一個可以封裝、具有繼承多態特性的對象,并且將重心放在這些對象關系功能的維護上。

  數據庫?就先不管它吧。

  只有脫離了數據庫的束縛,我們才能自由的翱翔在面向對象的世界里!

  忘不掉

  “問題是我忘不掉??!”

  “我只要看到需求,腦子里馬上就是數據庫就是表。”

  “沒有數據庫,我都不知道怎么開始寫代碼了。”

  ……

  是的,忘掉數據庫是很難很難——尤其是對于我們這些老人來說。已經浸淫sql數十年的高手,你讓我忘掉它?你以為寫小說啊,張無忌學太極???

  我只能說說我是怎么做到的,希望能給你一些參考。

  我就假設我的系統不是用“關系數據庫”存儲數據,不是mysql,不是oracle;我用nosql,我用xml文件存儲,行不行?nosql,怎么用?不知道啊,我十竅通了九竅。但我就要在我還不知道nosql怎么用的時候,就開始構建我的BLL/領域層。而且我只設定幾個最簡單的假設:

  所有的對象都可以直接從硬盤Load()出來

  所有的對象都可以直接Save()到硬盤

  對象之間用1:1、1:n、n:n建立關聯即可

  究竟怎么從硬盤里存?。ㄋ^的“持久化”),以后再說。我連用什么進行持久化都不知道,現在怎么考慮?但有一條,反正不會用關系數據庫,估計是用nosql吧……

  最終的期望

  真正的對象數據庫!快出來啊,求你了……

除非特別注明,雞啄米文章均為原創
轉載請標明本文地址:http://www.028keji.com/software/477.html
2015年12月4日
作者:雞啄米 分類:軟件開發 瀏覽: 評論:0