本节书摘来自华章出版社《面向对象的思考过程(原书第4版)》一书中的第1章,第1.8节,[美] 马特·魏斯费尔德(Matt Weisfeld) 著黄博文 译更多章节内容可以访问“华章计算机”公众号查看。
1.8.1 接口
我们可以看到接口定义了对象之间通信的基本手段。每个类设计接口规格来保证对象能被正确实例化和操作。必须向对象提供的接口发送消息来使用对象暴露的任何行为。接口需要完整描述类与类之间的交互。在大多数面向对象的语言中,访问修饰符指定为public的方法属于接口。
私有数据
为了实现数据隐藏,必须将所有属性声明为private。属性绝不是接口的一部分。只有Public方法是类接口的一部分。将属性描述为public破坏了数据隐藏这一概念。
我们回过头看一个使用的例子;计算一个数字的平方值。在这个例子中,包括两个接口:
如何实例化一个Square对象。
如何传递给该对象一个值,并获取返回的平方值结果。
正如在本章前面讨论的一样,如果用户需要访问一个属性,我们会创建一个方法(即getter,又称为取值方法)来返回该属性值。然后用户想要获取该属性值,只需调用取值方法即可。在这种方式中,拥有该属性的对象可以控制访问该属性。这种控制非常重要,特别对安全、测试和维护而言。如果你可以控制对属性的访问,当出现了问题,无需追踪所有可能修改了该属性的代码片段,我们只需要修改一个地方(即setter,又称为赋值方法)。
基于安全的原因,你需要防止不受控的代码对诸如密码和个人信息等数据进行修改和获取。
类接口与方法签名
请注意类有接口,方法也有接口。不要混淆这两个接口的概念。类的接口是公共方法。你使用方法的签名来调用这些公共方法。方法的签名主要由方法名和它的参数列表组成。稍后会详细介绍方法签名这一概念。
1.8.2 实现
只有公共属性和方法被认为是接口。用户通过类接口与对象交互时,不应该看到该对象任何内部实现的部分。任何被定义为私有的东西对用户都是不可访问的,这些私有资源属于该类的内部实现。
在之前的例子中,只隐藏了Employee类的实例的属性。很多情况下,也应该隐藏某些方法,不作为接口的一部分。上节的求平方值的例子中,用户不应该关心平方值是如何被计算出来的,只要答案正确即可。我们可以修改实现,但不应该影响用户的代码。例如,提供该计算器的公司可以改变算法(很可能因为该算法更高效)而不会影响结果。
1.8.3 接口/实现范式的一个真实示例
图1-12使用了真实的对象演示了接口/实现范式,这里没有使用代码。烤面包机需要电。为了得到电,烤面包机的插头必须插到电源插座,电源插座就是接口。所有需要获取电力的烤面包机需要实现一个插头,要与电源插座规格适配。这是烤面包机和电力公司(事实上是能源行业)之间的接口。电力设备会关心实际的实现,而烤面包机则无需担心。事实上,对于所有面包机而言,电力实现可能是原子能设备或本地发电机。基于这样的模型,一个装置只要满足接口规格,就可以获取电力,如图1-12所示。
1.8.4 接口/实现范式的模型
我们再拿Square类来举例。假设你正在编写一个计算整数平方值的类。你必须提供接口和实现,也就是说必须定义一种方式使用户能调用并获取平方值,也要实现计算平方值。然而,用户不应该知道任何详细的实现。图1-13展示了一种实现方式。注意在该类图中,加号(+)表示public访问修饰符,而减号(-)表示private访问修饰符。即你可以通过给方法指定加号签名的方式来定义接口。
该类图代码如下:
注意该类中用户唯一能访问的元素就是公共方法getSquare。该公共方法就是接口。求平方值算法的实现在私有方法calculateSquare中。请注意属性SquareValue是私有的,因为用户无需知道该属性的存在。因此对象隐藏了一部分实现,只暴露了用户需要与之交互的接口。与使用该对象无关的细节则对其他对象是隐藏的。
如果要修改实现,比如你想使用语言内置的平方值函数,你不需要修改接口。下面代码使用了Java库的方法Math.pow,其提供了同样的功能,但接口依然是calculateSquare:
用户使用相同的接口会得到相同的功能,但具体实现却变了。如果你编写处理数据的代码时可以利用这一点。例如,你可以把数据存储从文件转移到数据库中,而不必强制用户改变任何程序代码。如下