2012年10月31日 星期三

[C#] Template 樣板模式


Design Pattern : Template

1.      What is Template
記得小時候,寒假開始前,老師一定會叫我們過完寒假要寫一篇出遊的作文。
然而過完寒假後,一定是沒有寫 XD
這時候我們幾個死黨就會去找班上功課最好的同學A,準備把他的作文拿來抄一抄。
A
「你們大家全部抄我的,一模一樣一定會被老師發現。」
於是A拿起他的作文,在以下的地方改成空格,要我們自行填入:

作文題目:寒假出遊
我今天去___,看到很多___,中午和家人一起吃___

沒錯! 這個就是我們最早使用的Template!
也就是只要先寫好父類別的方法,(寒假出遊
這個方法裡面呼叫了自己的一些abstract方法以及決定執行順序。(我今天去看到很多
接著只要定義一些子類別繼承父類別,再來override這些abstract方法即可。

例如 我就可以把這篇作文寫成:
我今天去動物園,看到很多動物,中午和家人一起吃肯德基

2.      Definition

以下是參考前輩此篇文章的描述:
u  定義好method的內容,當作範本,讓其他程式使用。
u  透過繼承的方式,讓子類別能夠實作不同的邏輯區塊。
u  在父類別的method中,依相同順序執行不同區塊的邏輯。
u  所以不同的子類別,能夠實作各自的方法細節,然後統一利用父類別的final method,來執行任務



3.      An Example
實務上,常常對後端資料庫做查詢,如果有多種資料庫(如MS sql Server, Oracle…),查詢的流程其實一樣,只是細節可能不同(如資料庫連線設定,開啟關閉連線…etc
所以我們利用Template來實作資料庫查詢的類別。




u  定義父類別 ConnModel
備註1. DoQuery 就是決定查詢的步驟的方法。
備註2.可以使用mark掉的那些程式碼,由宣告的子類別來進一步控制父類別的方法。  例如:子類別不須要關閉連線這個步驟,則將isCloseConn這個標記設定為false即可。

   public abstract class ConnModel
   {
     private SqlConnection sqlConn;  //資料庫物件

        protected abstract void Setup(); //做資料庫連線設定
        protected abstract void StartConn(); //開始連線
        protected abstract DataTable Query(String sSql); //查詢
        protected abstract void EndConn(); //關閉連線

        //public bool isCloseConn = true; //是否關閉連線 (預設:是)

        /// <summary>
        /// 查詢
        /// </summary>
        ///<param name="sSql">SQL指令</param>
        public DataTable DoQuery(String sSql)
        {
            try
            {
                Setup();
                StartConn();
                return Query(sSql);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                //if (isCloseConn == true)   //檢查是否自動關閉連線
                //{
                    EndConn();
                //}

            }
        }
    }

u  定義第一個MS Sql Server子類別 MSSql
這邊可以很清楚看到,這個子類別只是將繼承的ConnModel裡面的abstract方法override成自己的內容。

  public class MSSql : ConnModel
   {
     /// <summary>
     /// 開始連線
       /// </summary>
        protected override void StartConn()
        {
            Console.WriteLine("建立MS Sql Server連線!");
        }
        /// <summary>
        /// 做資料庫連線設定
        /// </summary>
        protected override void Setup()
        {
            Console.WriteLine("資料庫連線設定!");
        }
        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="sSql"></param>
        /// <returns></returns>
        protected override DataTable Query(String sSql)
        {
            Console.WriteLine("開始查詢MS Sql Server後端資料庫!");
            return null;
        }
        /// <summary>
        /// 關閉連線
        /// </summary>
        protected override void EndConn()
        {
            Console.WriteLine("關閉MS Sql Server資料庫連線!");
        }
       }

u  定義第二個Oracle子類別 Oracle
就不列出程式碼了,只是把上面輸出的部分稍微修改。

u  主程式(mark掉的部分,就是備註2.提到的東西)
Oracle _oracle = new Oracle();
String sSql_oracle = "SELECT 1 FROM DUAL";
//_oracle.isCloseConn = true;
_oracle.DoQuery(sSql_oracle);
_oracle = null;

MSSql _mssql = new MSSql();
String sSql_ms = "SELECT 1 ";
//_mssql.isCloseConn = false;
_mssql.DoQuery(sSql_ms);
_mssql = null;

u  執行結果
資料庫連線設定!
建立Oracle連線!
開始查詢Oracle後端資料庫!
關閉Oracle資料庫連線!

資料庫連線設定!
建立MS Sql Server連線!
開始查詢MS Sql Server後端資料庫!
關閉MS Sql Server資料庫連線!


4.      至於優缺點,我參考書上的內容~
優點:符合OCP,易於維護。
缺點:步驟寫在父類別,但是步驟的邏輯寫在子類別,造成程式碼不易閱讀。






沒有留言:

張貼留言