代码改变世界

Effective C# 学习笔记(二十一)为类型定义有限的职责

2011-07-13 16:04  小郝(Kaibo Hao)  阅读(256)  评论(0编辑  收藏  举报

将类型或类型的方法对外暴露得越少,你将会获得更多的可扩展性,更容易修改其实现,将会减少更多的单元测试。如.net framework 中的对于枚举集合类型的实现方式,就是用嵌套类的形式来实现的,如下代码所示:List<T>类型封装了Enumerator<T>类型的行为,对外只保留了应暴露的方法。

// For illustration, not complete source

public class List<T> : IEnumerable<T>

{

private class Enumerator<T> : IEnumerator<T>

{

// Contains specific implementation of

// MoveNext(), Reset(), and Current.

public Enumerator(List<T> storage)

{

// elided

}

}

public IEnumerator<T> GetEnumerator()

{

return new Enumerator<T>(this);

}

// other List members.

}

 

其次,可以使用接口来定义类型行为,对外暴露接口,少暴露类型。

例如电话号码验证的类型,其代码如下:

public class PhoneValidator

{

public bool ValidateNumber(PhoneNumber ph)

{

// perform validation.

// Check for valid area code, exchange.

return true;

}

}

 

这里定义了一个电话验证类,其有一个方法ValidateNumber来验证电话号码的合法性。但随着需求的变化,该方法的验证规则就会产生不同,如美国的电话号码验证规则和中国的就不一样,这是你可能需要在 ValidatorNumber方法中添加参数,在方法体中添加逻辑判断,以进行应对。但是这样的修改对方法是破坏性的,每添加一种验证方式就要修改一次该方法,增加了维护的难度,这时若能保持原有验证逻辑,又不破坏原有代码,只做新算法的添加才是合理的思路,所以我们会把PhoneValidator抽象为一个接口,其行为定义为接口的方法,这样就可以保证基本的逻辑封装,有可以保证新增的实现不影响过去实现的代码。

代码如下:

public interface IPhoneValidator

{

bool ValidateNumber(PhoneNumber ph);

}

//美国电话号码验证器

internal class USPhoneValidator : IPhoneValidator

{

public bool ValidateNumber(PhoneNumber ph)

{

// perform validation.

// Check for valid area code, exchange.

return true;

}

}

//国际电话号码验证器

internal class InternationalPhoneValidator : IPhoneValidator

{

public bool ValidateNumber(PhoneNumber ph)

{

// perform validation.

// Check international code.

// Check specific phone number rules.

return true;

}

}

//注意上面的电话号码验证器的类都用了internal关键字进行修饰,也就是说这些类只在程序集内部可见,对外不可见,对外可见的只有IPhoneValidator接口