Обязательная перекомпиляция класса при изменении зависимости - PullRequest
0 голосов
/ 02 декабря 2018

Контекст:

Я Java-программист и читаю Uncle Bob Agile Software Development.Что касается принципа сегрегации интерфейса 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, должны быть перекомпилированы, даже если они не используют добавленный метод!(действительно ??)

  1. Верно ли это для Java?
  2. Верно ли это для c ++?
  3. Для каких других языков это верно, а для каких нет?'t?

Я был убежден, что в отношении Java, если ServiceClient в пакете, например, client.jar, интерфейс Service в service.jar и ServiceImpl в impl.jar, затем client.jar не нужно перекомпилировать и перекомпилировать, если он не использует новые методы из интерфейса службы и может использоваться вместе с новыми версиями service.jar и impl.jar.Мне кажется, что дела обстоят именно так в Java.Это что-то другое, например, в c ++ или некоторых других языках?

Возможно, в c ++ гораздо больше проблем, например, https://stackoverflow.com/a/4033900/1423685

Чтобы было ясно:

Я незапрос о перекомпиляции класса, реализующего измененный интерфейс (это очевидно, класс должен реализовать новый добавленный метод).Но я спрашиваю, должен ли я перекомпилировать класс ServiceClient, который использует этот интерфейс, даже когда класс не использует новые добавленные методы.Возможно в c ++ BC изменения и клиент действительно должен быть перекомпилирован, но мне кажется, что не в java.

Edit:

Я реализовал тест в java.4 банки:

  • interface.jar - содержит интерфейс public interface Service
  • creation.jar - содержит public class ServiceImpl implements Service
  • две вышеупомянутые банки заменяют
  • два приведенных ниже jar-файла не изменились даже после изменения выше
  • interfaceclient.jar - зависит от interface.jar, содержит класс ClientOfService, принимая Service в качестве параметра конструктора, использует этот сервис в doA()method
  • application.jar - зависит от всех вышеуказанных jar-файлов.Класс App в методе main создает экземпляр ServiceImpl и передает его в качестве аргумента конструктору ClientOfService, затем вызывает метод на ClientOfService, который выполняет вызов метода doA () из Service: 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 и creation.jar (я добавил несколько неиспользуемых методов и удалил один старый метод).

Таким образом, задача состоит в том, как изменить интерфейс (конечно, без изменения doA() объявление метода) и реализация, чтобы остановить его успешную работу?Является ли это возможным?Если так, то как?

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Для каких других языков это правда, а для каких нет?

Это действительно специфическая для реализации характеристика, а не языковая характеристика.

Перекомпиляцияобычно требуется для языковых реализаций, которые компилируют доступ членов на интерфейсах к адресам памяти или индексам массивов таблицы функций.Вот как реализованы большинство статических языковых компиляторов.Большинство реализаций Java и C подпадают под эту категорию.

Перекомпиляция не понадобится для реализации языков, которая компилирует доступ членов к поиску по словарю (так что для поиска используется имя функции, а не замещающий индекс).Вот как реализованы большинство динамических компиляторов языков.Например, большинству реализаций Python не нужно воссоздавать файлы .pyc, если классы в другом файле изменяют его интерфейс.

Таким образом, основное различие между статическим и динамическим языком.Есть исключения, конечно.На некотором статическом языке можно гарантировать, что любые новые дополнения будут добавлены в таблицу функций, поэтому существующий код, код которого использует старые индексы, все еще будет работать.Для авторов библиотек на большинстве статических языков важно поменять интерфейсы только так, чтобы сохранить двоичную совместимость, если это допускает языковая реализация.

0 голосов
/ 02 декабря 2018

Да, если вы измените интерфейс, вам нужно перекомпилировать классы, которые реализуют его в Java и в C ++.Это имеет несколько причин, среди прочего:

  • компилятору Java необходимо проверить, все ли совместимы классы, реализующие интерфейс (класс, реализующий интерфейс, должен реализовывать все его методы).
  • компилятору C ++ может потребоваться изменить техническое расположение классов (например, vtable, если doB () является виртуальным) и проверить, не скрыта ли другая функция-член с такой же сигнатурой, но в другом базовом классенедавно созданным.

Весь провайдер должен избегать подобных ситуаций.Поэтому, если doB() на самом деле не имеет ничего общего с этим интерфейсом, вам лучше использовать отдельный интерфейс с doB() и изменять / перекомпилировать только те классы, которые должны его реализовать.

Редактировать: Тот же принцип применяется к классам, которые используют интерфейс.Конечно, некоторые аргументы могут зависеть от реализации:

  • Для C ++ код, сгенерированный для класса using, должен будет полагаться на правильное определение интерфейса, чтобы он мог делать правильные предположения оверстка vtable и генерация правильного кода.Вот почему перекомпиляция также необходима для использования классов.
  • Для Java вызов методов интерфейса может действительно полагаться на явные имена и разрешение во время выполнения.Я не специалист по java, так что здесь исправление: некоторые изменения в интерфейсе на самом деле разрешены спецификациями Java без необходимости перекомпиляции.Но некоторые изменения требуют перекомпиляции.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...