天天看點

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

關鍵字:提出需求、需求分析、原則、設計模式、索引

     先說一下讨論的範圍:使用資料庫儲存資訊的項目,b/s結構,asp.net編寫。請不要讨論這個範圍之外的事情哦,謝謝!

     這裡想說的并不僅限于一個控件,而是一個關于分頁的解決方案。資訊都是放在資料庫裡的,在b/s結構裡面一次提取所有的資料顯示并不是一個好的方法,是以就需要一個把資料分成多個頁的形式來顯示。關于分頁的解決方案有多種,一種實作方式可以用一個“分頁控件”(我的解決方案),也可以用其他的方式來展現(比如LinQ、ORM等)。這裡想說的是我的這個解決方案,我想從提出需求、需求分析到解決方案的步驟來說明。

一、提出需求

     客戶的資訊(産品資訊、員工資訊、合同資訊、金額相關等)都會放在資料庫裡面,由于是采用b/s結構,資訊多了如果不分頁的話,顯示起來就會比較慢。資料庫有多種類型,asp.net常用的是SQL Server ,小一點的網站會采用Access,資料量多了,或者比較重要的會采用Orcale。避免版權問題的會采用mySQL。還有特殊的會采用其他的資料庫。

     分頁方式也會有多種,網站為了照顧SEO,一般要采用URL的方式來分頁(包括URL重寫)。而OA、CRM這一類的(包括網站的背景管理)就不必考慮SEO了,采用Postback的分頁方式會更友善,可以很容易的儲存狀态,比如查詢條件等。

     總結一下就是:

          1、多種資料庫(SQL Server、Access、Orcale等)。

          2、多種分頁方式(URL、Postback等)。

          3、提高提取資料的速度。

          4、對SEO要友好。

          5、使用要友善。

          6、便于閱讀、便于擴充。

          7、支援多種顯示資料的控件(比如GridView、repeater等)。

二、需求分析

     要求基本就是這麼多了,那麼怎麼來實作呢?我們先開看看分頁的基本步驟:

          1、繪制UI,生成分頁事件或者URL位址。

          2、選擇分頁算法。

          3、送出給資料庫。

          4、得到記錄集,綁定到控件。

     第一步是比較獨立的,每一個方案就差不多會把它獨立出來。而下面的就不太一緻了。基本就是這樣。

     然後再來看看常用的幾種解決方案。

          1、GridView

               一般簡單的可以使用GridView自帶的分頁功能來實作,優點就是使用起來非常的友善,但是他有一個明顯的缺點,就是記錄多了會比較慢,原因是他是把所有的資料都提取出來放在記憶體裡面,然後在計算顯示哪些資料。

          2、LinQ

               利用LinQ來分頁的話,那麼他就會把生成分頁算法(SQL語句)、送出到資料庫、得到記錄集、填充到實體類都包含進去了。ORM好像也是這樣(沒用過ORM,隻好用“好像”這個詞了)。

          3、AspNetPager

               就是吳旗娃的分頁控件,他隻實作了第一部分,其他的都要自己另想辦法了。最近又推出了Socut.Data.dll,可以用它來提取資料,但是這樣又把原來的存儲過程給“扔”掉了。另外配合起來也不是很“默契”,或者說不是“無縫連接配接”吧。

          4、QuickPager

               就是我的分頁控件了,我要把這幾個都包含進去,目的就是要簡化操作,讓使用的時候達到最簡單。

          5、其他的方案

               這個我就不太了解了,應該還有很多的分頁方案的,隻是我還不太了解。

三、如何解決

     分頁控件的基本結構已經完成了,又看了王濤的《你必須知道的.net》和兩本設計模式的書(都還沒有看完),不能白看呀,理論聯系實際,實際配合理論,看看分頁控件的内部代碼的設計方式有哪些優缺點,符合了哪些原則,違反了哪些原則,還有和哪些設計模式有點像。

     多種資料庫,一般是SQL Server2000、SQL Server2005、Orcale、mySQL這幾種資料庫,而這幾種資料庫對于“分頁算法”又各有不同,SQL Server2000隻能用表變量、颠倒Top、Max等,而SQL Server2005可以使用Row_Number,Orcale可以使用number、mySQL可以使用limit。各個資料庫有各自的特點。雖然一個項目一般隻用一種資料庫,隻考慮一種資料庫的情況也是可以的,但是給自己增加一點難度,我的分頁方案可以适合多種資料庫,而且還可以擴充。

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

OO原則:

     1、單一職責。

          從表面上看,QuickPager是嚴重違反了這個原則,不僅負責繪制UI,還負責拼接SQL語句,還要處理回發事件,還要送出給資料庫,還要綁定顯示資料的控件。一個分頁控件要實作這麼多的事情,是不是會很複雜、耦合度也高了,嚴重的違反了單一職責呢?

簡單的看确實是這樣,但是仔細看一下分頁控件内部結構,就會發現不是這樣的。

class QuickPager:有一點“實體類”的感覺,他本身基本什麼功能都不能實作,隻是負責記錄一些分頁需要的資訊。

class PageSQL:負責分頁算法,說白了就是拼接SQL語句的。當然不是随意的拼接,而是按照分頁算法來拼接。分頁算法又有好多種。

class PageUI:繪制UI,包括總記錄數、總頁數、第一頁、上一頁、下一頁、頁号導航、分頁事件等。

class PageGetData:負責把PageSQL生成SQL語句交給“資料通路函數庫”,然後傳回記錄集。

          這麼看的話,每一個類的職責都是比較單一的,一個類負責一件事情,實作一個功能,和在一起配合工作,才實作了最終的分頁效果。

如果有變化的話隻需要修改一個類就可以,不影響其他的類。比如要加一個分頁算法的話,隻需要添加一個子類繼承PageSQL就可以了。對其他的類,和其他的分頁算法都沒有關系。

這樣是不是說可以符合了單一職責呢?

     2、開放封閉原則。

          上面說了,要增加一個分頁算法的話,隻需要加一個子類就可以了,不用修改其他的代碼,這個就是開放封閉原則吧。同樣,URL分頁、Postback分頁也是這樣的思路。

     3、依賴倒置

          就是依賴抽象,分頁控件就是根據分頁的需求進行的一個“抽象”,内部的各個類也是依據抽象才能夠協同工作的。

設計模式

     1、政策模式

     定義:政策模式定義了一系列的算法,并将每一個算法封裝起來,而且使它們還可以互相替換。

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

這個圖和上面的是不是很像?

     Context(應用場景): 是QuickPager

     Strategy(抽象政策類):是PageSQL、PageUI

     ConcreteStrategy(具體政策類):是SQL_Max、SQL_Row_Number等和UI_PostBack、UI_URL。

     一個分頁控件要提供多種分頁算法,一個分頁算法就相當于一個政策。同理,URL分頁、Postback分頁都可以看做是一種政策。看深入淺出設計模式,裡面的例子采用的是接口,而分頁控件采用的是基類。

     在QuickPager裡面定義下面幾個成員,這時并沒有執行個體化。

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

/**//// <summary>

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        /// 通路資料庫用的執行個體

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        /// </summary>

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        private  DataAccessHelp dal = null;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        /**//// <summary>

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        /// 生成SQL語句的部分

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        private PageManage.PageSQL MgrPageSQL = null;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        /// 提取資料的部分

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        private PageManage.PageGetData MgrGetData = null;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        private PageManage.PageUI MgrPageUI = null;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

然後再設計幾個屬性,來處理如何執行個體化這幾個成員。

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

   資料通路執行個體的設定#region 資料通路執行個體的設定

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        /// 設定資料通路層的執行個體

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        public DataAccessHelp DAL

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

{

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

            set 

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

{ dal = value; }

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

            get

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                if (dal == null)

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                    dal = new DataAccessHelp();

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                return dal;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

            }

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        }

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        #endregion

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        分頁算法的執行個體#region 分頁算法的執行個體

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        /// 分頁算法的執行個體

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        public PageManage.PageSQL ManagerPageSQL

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

{ MgrPageSQL = value; }

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                if (this.SetRunKind == myPageRunKind.Customer)

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                    return null;        //自定義方式不提供分頁算法

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                PageManage.PageSQL tmp = MgrPageSQL;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                if (tmp == null)

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                    switch (SetSQLKind)

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                        case myPageSQLKind.Row_Number:

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                            tmp = new JYK.Controls.PageManage.SQL_Row_Number();

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                            break;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                        case myPageSQLKind.Max_TopTop :

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                            if (this.TableOrderColumns.Contains(","))

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                                //多字段排序

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                                //CommandClass.MsgBox("Max_TopTop2", false);

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                                tmp = new JYK.Controls.PageManage.SQL_TopTop();

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                            }

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                            else

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                                //一個排序字段

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                                //CommandClass.MsgBox("Max_TopTop1", false);

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                                tmp = new JYK.Controls.PageManage.SQL_Max();

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

 //其他的算法的判斷就省略了。

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                    }

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                    MgrPageSQL = tmp;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                }

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                if (tmp.myPage == null)

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                    tmp.myPage = this;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                return tmp;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        分頁方式的執行個體#region 分頁方式的執行個體

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        /// 分頁方式的執行個體

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

        public PageManage.PageUI ManagerPageUI

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

{ MgrPageUI = value; }

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                PageManage.PageUI tmp = MgrPageUI;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                    switch (this.SetUIKind)

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                        case myPageUIKind.PostBack:

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                            tmp = new JYK.Controls.PageManage.UI_PostBack();

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

                    MgrPageUI = tmp;

【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式
【開源】QuickPager 分頁控件的内部結構,和OO原則與設計模式

     這樣就非常的靈活了,不僅可以根據不同的屬性設定來執行個體化不同的子類。比如根據不同的分頁算法來執行個體化不同的子類。而且還可以在外部設定執行個體,就是說可以再分頁控件的外部自己定義一個子類,然後執行個體化。

再有一個好處就是,用到的時候才執行個體化,不用就不執行個體化,比如如果采用自定義的運作方式的話,那麼dal 、 MgrPageSQL、 MgrGetData都不會被執行個體化,這樣就不會有浪費的感覺了。

自定義的運作方式,就是像吳旗娃的分頁控件那樣的使用方式。是需要自己處理資料的,是以dal 、 MgrPageSQL、 MgrGetData這三個類就用不到了,用不到也就不需要執行個體化了。

     2、模闆模式

          政策模式隻是規定了這幾個類的關系,至于類的内部的實作方式,可以考慮使用模闆模式。MgrPageSQL和子類的實作方式就是模闆模式。

          模闆模式:定義一個操作中的算法的骨架,而将一些步驟延遲到子類中。Template Method使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。

          在MgrPageSQL裡面定義了分頁算法必須做的幾件事情,和幾個步驟的實作代碼,然後在子類裡面完善。

總結:

     下一篇會說一下QuickPager裡面已經實作的幾種分頁算法的SQL語句、适用範圍、壓力測試、幾種算法之間的對比和與存儲過程的對比。