谈谈面向对象 之 封装

来源:互联网 发布:淘宝怎么找套现店铺 编辑:程序博客网 时间:2024/06/05 11:09

一、封装有什么好谈的?

封装就是封装啊,把成员变量呀、方法呀封装到一个类中。允许其它类访问的,就设置为public;允许子类访问的,就设置为protected;只能自己访问的,就设置为private。不就是这样么?

确实,封装基本上就是这样。

那还有什么好谈的?

这里老谭想谈谈封装的理念,以及开发实践中的一些具体做法。

二、封装的理念

如在谈抽象一文中所述,抽象是面向对象最重要的特征,对象由抽象而来,封装则是定义对象的手段之一,也就是说,封装是实现抽象的手段之一。

经过抽象,我们明确了对象的内容,明确了对象之间的关系,使得一个个对象具备了完整的概念。封装则使得这些概念得以落地:将对象的内部状态遮盖起来,将对象的内部方法遮盖起来,外部仅可以通过公开的接口与其交互,而这些公开的接口体现了对象的完整概念。

@元模式之高茂源 说的很有道理:面向对象中的抽象,应该翻译成协议更准确。封装,使得对象间仅需公开协议。

封装有多种不同的粒度:子系统隐藏内部实现,公开相互之间的服务调用接口;程序集/组件隐藏内部实现,公开API。但在面向对象环境中讨论封装,我们主要关注类的定义。

三、原则:最大限度的封装

在实际开发中,我们提倡的原则是,最大限度的封装。即,对于类或其属性/方法而言:

  1. 能设置为private的,不设置为protected,能设置为protected的,不设置为public;
  2. 如果可以为static的,就设置为static;
  3. 对于类而言,能设置为internal的,不设置为public;
  4. 不设置public的成员变量。

在具体的开发实践中,使用最大封装原则时会遇到一些实际的情况,如:

  1. 一些方法没有被用到,设置为private了,但是随着外部需求的进展,需要改为public。为避免这种修改频繁发生,干脆一开始都设置为public,更为便捷;
  2. 将类设置为internal,单元测试不方便。

对于第一个情况,不是简单的public/private的设置问题,而是意味着模块之间接口不稳定,或者处于含糊阶段。这就要求回到设计阶段,明确模块之间的接口。在具体的开发技术上,鼓励采用面向接口的开发,强制要求明确模块之间的接口。

对于第二个情况,建议首先考虑上一个建议,将单元测试和被测试代码之间的关系定位为模块之间的调用关系,测试对象不涉及到internal的类。如果考虑测试的便利性,例如确实不希望做繁琐的配置或fake,而是直接测试internal类的成员,可以考虑使用C#提供的 InternalVisibleTo 属性,来明确模块中的internal类,对于单元测试项目是可见的。

四、类内方法的封装

封装不仅限于对象之间,对象内部也有封装的用武之地:提取方法。

提取方法是重构的技术之一,创建类的私有方法,将处理逻辑封装到这样的私有方法内。这本质上是一种抽象过程,结果是提炼出了一段处理逻辑。封装则是落实该过程的具体措施,定义了一个私有方法,用于实现提炼出的处理逻辑。

提取方法一般用于三种情形:

  1. 分解长方法。如果一个方法太长,则常常意味着其中包含了较复杂的业务逻辑,需要将业务逻辑分解,封装到各个“子逻辑”中;
  2. 公共方法提炼。多处处理重复使用相同或相似的代码,需要将其提炼出来,封装到可以公共使用的方法中;
  3. 明确语义。如果从代码上看不出业务含义,需要编写注释,则可以将这样的代码封装到方法中,通过方法名体现业务含义。

五、总结

封装是实现抽象的手段之一。

其它还有什么?继承和多态。待续。


0 0
原创粉丝点击