Источник: Nuances of Programming
Привет всем Android-разработчикам! Давайте разберем принципы SOLID, вернее, один из них.
Недавно я углубился в SOLID и нашел один скрытый потенциал. Теперь хочу рассказать про него вам, не углубляясь в теорию.
Вернемся в недалекое прошлое и с нуля создадим проект с помощью Gradle на языке Java без дополнительной конфигурации сборки. Структура сборки приведена ниже.
На момент написания статьи версия Gradle v6.8.3. С плагином Java функция инкрементной компиляции включена по умолчанию.
Теперь представим, что Client1 использует только метод m1, Client2 — только метод m2, а Client3 метод m3 класса Service. Как вы думаете, что произойдет, если мы изменим тело m3 и еще раз скомпилируем проект?
Можно предположить, что если мы внесли бинарное совместимое изменение в тело метода, то скомпилироваться должен только Service. Но в действительности компилируется весь проект.
Чтобы вывести результат сразу в Gradle, воспользуемся опцией listFiles для Java компиляции. Она записывает все компилируемые файлы.
tasks.withType(JavaCompile) {
options.listFiles = true
}
Скомпилируем исходные Java-файлы с помощью JDK компилятора, вызвав задачу compileJava. Как правило, ее запускают с задачей build или assemble .
./gradlew compileJava
Наконец, можем увидеть все скомпилированные файлы:
> Task :compileJava
Source files to be compiled:
/ISP_java/src/main/java/com/jurcik/ivet/service/Service.java
/ISP_java/src/main/java/com/jurcik/ivet/client/Client1.java
/ISP_java/src/main/java/com/jurcik/ivet/client/Client2.java
/ISP_java/src/main/java/com/jurcik/ivet/client/Client3.java
Почему так происходит?
Дело не в Gradle и его работе. Полученный результат — ожидаемое поведение Java. Ведь двоичная совместимость не влияет на список компилируемых исходных файлов.
Все объявления, которые должны быть импортированы в исходный код, создают зависимость кода. Таким образом, исходный код Client1 зависит от метода m2 и m3, хоть он и не вызывает их. Поэтому, изменяя код m2 или m3 в классе Service, Client1 будет еще раз скомпилирован, несмотря на то, что он не менялся.
Принцип разделения интерфейса спешит на помощь
Принцип разделения интерфейса следующий: ни один клиент не должен вынужденно зависеть от методов, которые он не использует.
Применим его и создадим для каждого метода отдельный интерфейс, который предоставит определенному клиенту только то, что ему нужно. Ниже проиллюстрирована структура:
Теперь еще раз внесем бинарное совместимое изменение в тело m3 класса Service и скомпилируем проект.
./gradlew compileJava
Вот оно!
> Task :compileJavaSource files to be compiled:/ISP_java/src/main/java/com/jurcik/ivet/service/Service.java
Скомпилировался только Service.
Что насчет Kotlin?
Компилятор Kotlin достаточно умный. Отслеживая изменения с помощью двоичного интерфейса приложений, он перекомпилирует только измененные файлы. Однако он не отменяет принцип SOLID, а лишь упрощает его выполнение.
Заключение
Каждый разработчик, знакомый с ООП наверняка слышал о принципах SOLID. Мы регулярно применяем их по несколько раз, не замечая этого. Несмотря на то, что они глубоко укоренились у нас в голове, им стоит уделять особое внимание. Ведь они не ограничены лишь архитектурой системы.
Читайте также:
Перевод статьи Iveta Jurčíková: Compile less with SOLID