在写完这篇文章后,得到了园友的反馈,说这种简单的业务逻辑还可以,但业务比较复杂时,根据就没法用这种方法。
针对这个问题,我觉得有必要再写一个续集了,呵呵!
上回说的主要核心内容是将公用的部分从一个方法中提取出来,生成一个新的方法,这个重构中叫做“提取到方法”
,另外一个核心内容就是方法的”单一职责“,即一个方法干一件事,将出现复杂事件时,将多个方法进行组合调用即可这回主要说一个重构中的提取,其实不仅方法可以被提取,类,及整个项目也可以被提取,只要他们有被提取的必要!
一个例子:对于一个数据实体操作的基类,它包括了其它所有实体类共有的属性(DB)和方法(SubmitChanges),这可以理解了”提取到类“,当然这也是类的继承及面向对象的一个例子。1 ///2 /// LINQ数据库操作基类 3 /// 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 SubmitChanges13 ///14 /// XXB默认提交【重写时候可能需要写入自定义的类似约束的逻辑】15 /// 16 protected virtual void SubmitChanges()17 {18 ChangeSet cSet = DB.GetChangeSet();19 if (cSet.Inserts.Count > 020 || cSet.Updates.Count > 021 || cSet.Deletes.Count > 0)22 {23 try24 {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 // 使用当前数据库中的值,覆盖Linq缓存中实体对象的值 32 occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues);33 // 使用Linq缓存中实体对象的值,覆盖当前数据库中的值 34 occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues);35 // 只更新实体对象中改变的字段的值,其他的保留不变 36 occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges);37 }38 DB.SubmitChanges();39 }40 }41 }42 43 #endregion44 }
还有一种更大程序上的提取,即”提取到项目“,就是说,它的整个项目都是其它项目公用的部分,所有把整个项目抽象出来
Entity.Commons这个项目是对所有解决方案的所有实体层进行的抽象,它里面有对实体的分页,实体参数组织,实体消息返回及实体统一验证等功能,都在Entity.Commons里实现
EntityBase.cs代码如下:
View Code
1 ///2 /// 实体基类,与linq to sql数据映射对应 3 /// 4 [Serializable] 5 public abstract class EntityBase /*: INotifyPropertyChanging, INotifyPropertyChanged*/ 6 { 7 8 public EntityBase() 9 { 10 this.IsRealDeleted = true; 11 } 12 #region 实体相关 13 ///14 /// 实体主键 15 /// 在子类中对它赋值,在其它类中可以访问到这个主键属性 16 /// 17 public abstract object[] PrimaryKey { get; } 18 ///19 /// 是否执行真删除,默认为true,如果设为false,则更新实体的status字段 20 /// 21 public virtual bool IsRealDeleted { get; protected set; } 22 ///23 /// 记录修改的列信息 24 /// 子类可以根据需要,去复写记录数据的方式 25 /// 26 /// 27 /// 28 protected virtual void PropertyChangedEvent(object sender, PropertyChangedEventArgs e) 29 { 30 #region 添加修改字段记录 31 // VLog.IVLog log = new VLog.SqlVLog(); 32 // log.Write(string.Format("被修改的字段{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 ///47 /// 验证的字段名集合,为NULL表示验证所有字段 48 /// 49 public string[] ValidFields { get; set; } 50 51 ///52 /// 数据验证(是否成功) 53 /// 虚属性,子类可以根据自己的逻辑去复写 54 /// 55 public virtual bool IsValid { get { return this.GetRuleViolations().Count() == 0; } } 56 ///57 /// 获取验证失败的信息枚举,默认提供了非空验证 58 /// 它使用了简单的迭代器,如果GetRuleViolations有错误则返回迭代列表 59 /// 60 ///61 public virtual IEnumerable 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 #endregion111 112 #region Change tracking113 114 private Dictionary _changeList;115 116 public Dictionary 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 ();128 }129 130 private bool _IsAlreadySaved = false;131 132 public bool IsAlreadySaved()133 {134 return _IsAlreadySaved;135 }136 /// 137 /// 保存实体138 /// 139 public void MarkEntitySaved()140 {141 _IsAlreadySaved = true;142 }143 ///144 /// 实体初始化,开始跟踪实体的变化 145 /// 146 public virtual void Initialization()147 {148 this.StartTrackChanges();149 }150 151 #endregion152 153 #endregion154 }155 #region 子类更新需要实现它的分部方法,内容如下156 //partial void OnCreated()157 // {158 // base.IsRealDeleted = false;//假删除159 // base.Initialization();//基类的某些属性初始化160 // this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(base.PropertyChangedEvent);//初始实体时,先订阅列修改的事件161 // }162 #endregion
通过这篇文章,我们知道了,对于代码重构,不仅仅只对于方法而言,对于重构,也不仅仅只对一个项目而言,它可能是项目与项目之间的重构。