1.对于属性的封装,如果返回集合,使用IEnumerable<T>,如果延迟加载,使用IQueryable<T>,原因是这个接口只能遍历取出它的值,而不能对这个集合做出改变,比如
public class Order { private List<string> names; public IList<string> Names { get { return names; } } }
在程序中调用
Order order = new Order();
order.Names.Add("aa");
就对names做出了改变
所以将代码重构,IList<string>换成IEnumerable<string>
public class Order { private List<string> names; public IEnumerable<string> Names { get { return names; } } }
因为IEnumberable只包括一个一个返回值为IEnumerator的GetEnumerator()方法
2.使用委派代替继承,是指在根本没有父子关系的类中使用继承是不合理的,可以用委派的方式来代替。
如下代码所示,Child和Sanitation(公共设施)是没有逻辑上的父子关系,因为小孩不可能是一个公共设施,所以我们为了完成这个功能让Child类中可以使用WashHands()方法,可以考虑使用委派的方式
重构之前:
public class Sanitation { public string WashHands() { return "Cleaned"; } } public class Child : Sanitation { }
重构之后:这种方式我们经常会用到,其实IOC也使用到了这个原理,可以通过构造函数注入和方法注入等
public class Sanitation { public string WashHands() { return "Cleaned"; } } public class Child { private Sanitation Sanitation { get; set; } public Child() { Sanitation = new Sanitation(); } public string WashHands() { return Sanitation.WashHands(); } }
这个重构是一个很好的重构,在很大程度上解决了滥用继承的情况,很多设计模式也用到了这种思想(比如桥接模式、适配器模式、策略模式等)。
3.封装条件,是指条件关系比较复杂时,代码的可读性会比较差,所以这是我们应该根据条件表达式是否需要参数将条件表达式提取成可读性更好的属性或者方法,如果条件表达式不需要参数则可以提取成属性,如果条件表达式需要参数则可以提取成方法。
4.分解复杂判断,是指把原来复杂的条件判断等语句用尽快返回等方式简化代码。
比如:
public class Security { public bool HasAccess(User user, Permission permission, IEnumerable<Permission> exemptions) { bool hasPermission = false; if (user != null) { if (permission != null) { if (exemptions.Count() == 0) { if (SecurityChecker.CheckPermission(user, permission) || exemptions.Contains(permission)) { hasPermission = true; } } } } return hasPermission; } }
重构后:
public class Security { public bool HasAccess(User user, Permission permission, IEnumerable<Permission> exemptions) { if (user == null || permission == null) { return false; } if(exemptions.Contains(permission)) { return true; } return SecurityChecker.CheckPermission(user, permission); } }
让代码在做处理任务之前先检查条件,如果条件不满足就尽快返回,不继续执行。