.NET 業務架構開發實戰之九 Mapping屬性原理和驗證規則的實現策略
前言:之前的討論一直關注在怎麼從DAL中擷取資料,以及資料的Mapping問題。實際上,一個業務架構最主要的作用就是簡化商務邏輯的編寫和開發。
本篇的議題如下:
- 架構的借鑒
- 綜合考慮
系列文章連結:
[原創].NET 分布式架構開發實戰之一 故事起源
[原創].NET 分布式架構開發實戰之二 草稿設計
[原創].NET 分布式架構開發實戰之三 資料訪問深入一點的思考
[原創].NET 分布式架構開發實戰之四 構建從理想和實現之間的橋樑(前篇)
[原創].NET 分布式架構開發實戰五 Framework改進篇
[原創].NET 業務架構開發實戰之六 DAL的重構
[原創].NET 業務架構開發實戰之七 業務層初步構想
[原創].NET 業務架構開發實戰之八 業務層Mapping的選擇策略
[原創].NET 業務架構開發實戰之九 Mapping屬性原理和驗證規則的實現策略
[原創].NET 業務架構開發實戰之十 第一階段總結,深入淺出,水到渠成(前篇)
[原創].NET 業務架構開發實戰之十 第一階段總結,深入淺出,水到渠成(後篇)
1. 架構的借鑒
一個架構的產生不是那麼簡單的,有很多的問題需要Richard去考慮:
- 避免重新造輪子
- 借鑒現有的成熟的架構的思想
在開發的過程中,Richard一直使用Visual Studio IDE開發。而且每次隨著VS新版本的發布,總是伴隨著新技術的產生。很多的時候,開發人員只是關注在新技術的使用和學習上。但是對於新技術,還有另外一方面是很值得關注的:實現的原理,和為什麼這樣實現,即,思想。新技術,毫無疑問是一些大師們思考的結果,從他們的思想中借鑒,益處是很大的。
在Richard學習的過程中,有一個地方特別引起來他的關註:那就是相依性屬性概念的提出,先是WPF,然後在他學習WF的時候,也看到了相依性屬性的再次使用。他考慮,把相依性屬性的思想使用到自己正在開發的業務架構中來。
首先,他分析了現在的相依性屬性的實現方式(以WPF為例),
代碼
public class FrameworkElement: UIElement, ...
{
public static readonly DependencyProperty MarginProperty;
...
}
public Thickness Margin
{
set { SetValue(MarginProperty, value); }
get { return (Thickness)GetValue(MarginProperty); }
}
static FrameworkElement()
{
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(
new Thickness(), FrameworkPropertyMetadataOptions.AffectsMeasure);
MarginProperty = DependencyProperty.Register("Margin",
typeof(Thickness), typeof(FrameworkElement), metadata,
new ValidateValueCallback(FrameworkElement.IsMarginValid)); ...
}
在Richard一直認為,一個屬性的聲明是很簡單的,而且長期以來Richard都一直使用下面的方式:
public Thickness Margin
{
get;set;
}
比較而言,相依性屬性最大的好處就於:給普通的屬性提供更加多的資訊,而且提供了更多的功能:驗證,觸發回調事件。當然,使用普通的屬性也能達到:
public Thickness Margin
{
get{return margin;}
set
{
if(margin<0)
...
...
}
}
相比而言,依賴的屬性的方式更加優雅,而且擴充性也好。
還有一點比較重要的就是,一旦把一個屬性變為相依性屬性,那麼.NET Framework就開始管理這個屬性,如自動的驗證,值的改變和跟蹤。這樣就把任務交給了Framework,開發人員做事情就比較方便了。
Richard想起了之前在開發業務類中遇到的問題:例如下面的代碼:
public class Product
{
public string ProductName{get;set;}
public double Price{get;set;}
}
很多的時候,在增加或者更新一個Product的時候,由於邏輯的需要,往往要判斷ProductName不為空白,而且Price要大於零等。所以每次都需要寫代碼判斷:
public void Add()
{
if(string.IsNullOrEmpty(this.ProductName){...}
if(this.Price<0){...}
}
問題還不止這些,如果在其他的業務類中也需要同樣,而且類似的驗證,那隻有一行行的寫類似的代碼,最好的情況就是copy一些代碼。
這樣寫代碼確實很累,後面Richard也想用一些方式來改進,用到了Enterprise Library中的Validation驗證模組,於是代碼就變成了下面的樣子:
public class Product
{
[NotNullValidator]
public string ProductName{get;set;}
public double Price{get;set;}
}
使用聲明的開發,AOP的思想,其實這樣的方式相比之前而言,確實已經很不錯了。在把業務類的資料儲存的時候只要調用Validation驗證模組的Validate()方法就行了。確實很方便,但是存在的問題就是:每次調用Validate()方法時候,就會把這個業務類的所有屬性都會檢查一遍(那些加了驗證標籤的屬性),這樣,效能方面不好,而且還不能針對某一個屬性單獨的驗證。
2. 綜合考慮
Richard還考慮到了另外的一點:之前一直在解決mapping的問題,說到底就是把從DAL中拿到的資料賦值給業務類的屬性。而且還要基於業務類建立查詢對象,最後把查詢對象解析為SQL語句,所以還要儲存業務屬性和DAL中資料實體屬性的對應關係,即哪個業務屬性對應哪個資料實體屬性(也是表欄位)。
綜合上面的考慮,Richard決定把相依性屬性的優勢利用起來(自動的驗證,資料改變跟蹤,另外加上許可權的驗證),而且給相依性屬性更多的中繼資料資訊:把mapping的欄位資訊儲存在相依性屬性中。所以,現在屬性的聲明如下:
代碼
public static readonly PropertyInfo<int> ProductIdProperty = RegisterProperty<Product>(
new PropertyInfo<int>("ProductId",typeof(M_Product)","Id"));
public string ProductId
{
get { return ReadProperty(ProductIdProperty); }
set { LoadProperty(ProductIdProperty, value); }
}
在上面的屬性聲明中,就指定從業務類(如,Product)的屬性從哪個資料實體(typeof(m_Product))的哪個屬性(如,Id)取值。
RegisterProperty就是把屬性的資訊儲存在一個字典中:
Dictionary<Type,List< IPropertyInfo>>
其中PropertyInfo繼承了IPropertyInfo介面。
最後的結果就是:所有業務類的mapping屬性都被儲存在了一個全域的靜態字典中。
另外還有一個全域的靜態字典用來儲存每個屬性所對應的驗證規則:
Dictionary< IPropertyInfo,List<ICheckRule>>
所有的驗證規則都是從ICheckRule介面繼承。
一個比較強大的屬性就產生了。當然,在mapping屬性中的驗證只是基本的驗證,還有更加複雜的業務驗證將會放在其他的地方,實現方式或者類似WPF那麼:採用回調,如new ValidateValueCallback(FrameworkElement.IsMarginValid)。
所以,借鑒於mapping屬性就解決了三個問題:
- mapping和查詢對象的實現
- 部分驗證規則的聲明
- 業務屬性的管理
著作權為小洋和部落格園所有,歡迎轉載,轉載請標明出處給作者。
http://www.cnblogs.com/yanyangtian
下篇講述:.NET 業務架構開發實戰之十 水到渠成,發布架構實現的第一個版本