[Architecture] 資料存取層 (二)

[Architecture] : 資料存取層 (二)

前言 :

上篇發表之後
朋友們的反應,大多是說太抽象了,好像啥都沒講。
其實觀念的東西真的就是抽象,本質真的就是簡單兩字而已。

 

呵呵~說的有點多了,
這第二篇主要是補充一個實作的例子,
看會不會比較那麼虛無飄渺嚕。

 

 

架構 :

 

藍色框框代表一個獨立的DLL
特別標明出來是要傳達,
資料存取層的介面定義是跟邏輯層綁在一起的
資料存取層的實作成是是相依於邏輯層內的資料存取層介面

 

常常工程師在設計軟體的時候
會寫成 : 邏輯層==>資料存取層
建議的作法是 : 邏輯層(資料存取介面<=)=資料存取層
把相依的方向改變,這是物件導向設計中一個很重要的觀念。

 

 

範例 :

 


namespace Clark.Example
{
    public class Product
    {
        public string ProductID = string.Empty;
        public string Caption = string.Empty;
        public string Description = string.Empty;
    }

    public interface IProductStore
    {
        void Add(Product product);

        void Update(Product product);

        void Delete(Product product);        

        Product[] GetAll();
    }

    public class Business
    {
        private IProductStore _store;

        public Business(IProductStore store)
        {
            _store = store;
        }

        public int GetProductCount()
        {
            Product[] products = _store.GetAll();

            return products.Length;
        }
    }
}

namespace Clark.Example.SqlStorage
{
    public class SqlProductStore : IProductStore
    {
        private string _connectionString;

        public SqlProductStore(string connectionString)
        {
            _connectionString = connectionString;
        }

        public Product[] GetAll()
        {
            Product product;
            List<Product> productList;
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("SELECT * FROM Products WHERE", conn);
            SqlDataReader reader = null;

            conn.Open();
            reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);

            productList = new List<Product>();
            while (reader.Read())
            {
                product = new Product();
                product.ProductID = reader.GetValue(1).ToString();
                product.Caption = reader.GetValue(2).ToString();
                product.Description = reader.GetValue(3).ToString();
                productList.Add(product);
            }

            reader.Close();
            conn.Dispose();
            cmd.Dispose();

            return productList.ToArray();
        }        

        public void Add(Product product)
        {
            // 
        }

        public void Update(Product product)
        {
            // 
        }

        public void Delete(Product product)
        {
            // 
        }
    }
}

namespace Clark.ExampleConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            IProductStore store = CreateStore();

            Business business = new Business(store);

            Console.WriteLine(business.GetProductCount());
            Console.ReadLine();
        }
                
        private static IProductStore CreateStore()
        {            
            return new Clark.Example.SqlStorage.SqlProductStore("xxxxx");
        }
    }
}

 

說明 :

 

這支應用程式很簡單,主要就是
在螢幕上顯示資料存放區內存放的Product的數量
比較需要說明的是一些設計的思路

 

Clark.Example

 

Product : 這是需要永續存放的物件。
永續存放這是一個很關鍵的詞,
在觀念上我們可以把系統看成下面的圖

執行區內是應用程式執行時使用的物件
有時我們會將物件存到可以長久存放的地方(資料庫或是其他)
在下次啟動時可以取得之前存的物件。
這邊要特別注意 : 【存放的是「物件」而不是「資料」】
單純存放資料的話,很容易陷入資料導向程式設計的思考方向。

 

IProductStore : 資料存取層定義介面
定義資料存取層,應該實作的介面功能。
定義這個介面要注意的依然是 : 【存放的是「物件」而不是「資料」】
介面功能要定義應該是 : 永續存放的物件,有哪些方法可以通過資料存取層。

 

 

Business : 邏輯層物件
系統運作的邏輯物件。

 

 

Clark.Example.SqlStorage

 

SqlProductStore : 實作資料存取層定義介面的物件
這個物件就是實作資料存取層定義介面,存放物件的目的地是SQL資料庫。
透過各種實作資料存取層定義介面的物件,
我們可以抽換存放物件目的地,而不用去改到企業邏輯。

 

Clark.ExampleConsole

 

Program : 程式碼進入點
這個簡單的範例 Program除了是程式碼進入點,
另外他也負責了IProductStore、Business的生成。

 

範例中的生成模式,並沒有將Clark.Example.SqlStorage從系統中鬆綁。
實際在撰寫相關程式的時候
是會透過各種的生成模式,將延伸的Dll鬆綁的。
物件的生成模式,大家有空可以參考之前文章提到的資料嚕。

 

 

結語 :

 

看這篇的朋友
可能還不是很懂我想表達的東西
找時間再多發幾篇文章。
透過不同的角度去詮釋觀念,慢慢的輪廓應該就會浮現了吧 ^^

 

PS : 呼~用文字表達心中的想法真不是一件簡單的事。

 

期許自己
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。