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

3 причины начать использовать интерфейсы Java

что такое интерфейс? 🚪 Oracle говорит: “Интерфейс – это группа связанных методов с пустым значением… С тегом java, веб-разработчик, программирование, учебное пособие.

Oracle говорит: “интерфейс – это группа связанных методов с пустыми телами”

Я думаю об интерфейсах как о контракте, который класс обещает компилятору выполнить. Если класс не выполняет обещанного, компилятор пожалуется и выдаст сообщение об ошибке.

Зачем связывать себя этим контрактом и позволять компилятору кричать на меня о невыполненном обещании? Почему бы мне просто не написать методы внутри класса и не покончить с этим?

Проведя некоторое время в этой отрасли, я начал понимать, почему мы их используем. Я перечислю наиболее важные три причины с моей точки зрения.

Допустим, ваша команда пишет новую услугу, которая будет добавлена в список услуг, предлагаемых вашей компанией, а другие команды напишут некоторые другие сервисы, которые будут использовать вашу услугу.

Как они узнают, какой метод вызывать? какие параметры передать? какой тип возврата следует ожидать?

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

Вот интерфейс, который документирует, как взаимодействовать со службой регистрации

public interface IRegistrationService {
    void registerNewUser(String userName);
    boolean userIsRegistered(String userName);
    void cancelRegistration(int registrationId);
    void cancelRegistration(String userName);
}

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

public class RegistrationService implements IRegistrationService {
    public void registerNewUser(String userName) {
        // production code
    }
    public boolean userIsRegistered(String userName) {
        // production code
        return false; // the result of prod code
    }
    public void cancelRegistration(int registrationId) {
        // production code
    }
    public void cancelRegistration(String userName) {
        // production code
    }
}

Представьте, что мы хотим написать спецификацию что что-то должно делать, но не писать, как это должно быть сделано , и оставить эту деталь тому, кто хочет, чтобы это произошло.

Возможно, самым известным примером этого является JPA (Java Persistence API) JPA – это набор интерфейсов, который определяет, как должна выглядеть сохраняемость базы данных в приложениях Java. Существует несколько реализаций этих интерфейсов

  • Зимовать
  • Toplink
  • EclipseLink
  • Apache OpenJPA
  • и еще много чего

Давайте приведем пример на “Как пользоваться автомобилем” спецификация

public interface CarDrivingSpecification {  
        void startEngine();  
        void pressGas();  
        int getGasLeftInTank();  
        // can the car go for the kilometers provided, taking into consideration the gas left in the tank   
        boolean canGoForGivenKms(float kms);
    }

Здесь мы только указываем, что будет делать класс, реализующий этот интерфейс, а не фактическую реализацию того, как он это делает.

Третьим и наиболее важным примером использования интерфейсов является тот факт, что они позволяют нам использовать мощную концепцию Полиморфизм .

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

Это может сделать ваш код намного более элегантным и чистым. Но сначала, что такое полиморфизм ? Это позволяет нам говорить что-то вроде: “Объект student можно рассматривать как объект Human” или “Объект Car можно рассматривать как объект Vehicle”.

Но как полиморфизм может помочь нам написать чистый код? Давайте напишем некоторый код, который НЕ использует полиморфизм.

Давайте начнем с объявления классов сущностей Класс велосипеда 🚲

import lombok.AllArgsConstructor;  
@AllArgsConstructor  
public class Bicycle {  
     private final int Id;  

     public void goForward(){  
         System.out.println("Bike forward");  
      }  
}

Класс автомобиля 🚘

import lombok.AllArgsConstructor;  
@AllArgsConstructor  
public class Car {  
     private final int Id;  

     public void goForward(){  
          System.out.println("Car forward");  
      }  
     public void checkEngine(){  
         System.out.println("Checking Car engine");  
       }  
}

Класс грузовика 🚚

import lombok.AllArgsConstructor;  
@AllArgsConstructor  
public class Truck {  
     private final int Id;  

     public void goForward(){  
          System.out.println("Truck forward");  
     }  
     public void checkEngine(){  
         System.out.println("Checking Truck engine");  
       }  
 }

Теперь давайте напишем службу, которая будет использовать эти классы и запускать методы каждого объекта

   public class TrafficService {  
    private List getBicyclesFromMap(){  
        return Arrays.asList(new Bicycle(1), new Bicycle(2));  
    }  
    private List getCarsFromMap(){  
        return Arrays.asList(new Car(1), new Car(2));  
    }  
    private List getTrucksFromMap(){  
        return Arrays.asList(new Truck(1), new Truck(2));  
    }  

    public void goForward(List bicycles, List cars, List trucks){  
        bicycles.forEach(Bicycle::goForward);  
        cars.forEach(Car::goForward);  
        trucks.forEach(Truck::goForward);  
    }  

    public void checkEngine(List cars, List trucks){  
        cars.forEach(Car::checkEngine);  
        trucks.forEach(Truck::checkEngine);  
    }  

    public void makeAllTransportGoForward(){  
        goForward(getBicyclesFromMap(), getCarsFromMap(), getTrucksFromMap());  
    }  
    public void makeAllEnginesStart(){  
        checkEngine(getCarsFromMap(), getTrucksFromMap());  
    }  
}

Прежде всего, мы должны были указать метод для каждого класса объектов, чтобы получить его экземпляры с карты. Также обратите внимание, что в методе forward мы должны были передать в качестве параметров три типа объектов (Велосипед, Автомобиль, Грузовик), и мы должны были вызвать метод goForward для каждого класса объектов. Теперь, для трех сущностей, это не большая проблема. Однако, когда у вас есть 10 или даже 100 единиц, это быстро становится проблемой.

Давайте применим интерфейсы и полиморфизм и посмотрим на результаты

Мы начнем с определения интерфейсов, Интерфейс Transport

public interface Transport {  
      void goForward();  
}

Интерфейс Vehicle , который расширяет транспортный интерфейс

public interface Vehicle extends Transport{
     void checkEngine();
}

Классы сущностей отмечают, что мы заставляем классы реализовывать интерфейсы . Откинуть капот 🚚

import lombok.AllArgsConstructor;  
@AllArgsConstructor
public class Bicycle implements Transport{
    private final int id;
    public void goForward() {
        System.out.println("Bike forward");
    }
}
// other class
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class Car implements Vehicle{
    private final int id;
    public void checkEngine() {
        System.out.println("Checking Car engine");
    }
    public void goForward() {
        System.out.println("Car forward");
    }
}
// other class
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class Truck implements Vehicle{
    private final int id;
    public void checkEngine() {
        System.out.println("Checking Truck engine");
    }
    public void goForward() {
        System.out.println("Truck forward");
    }
}

Служба, которая использует классы Полиморфизм

public class TrafficService {
    List getTransportFromMap(){
        return Arrays.asList(
                new Bicycle(1), new Bicycle(2),
                new Car(1), new Car(2),
                new Truck(1), new Truck(2));
    }

    List getVehicleFromMap(){
        return Arrays.asList(
                new Car(1), new Car(2),
                new Truck(1), new Truck(2));
    }

    public void goForward(List transports){
        transports.forEach(Transport::goForward);
    }

    public void checkEngine(List vehicles){
        vehicles.forEach(Vehicle::checkEngine);
    }

    public void makeAllTransportGoForward(){
        goForward(getTransportFromMap());
    }
    public void makeAllEnginesStart(){
        checkEngine(getVehicleFromMap());
    }
}

Что нам помогли сделать интерфейс и полиморфизм? 💪

  • Соберите те объекты, которые имеют совместимый интерфейс (транспортное средство, Транспорт), в единую структуру данных списка.

    • Метод goForward обрабатывает все объекты, которые реализуют транспорт интерфейса, в одной команде и запускает конкретную реализацию каждого из них.
    • То же самое относится и к методу check Engine, который обрабатывает все объекты, реализующие интерфейс транспортного средства.
    • Таким образом, наш код стал намного чище!!!

Интерфейсы имеют три основных способа использования

  1. создание и документирование API-интерфейсов
  2. написание спецификации для реализации другими людьми
  3. использование полиморфизма для написания читаемого чистого кода.

GitHub

Оригинал: “https://dev.to/jarjanazy/3-reasons-to-start-using-java-interfaces-43ee”