依赖项更改时强制类重新编译

bas*_*iat 6 c++ java oop interface solid-principles

语境:

我是java程序员,正在阅读Uncle Bob Agile软件开发.关于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();
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果接口服务发生变化,例如doB()添加了方法,那么所有依赖类ServiceClient都必须重新编译,即使它们不使用添加的方法!(真??)

  1. 对于java来说是真的吗?
  2. 这对c ++来说是真的吗?
  3. 对于哪些其他语言,它是真的,而不是?

我坚信,关于java if ServiceClient是否在包中,例如client.jar,接口Servicein service.jarServiceImplin impl.jar,然后client.jar不必重新编译和重建,如果它不使用来自Service接口的新方法,它可以与新版本的service.jarimpl.jar.在我看来,事情在java中是这样的.是其他在例如c ++或其他语言?

可能是在C++更坏,如 /sf/answers/282373031/

说清楚:

我不是要求重新编译实现更改接口的类(这很明显,它必须实现新添加的方法).但我问我是否必须重新编译使用此接口的类ServiceClient,即使类没有使用新添加的方法.可能在c ++ BC变化和客户端真的必须重新编译,但在我看来,不是在java中.

编辑:

我在java中实现了一个测试.4个罐子:

  • interface.jar - 包含接口 public interface Service
  • implementation.jar - 包含 public class ServiceImpl implements Service
  • 两个罐子上面的变化
  • 即使上面改变了,两个以下的罐子也没有改变
  • interfaceclient.jar -依赖interface.jar,包含类ClientOfService回吐Service作为构造函数的参数,它的使用该服务doA()的方法
  • application.jar - 依赖于以上所有jar.Main方法中的Class App创建ServiceImpl实例并将其作为arg传递给ClientOfService的构造函数,然后在ClientOfService上cals一个方法,该方法从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"); }

在应用程序的主要interface.jar和implementation.jar的变化后成功运行(我加了一些未使用的方法和删除一个旧方法).

所以挑战是如何改变界面(当然不改变doA()方法声明)和实现以阻止它成功运行?可能吗?如果是这样,怎么样?

Chr*_*phe 6

是的,如果更改了接口,则需要重新编译用Java和C ++实现的接口的类。这有几个原因,其中包括:

  • Java编译器需要检查实现接口的类是否仍然兼容(实现接口的类必须实现其所有方法)。
  • C ++编译器可能需要更改类的技术布局(例如,vtable如果doB()是虚拟的),并验证新创建的成员函数是否没有隐藏具有相同签名但在另一个基类中的另一个成员函数。

ISP的全部目的就是避免这种情况。因此,如果doB()实际上与该接口没有任何关系,则最好选择一个带有just的隔离接口doB(),并仅更改/重新编译需要实现该接口的类。

编辑:相同的原则适用于使用该接口的类。当然,某些参数可能取决于实现:

  • 对于C ++,为using类生成的代码将需要依赖正确的接口定义,以便可以对vtable布局做出正确的假设并生成正确的代码。这就是为什么使用类也需要重新编译的原因。
  • 对于Java,对接口方法的调用确实可以依赖于显式名称和运行时解析。我不是Java专家,所以这里有一个更正:Java规范实际上允许对接口进行一些更改,而无需重新编译。但是有些更改需要重新编译。