架構,改善程序復用性的設計~第三講(jiang) 實現(xian)一(yi)種功能的代(dai)碼只(zhi)能出(chu)現(xian)在一(yi)處(chu)(續)
在寫完架構,改善程序復用性的設計~第三講 實現一種功能的代碼只能出現在一處 , 這篇(pian)文章(zhang)后,得到了園友的(de)反饋,說這種簡單(dan)的(de)業務(wu)邏輯還(huan)可以,但業務(wu)比(bi)較復(fu)雜時,根據就沒法(fa)用這種方法(fa)。
針(zhen)對(dui)這(zhe)個(ge)問(wen)題,我覺得有必要再寫一個(ge)續集了,呵(he)呵(he)!
上回說的主要核心內容是將公用的部分從一個方法中提取出來,生成一個新的方法,這個重構中叫做“提取到方法”
,另(ling)外(wai)一(yi)(yi)個核心內容就是(shi)方法的”單(dan)一(yi)(yi)職責“,即一(yi)(yi)個方法干(gan)一(yi)(yi)件事,將(jiang)出(chu)現復雜事件時,將(jiang)多(duo)個方法進行組合(he)調用即可
這回主要說一個重構中的提取,其實不僅方法可以被提取,類,及整個項目也可以被提取,只要他們有被提取的必要!
一個例子:對于一個數據實體操作的基類,它包括了其它所有實體類共有的屬性(DB)和方法(SubmitChanges),這(zhe)可以理解(jie)了”提取到類(lei)“,當然這(zhe)也是類(lei)的繼承及面向對(dui)象(xiang)的一(yi)個例子。
1 /// <summary> 2 /// LINQ數(shu)據(ju)庫操(cao)作基類 3 /// </summary> 4 public abstract class RepositoryBase 5 { 6 public RepositoryBase(DataContext db) 7 { 8 DB = db; 9 } 10 protected System.Data.Linq.DataContext DB { get; private set; } 11 12 #region DBContext SubmitChanges 13 /// <summary> 14 /// XXB默認提交【重寫時候(hou)可能需(xu)要寫入自定義的類似約束(shu)的邏輯】 15 /// </summary> 16 protected virtual void SubmitChanges() 17 { 18 ChangeSet cSet = DB.GetChangeSet(); 19 if (cSet.Inserts.Count > 0 20 || cSet.Updates.Count > 0 21 || cSet.Deletes.Count > 0) 22 { 23 try 24 { 25 DB.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict); 26 } 27 catch (System.Data.Linq.ChangeConflictException ex) 28 { 29 foreach (System.Data.Linq.ObjectChangeConflict occ in DB.ChangeConflicts) 30 { 31 // 使用當前數據庫(ku)中的(de)值,覆蓋Linq緩存中實(shi)體對(dui)象的(de)值 32 occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues); 33 // 使用Linq緩存(cun)中實體對象的值(zhi)(zhi),覆蓋(gai)當前數據庫中的值(zhi)(zhi) 34 occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues); 35 // 只(zhi)更(geng)新(xin)實體對象(xiang)中改(gai)變(bian)的字(zi)段的值,其他(ta)的保(bao)留不(bu)變(bian) 36 occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges); 37 } 38 DB.SubmitChanges(); 39 } 40 } 41 } 42 43 #endregion 44 }
還有一種更大(da)程序上的(de)提(ti)取,即”提(ti)取到項(xiang)目(mu)“,就是(shi)說(shuo),它的(de)整個項(xiang)目(mu)都是(shi)其它項(xiang)目(mu)公用的(de)部(bu)分,所有把整個項(xiang)目(mu)抽象出來
Entity.Commons這(zhe)個項目是對所有解決(jue)方(fang)案的(de)所有實(shi)(shi)(shi)體(ti)層進行的(de)抽象,它里面有對實(shi)(shi)(shi)體(ti)的(de)分頁,實(shi)(shi)(shi)體(ti)參數組(zu)織,實(shi)(shi)(shi)體(ti)消息(xi)返回及實(shi)(shi)(shi)體(ti)統一驗證等功能,都在(zai)Entity.Commons里實(shi)(shi)(shi)現
EntityBase.cs代碼如下:
View Code
1 /// <summary> 2 /// 實體基類,與(yu)linq to sql數據映射對應(ying) 3 /// </summary> 4 [Serializable] 5 public abstract class EntityBase /*: INotifyPropertyChanging, INotifyPropertyChanged*/ 6 { 7 8 public EntityBase() 9 { 10 this.IsRealDeleted = true; 11 } 12 #region 實體相關 13 /// <summary> 14 /// 實體(ti)主(zhu)鍵 15 /// 在子類中對它賦(fu)值,在其它類中可以訪(fang)問到這個主鍵屬(shu)性 16 /// </summary> 17 public abstract object[] PrimaryKey { get; } 18 /// <summary> 19 /// 是否(fou)執行真刪(shan)除,默認為(wei)true,如果設為(wei)false,則(ze)更新實體的(de)status字段 20 /// </summary> 21 public virtual bool IsRealDeleted { get; protected set; } 22 /// <summary> 23 /// 記(ji)錄修改(gai)的列(lie)信息 24 /// 子類可以根據需要(yao),去復寫(xie)記錄數據的方(fang)式 25 /// </summary> 26 /// <param name="sender"></param> 27 /// <param name="e"></param> 28 protected virtual void PropertyChangedEvent(object sender, PropertyChangedEventArgs e) 29 { 30 #region 添加修改字段記錄 31 // VLog.IVLog log = new VLog.SqlVLog(); 32 // log.Write(string.Format("被修(xiu)改的(de)字段(duan){0}", e.PropertyName)); 33 #endregion 34 #region 記錄修改的字段和修改成的值 35 Type t = this.GetType(); 36 PropertyInfo pi = t.GetProperty(e.PropertyName); 37 object value = pi.GetValue(this, null); 38 this.OnPropertyChanged(e.PropertyName, value); 39 #endregion 40 41 } 42 #endregion 43 44 #region 實體驗證 45 46 /// <summary> 47 /// 驗證(zheng)的字段名(ming)集合,為NULL表示驗證(zheng)所有字段 48 /// </summary> 49 public string[] ValidFields { get; set; } 50 51 /// <summary> 52 /// 數據驗(yan)證(zheng)(是否成功) 53 /// 虛屬(shu)性,子類可以(yi)根(gen)據自己(ji)的邏輯去復寫 54 /// </summary> 55 public virtual bool IsValid { get { return this.GetRuleViolations().Count() == 0; } } 56 /// <summary> 57 /// 獲(huo)取驗(yan)證(zheng)失敗(bai)的信息枚舉(ju),默認(ren)提供了(le)非空驗(yan)證(zheng) 58 /// 它使(shi)用了簡單的迭代(dai)器,如果GetRuleViolations有錯誤則返(fan)回(hui)迭代(dai)列表 59 /// </summary> 60 /// <returns></returns> 61 public virtual IEnumerable<RuleViolation> GetRuleViolations() 62 { 63 PropertyInfo[] propertyInfo = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); 64 if (ValidFields != null) propertyInfo = propertyInfo.Where(i => ValidFields.Contains(i.Name)).ToArray(); 65 foreach (var i in propertyInfo) 66 { 67 if (i.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false) != null 68 && i.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false).Count() > 0 69 && !((System.Data.Linq.Mapping.ColumnAttribute)i.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false)[0]).CanBeNull 70 && !((System.Data.Linq.Mapping.ColumnAttribute)i.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false)[0]).IsPrimaryKey) 71 if (i.GetValue(this, null) == null || string.IsNullOrEmpty(i.GetValue(this, null).ToString())) 72 yield return new RuleViolation("*", i.Name); 73 } 74 } 75 #endregion 76 77 #region 重寫linq to sql的一些東西 78 79 #region INotifyPropertyChanged and INotifyPropertyChanging Members 80 81 public event PropertyChangedEventHandler BasePropertyChanged; 82 public event PropertyChangingEventHandler BasePropertyChanging; 83 protected virtual void OnPropertyChanging(String propertyName) 84 { 85 if ((this.BasePropertyChanging != null)) 86 { 87 this.BasePropertyChanging(this, new PropertyChangingEventArgs(propertyName)); 88 } 89 } 90 protected virtual void OnPropertyChanged(String propertyName, object newValue) 91 { 92 if ((this.BasePropertyChanged != null)) 93 { 94 this.BasePropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 95 } 96 97 if (_changeList == null) 98 return; 99 100 if (_changeList.ContainsKey(propertyName)) 101 { 102 _changeList.Remove(propertyName); 103 } 104 _changeList.Add(propertyName, newValue); 105 } 106 protected bool IsPropertyChanged(string name) 107 { 108 return _changeList != null && _changeList.ContainsKey(name); 109 } 110 #endregion 111 112 #region Change tracking 113 114 private Dictionary<string, object> _changeList; 115 116 public Dictionary<string, object> GetChanges() 117 { 118 return _changeList; 119 } 120 121 private void StartTrackChanges() 122 { 123 if (_changeList != null) 124 { 125 throw new InvalidOperationException("This object is already tracking changes"); 126 } 127 _changeList = new Dictionary<string, object>(); 128 } 129 130 private bool _IsAlreadySaved = false; 131 132 public bool IsAlreadySaved() 133 { 134 return _IsAlreadySaved; 135 } 136 /// <summary> 137 /// 保存實體 138 /// </summary> 139 public void MarkEntitySaved() 140 { 141 _IsAlreadySaved = true; 142 } 143 /// <summary> 144 /// 實(shi)體初始(shi)化,開(kai)始(shi)跟蹤實(shi)體的變化 145 /// </summary> 146 public virtual void Initialization() 147 { 148 this.StartTrackChanges(); 149 } 150 151 #endregion 152 153 #endregion 154 } 155 #region 子類更新需要實現它的分部方法,內容如下 156 //partial void OnCreated() 157 // { 158 // base.IsRealDeleted = false;//假刪除 159 // base.Initialization();//基(ji)類的某些屬性初(chu)始化 160 // this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(base.PropertyChangedEvent);//初始(shi)實體(ti)時(shi),先訂閱(yue)列修(xiu)改(gai)的事(shi)件 161 // } 162 #endregion
通(tong)過(guo)這篇文章,我們知道了,對于代碼重(zhong)構(gou),不僅僅只對于方法而(er)言,對于重(zhong)構(gou),也(ye)不僅僅只對一個項(xiang)(xiang)目(mu)而(er)言,它可能是項(xiang)(xiang)目(mu)與項(xiang)(xiang)目(mu)之間的重(zhong)構(gou)。
