Рубрики
Без рубрики

Типы пересечений в Java

Цель этого сообщения в блоге – объяснить, как мы можем использовать типы пересечений в Java, когда мы ожидаем объект tha… Помеченный java.

Цель этого сообщения в блоге – объяснить, как мы можем использовать типы пересечений в Java, когда мы ожидаем объект, реализующий различные интерфейсы.

Принцип разделения Интерфейсов

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

Например, давайте возьмем этот File интерфейс:

interface File {
  Collection readLines();
  void write(String line);
  void deleteFile();
}

class LocalFile implements File {
  // ...
}

Как клиент этого интерфейса, крайне маловероятно, что мне понадобятся все методы. Возможно, я захочу просто прочитать файл, и в этом случае я, конечно, не хочу иметь возможность удалять его. Если я просто хочу удалить файл, я, вероятно, не захочу читать все его строки.

Чтобы избежать этого, рекомендуется разделить этот интерфейс на 3 отдельных:

interface FileReader {
  Collection readLines();
}

interface FileWriter {
  void write(String line);
}

interface FileDestroyer {
  void deleteFile();
}

class LocalFile implements FileReader, FileWriter, FileDestroyer {
  // The concrete class can implement all 3 interfaces
  // ...
}

Теперь клиент может просто запросить нужный ему интерфейс и игнорировать все остальное.

Комбинация интерфейсов

Написание крошечных интерфейсов полезно для обеспечения безопасности интернет-провайдера и снижения сцепления кода. Однако, что происходит, когда клиент хочет прочитать файл и записать одновременно?

Первые два фрагмента не будут компилироваться, потому что один из интерфейсов не реализован:

void readAndWrite(FileReader reader) {
  reader.readLines();
  reader.write("Hello"); // That won't compile since reader does not implement FileWriter
}

void readAndWrite(FileWriter writer) {
  reader.readLines(); // That won't compile since writer does not implement FileReader
  reader.write("Hello");
}

В качестве альтернативы можно передать экземпляр Local File но это создает высокую связь между методом и конкретным классом Local File , полностью сводя на нет всю цель интерфейсов.

void readAndWrite(LocalFile file) {
  file.readLines();
  file.write("Hello");
  // That will compile but it is not recommended
}

Начиная с Java 1.5 и введения дженериков, функция, известная как Типы пересечений, позволяет комбинировать интерфейсы в такого рода ситуациях.

Типы перекрестков спешат на помощь

Следующий код использует типы пересечений для решения проблемы необходимости объекта, реализующего несколько интерфейсов:

 void readAndWrite(T file) {
  file.readLines();
  file.write("Hello");   
}

Символ & означает, что метод ожидает тип T который реализует как интерфейсы FileReader , так и FileWriter .

Вывод

Типы пересечений – это функция, которая не так широко используется в Java. Однако он очень мощный, поскольку позволяет писать очень крошечные интерфейсы и комбинировать их по требованию. Отныне нет никаких оправданий для написания больших толстых интерфейсов, которые имеют десятки совершенно не связанных методов!

Оригинал: “https://dev.to/rnowif/intersection-types-in-java-1jk8”