接口隔离原则是一世 in SOL一世D principles. According Robert Martin's Agile Software Development: Principles, Patterns and Practices, the principle is defined as, “Clients should not be forced to depend on methods that they do not use.” 一世n other words, classes should not have access to behavior it does not use. Let’s look at a Python example.
我们被雇用来创建一款游戏,玩家可以在其中设置娱乐系统。 系统的每一部分(电视,DVD播放器,游戏机等)都使用特定的电缆连接到另一台设备。 我们知道电视使用HDMI线连接到游戏机,而DVD播放器使用RCA线连接到电视。 游戏机和电视都通过以太网线连接到路由器,以便它们可以访问Internet。 最后,所有设备都通过电源线连接到墙壁,以便它们可以打开。
假设我们创建一个类来处理上面列出的所有连接。
class EntertainmentDevice:
def _connectToDeviceViaHDMICord(self, device): None
def _connectToDeviceViaRCACord(self, device): None
def _connectToDeviceViaEthernetCord(self, device): None
def _connectDeviceToPowerOutlet(self, device): None
现在,我们要做的就是将此接口扩展到我们的设备类。
class Television(EntertainmentDevice):
def connectToDVD(self, dvdPlayer):
self._connectToDeviceViaRCACord(dvdPlayer)
def connectToGameConsole(self, gameConsole):
self._connectToDeviceViaHDMICord(gameConsole)
def plugInPower(self):
self._connectDeviceToPowerOutlet(self)
class DvdPlayer(EntertainmentDevice):
def connectToTV(self, television):
self._connectToDeviceViaHDMICord(television)
def plugInPower(self):
self._connectDeviceToPowerOutlet(self)
class GameConsole(EntertainmentDevice):
def connectToTV(self, television):
self._connectToDeviceViaHDMICord(television)
def connectToRouter(self, router):
self._connectToDeviceViaEthernetCord(router)
def plugInPower(self):
self._connectDeviceToPowerOutlet(self)
class Router(EntertainmentDevice):
def connectToTV(self, television):
self._connectToDeviceViaEthernetCord(television)
def connectToGameConsole(self, gameConsole):
self._connectToDeviceViaEthernetCord(gameConsole)
def plugInPower(self):
self._connectDeviceToPowerOutlet(self)
查看每个班级,您会发现每个班级仅使用一种或两种方法娱乐系统设备。 例如,DVD播放机仅使用#connectToTV和#connectToPowerOutlet方法。 这些课程之间也有一些重复之处。 每个班级使用#connectToPowerOutlet。 首先,让我们来分离娱乐系统设备接口。
我们可以提取#connectToDeviceViaEthernetCord并创建一个专门针对互联网设备的课程。
class InternetDevice:
def _connectToDeviceViaEthernetCord(self, device): None
HDMI和RCA线均用于传输音频和视频数据。 两者之间的区别在于,RCA处理模拟信号,而HDMI处理数字信号。 我们可以利用这种差异来创建两个类,模拟设备和数字设备分别处理通过RCA和HDMI连接的设备。
class AnalogDevice:
def _connectToDeviceViaRCACord(self, device): None
class DigitalDevice:
def _connectToDeviceViaHDMICord(self, device): None
我们的娱乐系统设备该类现在只有#connectToPowerOutlet方法。 因为它仅处理将设备连接到插座的行为,所以应更改类名以反映该情况。 我们还可以定义一个#plugInPower使用的方法#connectDeviceToPowerOutlet方法。 我们重命名娱乐系统设备至WallPoweredDevice。
class WallPoweredDevice:
def plugInPower(self, device):
self.__connectToDeviceViaPowerOutlet(device)
def __connectToDeviceViaPowerOutlet(self, device): None
我们的课看起来很好。
class Television(WallPoweredDevice, InternetDevice, AnalogDevice, DigitalDevice):
def connectToDVD(self, dvdPlayer):
self._connectToDeviceViaRCACord(dvdPlayer)
def connectToGameConsole(self, gameConsole):
self._connectToDeviceViaHDMICord(gameConsole)
def connectToRouter(self):
self._connectToDeviceViaEthernetCord(self)
class DvdPlayer(WallPoweredDevice, AnalogDevice):
def connectToTV(self, television):
self._connectToDeviceViaRCACord(television)
class GameConsole(WallPoweredDevice, InternetDevice, DigitalDevice):
def connectToTV(self, television):
self._connectToDeviceViaHDMICord(television)
def connectToRouter(self):
self._connectToDeviceViaEthernetCord(self)
class Router(WallPoweredDevice, InternetDevice):
def connectToTV(self, television):
self._connectToDeviceViaEthernetCord(television)
def connectToGameConsole(self, gameConsole):
self._connectToDeviceViaEthernetCord(gameConsole)
最后,我们能够重构设备接口,使其只能访问其使用的行为。 由于行为是根据类支持的唯一行为分开的,因此扩展类充当子类的描述。 例如,我们知道路由器使用互联网,因此无需查看该类的内部功能,便需要将其插入墙中。
我们可以将这一想法更进一步,并说,类仅应在使用了该对象整个接口的地方使用对象。 在像Python这样的动态类型化语言中很难显示出来,因此我们将转换路由器类到Java并转换我们的互联网设备类到Java接口。
interface InternetDevice{
public void connectToDeviceViaEthernetCord(InternetDevice device);
}
class Router extends WallPoweredDevice implements InternetDevice{
public void connectToDeviceViaEthernetCord(InternetDevice device){}
}
在这个例子中路由器只能连接到使用互联网的其他设备。 因为我们想要只要有权访问与互联网设备, we tell it to 只要 understand objects that use the 互联网设备接口。
这样,即使我们实现了互联网设备像其他班级电视要么游戏机,路由器的#connectToDeviceViaEthernetCord将只能访问与互联网设备。
To learn more about Java interfaces, follow the link here.
向程序添加其他功能时,例如不仅通过以太网连接,而且还通过Wi-Fi连接到Internet,请务必注意这些方法的衔接。 这些方法之间的相互关系如何? 如果为某个类提供了在基类中定义的一组行为或在接口中得到确认的行为,则该类实际上需要该行为吗? 通过回答这些问题,我们能够创建易于重用的可重用通用类。
要点: