《Effective C#》读书笔记——条目21:限制类型的可见性<使用C#表达设计>
在保证类型可以完成其工作的前提下,我们应该尽可能的给类型分配最小的访问级别。可见性越低那么以后升级更改时所需的变化也就越少——因为能访问你的功能的代码越少,以后可能出现的修改也就会越少。
使用内部类来限制类型作用域
创建内部类是一种常被忽略的限制类型作用域的方法,在创建一个类时,应该仔细考虑这个新类型的作用范围:是将被所有的客户使用?还是仅仅用在程序集的内部。内部的类可以让你在稍后的任意替换其具体的实现,只要两个类实现同样的接口即可。例如下面验证电话号码的类:
1 public class PhoneValidator 2 { 3 public bool ValidateNumber(phoneNumber ph) 4 { 5 //验证号码的代码...略 6 return true; 7 } 8 }
现在该类是完全可以工作的,但是随着项目的升级,现在出现了一个新的需求,需要同时处理多种格式的电话号码,例如国际电话号码。为了不把所有的功能都混在一个类中,我们应该尽量降低两个不同功能间的耦合。我们通过接口来暴露功能,创建一个验证电话的接口:
1 public interface IPhoneValidator 2 { 3 bool ValidateNumber(phoneNumber ph); 4 }
接着把原来的 PhoneValidator类的访问级别改成internal类型,并实现IPhoneValidator接口:
1 internal class CNPhoneValidator:IPhoneValidator 2 { 3 public bool ValidateNumber(phoneNumber ph) 4 { 5 //验证号码的代码...略 6 return true; 7 } 8 }
随后创建支持验证国际电话格式的类:
1 internal class InternationalPhoneValidator:IPhoneValidator 2 { 3 public bool ValidateNumber(phoneNumber ph) 4 { 5 //验证号码的代码...略 6 return true; 7 } 8 }
上面的例子只是部分实现,通过使用工厂模式可以根据不同的电话号码给出对应的验证器。在程序集外部,只要接口是可见的。而那些针对不同地区的电话号码验证器则只在程序集的内部可见。你可以再任意地为不同的地区添加各自的验证类,而不会担心影响系统内的其他程序集。这样限制了类的作用范围之后,也就减少了日后升级和拓展整个系统时需要更改的代码。这里其实可以为PhoneValidator创建一个公有的抽象基类,其中包含一些公有的实现逻辑,这里使用接口是由于:现在各个实现中的公有逻辑很少。
小节:
更少的公有类型可以让单元测试变得简单,减少了公有类型的数量也就意味着要为公有类型创建的单元测试数量也会变少。同时,更多的使公有API通过接口暴露,在单元测试中也跟容易使用替代类型。以公有类型暴露给外界的类和接口将成为你组件的契约,必须认真对待。接口越复杂,日后修改也就越加受限。暴露的公有类型越少,今后更新扩展时选择的余地就会更大。