見到了“公司”定義一個Company類,那麼見到了“欄位”是不是也可定義一個Column類?
既然見到了公司,我們可以定義一個Class Company ,那麼我們見到了欄位,是不是也可以定義一個Class ColumnInfo呢?
公司的描述資訊類:
程式碼 public class Company { public int CompanyId { get; set; } public string CompanyName { get; set; } public string Province { get; set; } public string City { get; set; } public string Address { get; set; } public string HomePage { get; set; } public string Phone { get; set; } }
欄位的描述資訊類
程式碼 public class ColumnsInfo { #region 屬性——欄位的基本資訊的描述 #region 欄位編號 _ColumnID private int _ColumnID = 0; /// <summary> /// 配置資訊裡面的欄位的標識 /// 表ID + 四位序號 組成。一旦生成不建議修改。 /// </summary> public int ColumnID { get { return _ColumnID; } } #endregion #region 欄位所在的表的編號 _TableID private int _TableID = 0; /// <summary> /// 欄位所在的表的編號 /// </summary> public int TableID { get { return _TableID; } } #endregion #region 欄位型別 _ColumnKind private int _ColumnKind = 1; /// <summary> /// 欄位型別 /// 1:正常;2:主鍵;3:外來鍵 /// </summary> public int ColumnKind { get { return _ColumnKind; } } #endregion #region 欄位名 _ColSysName private string _ColSysName = ""; /// <summary> /// 資料庫裡的欄位名稱 /// </summary> public string ColSysName { get { return _ColSysName; } } #endregion #region 顯示給客戶看的欄位名 _ColName private string _ColName = ""; /// <summary> /// 顯示給客戶看的名稱 /// </summary> public string ColName { get { return _ColName; } } #endregion #region 欄位型別 _ColType private string _ColType = ""; /// <summary> /// 欄位型別,int、nvarchar、datetime 等 /// </summary> public string ColType { get { return _ColType; } } #endregion #region 欄位大小 _ColSize private Int32 _ColSize = 0; /// <summary> /// 欄位大小 /// </summary> public Int32 ColSize { get { return _ColSize; } } #endregion //表單控制元件專用 #region 是否儲存,表單控制元件用 _IsSave private bool _IsSave = true; /// <summary> /// 是否要把控制元件的值儲存到資料庫裡面。True:儲存,False:不儲存 /// </summary> public bool IsSave { get { return _IsSave; } } #endregion #endregion }
定義Company是為了儲存公司相關的一些資訊,那麼定義ColumnInfo是為了什麼呢?自然是要記錄欄位的相關資訊了,比如欄位名、欄位大小、欄位型別等,然後等到用的時候就可以直接獲取了。
我知道有的方法是採用XML來記錄這些資訊,然後和Company這樣的類作對應,還有個方法是採用“特性”,把這些資訊記錄到特性裡面。那麼我為什麼要定義一個ColumnInfo來記錄這些資訊呢?
前兩種方法有兩個特點:編譯前確定、類爆炸。
前兩種方法都是以面向物件為主,先根據現實裡的情況來定義實體類,然後在想辦法把實體類和資料庫對應上。在.net裡面是在執行時類的結構就不能在變化了。如果要改變類的結構或者改個類名,都需要修改程式碼然後重新編譯才行。
這樣的話對於資訊管理的專案就很麻煩了。比如公司資訊,今天調研的時候客戶說只需要六個屬性就可以了,但是第二天可能就要提出來在加上一個公司地址。等到了上線執行的時候又提出來需要加上電子信箱。當然了這些都是小修小改,比這麻煩的改動大家也都見得多了吧。
應對這樣的需求變化,就需要修改實體類。雖然有程式碼生成器,雖然有各種ORM,但是類的定義還是要改的吧。而且修改之後必須重新編譯,更新檔案才行。 我是比較煩修改程式碼的,改來改去就改亂了。
類爆炸,見到了員工定義一個Personal,見到了公司定義一個Company……這就是類爆炸。一個專案下來,幾十個、上百個實體類,這些實體類都負責什麼功能呢?有一大半都是隻實現了增刪改查,就完成任務了,說白了就是傳遞一下資料。如果只是為了傳遞資料而定義這麼多的實體類,在我看來真的是很浪費的。很多不必要的修改量也是由此而產生的。
當然瞭如果您定義實體類是為了實現很複雜的業務邏輯的話,那就另當別論了。
如何解決呢?我們先看看我們想要達到什麼目的?資訊的增刪改查。那麼資訊要放在哪裡呢?關係型資料庫(如果您的資料不是放在關係型資料庫的話,那麼不在本次討論的範圍內)。不管是員工資訊、公司資訊還是產品資訊,都是資料庫裡的一條條資料。既然都是資料,那麼就都要和欄位打交道。那麼我們是不是可以從這個角度來抽象一下呢?
ColumnInfo就是我的抽象的結果。每一個欄位都是一個例項,比如Company的CompanyName是一個例項,City又是一個例項,這些例項放在一個集合(我採用了字典Dictionary)裡面,就可以表達一個完整的含義。
這樣不管資訊如何變化,如何增加都不需要修改ColumnInfo的結構,這樣就避免的類爆炸,當然換成了“例項爆炸”,不過例項可是要比類好管理多了。 ColumnInfo是通過屬性值來區分的,那麼就意味著我可以在執行時決定屬性值。像欄位名有變化這樣的修改,就完全不用修改程式碼。
這還帶來了另外一個優點。由於是以欄位為最小單位,欄位可以靈活的組合,同一個欄位既可以放在集合A裡面,又可以放在集合B裡面。這樣就解決了欄位複用的問題。
延伸: 欄位在新增、修改的時候需要對應一個控制元件,比如CompanyName要對應一個文字框,City要對應一個下拉列表框。那麼我們是不是可以把控制元件也描述一下,並且把欄位和控制元件對應起來。這樣我們就可以在表單頁面里根據這些資訊來動態生成各種控制元件了。 【類圖】
以欄位資訊為父類,生成(派生)了兩個子類:列表,表單。表單又生成了兩個子類:新增/修改,查詢。為了準確描述各種控制元件各自特點的資訊,又定義了一個ControlInfo,在這裡定義控制元件的特殊屬性。
根據“表單類”可以繪製表單,實現新增、修改資料的功能,或者是查詢資料時候的查詢條件的錄入。 列表類可以繪製表格(<table>),還可以匯出Excel。
FunctionInfo是功能節點的描述資訊,裡面包含三個類:分頁資訊(相當於顯示資料和查詢資料);新增、修改、刪除用資訊;頁面資訊。
這就是自然框架的元資料,也就是描述資訊,是自然框架的“靈魂”。
自然框架的元資料就相當於蓋大樓用的圖紙,樂隊演奏音樂用的樂譜。
GridInfo類的程式碼:
程式碼
/// <summary>
/// 列表裡的描述資訊
/// </summary>
public class GridInfo : ColumnsInfo
{
#region 屬性
#region TD的寬度 _ColWidth
private int _ColWidth = 0;
/// <summary>
/// td的寬度。0:不限制寬度
/// </summary>
public int ColWidth
{
get { return _ColWidth; }
}
#endregion
#region TD的對齊方式 _ColAlign
private string _ColAlign = "";
/// <summary>
/// 橫向的對齊方式 left center right
/// </summary>
public string ColAlign
{
get { return _ColAlign; }
}
#endregion
#region 格式化 _Format
private string _Format = "";
/// <summary>
/// 格式化的方式。空字串表示不格式化
/// </summary>
public string Format
{
get { return _Format; }
}
#endregion
#region 最多顯示的字元數
private int _MaxLength = 0;
/// <summary>
/// 最多顯示多少個字元。0:不限制。注:一個漢字佔兩個字元
/// </summary>
public int MaxLength
{
get { return _MaxLength; }
}
#endregion
#endregion
}
FormInfo類的程式碼
/// <summary>
/// 表單的描述資訊
/// </summary>
public class FormInfo : ColumnsInfo
{
#region 屬性
//新增修改、查詢共用的屬性
#region 控制元件型別 _ControlKind
private int _ControlKind = 201;
/// <summary>
/// 欄位對應的控制元件型別(編號),比如 201(表示單行文字)
/// </summary>
public int ControlKind
{
get { return _ControlKind; }
}
#endregion
#region 控制元件的描述資訊 _ControlInfo
private ControlInfo _ControlInfo ;
/// <summary>
/// 控制元件的描述資訊,寬、高、最大字元數等。
/// </summary>
public ControlInfo ControlInfo
{
get { return _ControlInfo; }
}
#endregion
#region 預設值 _DefaultValue
private string _DefaultValue = "";
/// <summary>
/// 預設值
/// </summary>
public string DefaultValue
{
get { return _DefaultValue; }
}
#endregion
#region 控制元件狀態 _ControlState
private string _ControlState = "";
/// <summary>
/// 控制元件的狀態。1:正常;2:只讀;3:不可用;4:隱藏
/// </summary>
public string ControlState
{
get { return _ControlState; }
}
#endregion
//佈局,也是共用的
#region 是否合併到上一個TD _TDStart
private Int32 _TDStart = 0;
/// <summary>
/// 是否合併到上一個TD。0:不合並;其他:合併後新增幾個空格(用於佔位);
/// </summary>
public Int32 TDStart
{
get { return _TDStart; }
}
#endregion
#region 是否把下一個欄位合併上來 _TDEnd
private bool _TDEnd = false;
/// <summary>
/// 是否把下一個欄位合併上來。false:不合並;true:合併
/// </summary>
public bool TDEnd
{
get { return _TDEnd; }
}
#endregion
#region 一個控制元件佔用幾個TD _TDColspan
private Int32 _TDColspan = 1;
/// <summary>
/// 記錄一個控制元件佔用幾個TD
/// </summary>
public Int32 TDColspan
{
get { return _TDColspan; }
}
#endregion
#endregion
}
ModInfo類的程式碼:
程式碼
/// <summary>
/// 新增、修改的描述資訊
/// </summary>
public class ModInfo : FormInfo
{
#region 屬性
#region 幫助資訊 ControlColHelp
private string _ControlColHelp = "";
/// <summary>
/// 幫助資訊
/// </summary>
public string ControlColHelp
{
get { return _ControlColHelp; }
}
#endregion
#region 幫助資訊的位置 _ControlHelpStation
private int _ControlHelpStation = 1;
/// <summary>
/// 幫助資訊的位置。1:不顯示;2:最面;3:右面
/// </summary>
public int ControlHelpStation
{
get { return _ControlHelpStation; }
}
#endregion
#region 控制元件在aspx檔案裡的ID名稱 _ControlID
private string _ControlID = "";
/// <summary>
/// 控制元件在aspx檔案裡的ID名稱,手動繪製頁面的時候使用。
/// </summary>
public string ControlID
{
get { return _ControlID; }
}
#endregion
#region 驗證方式,_ControlCheckKind
private int _ControlCheckKind = 101;
/// <summary>
/// 驗證方式
/// </summary>
public int ControlCheckKind
{
get { return _ControlCheckKind; }
}
#endregion
#region 自定義驗證方式,表單控制元件用 _CustomerCheckKind
private string _CustomerCheckKind = "";
/// <summary>
/// 自定義驗證方式,即正則表示式
/// </summary>
public string CustomerCheckKind
{
get { return _CustomerCheckKind; }
}
#endregion
#region 驗證資訊,表單控制元件用 _CheckTip
private string _CheckTip = "";
/// <summary>
/// 未通過驗證的提示資訊
/// </summary>
public string CheckTip
{
get { return _CheckTip; }
}
#endregion
#endregion
}