Note: 这里的‘封装(Encapsulation)’指的是限制对象访问的语言特性,也被称为信息隐藏(information hiding)。翻译的初衷在于看看一些不同的想法,作者的思考在某个层次上是有道理的,但并是完全正确。总之这里有一个决策和角度的问题。
没有封装的OOP?
Python支持Object Oriented Programming, 却没有封装(encapsulation). 许多都对此不解,但讨论来讨论去,最终的结论是OO压根不需要封装。 Python里什么公有的,如果在成员名字前加两个下划线则表示不能由外部使用,也即非接口类的成员。但也有办法使用,当然风险自理。Python开发者称之为命名约定式的封装,而非强制封装。本质上,这并不是封装,也没有隐藏什么。原因何在?
用电脑做个比喻
我可以随时打开我的电脑,升级一下,或者换个部件,这很容易做到。如果硬件厂商也开始使用封装,我们可能很难再打开机箱,如果要加个内存或换个什么,就只能送回厂家了。
如上封装限制了对实现细节的使用。但确实需要时,就只能自己动手了。硬件上并没有限制我把它打开,软件为什么要这样做?
使用抽象代替封装
一个关于抽象(abstraction)的定义说到: ‘the act of considering something as a general quality or characteristic, apart from concrete realities, specific objects, or actual instances.’.
从编程上看,意思就是在实现之上提供一个接口,用户只需要知道接口层(即抽象层),而不用关心实现的细节。与封装的差异在于,如果用户想要去了解那些潜在的细节,仍然可以做得到。绝大多数硬件都是使用抽象代替封装,使用一个很少变化的接口,同时允许高级用户窥看细节。
当使用抽象代替封装时,用户可以清楚地看到接口,和使用封装的方式也没什么差别。我们鼓励用户使用开放的接口,但并不仅限于此。对于使用接口而言,抽象与封装的效果是一样的,只是前者允许访问背后的内容。这样使用者完全可以了解到他的行为可能带来的风险。
一个实例
假设我用一个跨平台的GUI库来开发应用程序。跨平台的GUI库好用,在不同平台上也保持相同的接口,会省去不少麻烦。
假设Windows用户希望添加一个特别的功能。这个时候,你如果坚持封装,你会面临如下的问题::
- 在原来的GUI库上实现一个新的库,这样就要包括其它的接口。
- 联系厂商做特殊修改,这个可能性不大,即使可行,也未必来得及!
- 放弃原先的库,在Windows上使用新的库。这个风险很高,成本也很高!
如果你转而使用抽象呢? 除了上面的选项外,你可以动到库里的细节实现,不过要考虑一下几个风险:
- 有没有可以破坏其它行为。
- 库的升级可能导致你的修改失败,所以每次升级时都要检查一下它的行为是否仍然正常。
- 当然库的厂商可不一定愿意为你提供技术支持了。
就是说,使用抽象代替封装时,你一定要自行权衡利弊。我可不是鼓励大家使用那些细节的内容,只是在一些情况下,这可能是一个最佳方案。
How I do it
在传统的OO语言,我将接口定义为public, 其它实现的细节内容我定义在protected中。四人帮曾经说: “因为继承会将父类的实现细节暴露给子类,所以通常称为‘继承破坏了封装’’”. 事实上,这正是我想要的效果。我的用户可以使用public接口,如果需要,他们可以子类化自己的类。
这招让我省了不少的事,我不用再纠结于private, protected或者public。我的座佑铭正是:Keep It Stupid Simple.
封装不是安全
把数据隐藏或者保护起来不让用户接触到,通常讲是很有必要的。但如果是要讨论安全性,我认为通过封装来实现安全性是极为糟糕的。
结论
依赖于细节实现绝不是什么好主意,所以只能使用类的公共接口。不过总有些意思不到情况让你需要使用一些内部细节,这个时候最好把类设计更加有用一些,让用记可以通过一些专业的方式来使用它。用户不是白痴,要假定他们都是专家,可以很合理的使用你的类来解决一些问题。如果他们要访问一些细节内容,自然有他们的理由,或许就是别无它法。所以,不要拿封装来对付他们。
原文地址.
转载请注明出处:http://blog.csdn.net/horkychen