上下文:
我是Java程序员,正在阅读Bob叔叔敏捷软件开发。关于ISP接口隔离原则,我可以理解为:
让我们拥有:
interface Service {
function doA();
}
class ServiceImpl implements Service {...}
class ServiceClient {
// ServiceImpl is injected; eg either through constructor or setter
private Service service;
function useOnlyDoA() {
service.doA();
}
}
现在,如果接口服务发生更改,例如添加方法doB()
,然后添加所有相关类,例如ServiceClient
必须重新编译,即使它们不使用添加方法! (真的吗?)
我坚信,如果ServiceClient
位于软件包中,则关于Java。 client.jar
,Service
中的接口service.jar
和ServiceImpl
中的impl.jar
的接口,则client.jar
不必重新编译并重建(如果没有)请勿使用Service界面中的新方法,并且可以将其与service.jar
和impl.jar
的新版本一起使用。在我看来,java中的情况是这样的。
是其他语言,例如c ++还是其他语言?
可能在C ++中有更多损坏,例如 https://stackoverflow.com/a/4033900/1423685
为清楚起见:
我不是在问重新编译实现更改接口的类(这很明显,它必须实现新添加的方法)。 但是我问我是否必须重新编译使用此接口的ServiceClient类,即使该类未使用新添加的方法也是如此。可能是在c ++ BC更改中,确实必须重新编译客户端,但是在我看来,这不是在Java中。
编辑:
我用Java实现了一个测试。 4罐:
public interface Service
public class ServiceImpl implements Service
ClientOfService
作为构造函数参数的类Service
,并在其doA()
方法中使用此服务
public static void main(String[] args) {
Service service = new ServiceImpl();
ClientOfService clientOfService = new ClientOfService(service);
System.out.println("App.main() :: calling clientOfService.doWorkCallingDoAFromService");
clientOfService.doWorkCallingDoAFromService();
System.out.println("App.main() :: end of main");
}
调用方法doA()更改interface.jar和Implementation.jar后,App中的主程序成功运行(我添加了一些未使用的方法,并删除了一个旧方法)。
因此面临的挑战是如何更改接口(当然,无需更改doA()
方法声明)和实现以使其成功停止运行?可能吗?如果是这样,怎么办?
答案 0 :(得分:4)
是的,如果更改了接口,则需要重新编译用Java和C ++实现的接口的类。这有几个原因,其中包括:
vtable
,如果doB()是虚拟的),并验证是否没有隐藏具有相同签名但在另一个基类中的另一个成员函数。新创建的一个。 ISP的全部目的就是避免这种情况。因此,如果实际上doB()
与该接口无关,则最好使用仅包含doB()
的隔离接口,并仅更改/重新编译需要实现该接口的类。
编辑:相同的原理适用于使用该接口的类。当然,其中一些参数可能取决于实现:
答案 1 :(得分:0)
对其他哪些语言来说这是真的,对哪些不是呢?
这实际上是特定于实现的特征,而不是语言特征。
语言实现通常需要重新编译,这些实现将接口上的成员访问编译到函数表的内存地址或数组索引。这就是大多数静态语言编译器的实现方式。大多数Java和C实现都属于此类。
对于编译成员对字典查找的访问的语言实现,则不需要重新编译(以便它使用函数名进行查找,而不是使用替代索引)。这就是大多数动态语言编译器的实现方式。例如,如果另一个文件中的类更改了其接口,则大多数Python实现无需重新创建.pyc文件。
因此,主要的区别是静态和动态语言之间。当然也有例外。可以使用某种静态语言来确保将任何新添加项添加到功能表中,因此使用旧索引的代码的现有代码仍然可以使用。对于大多数静态语言的库作者而言,重要的考虑因素是,如果语言实现允许,仅以保留二进制兼容性的方式更改接口。