Урок 16. Интерфейсы Java


В этой статье из моего бесплатного курса Java 8 я объясню тему интерфейсов в Java.

Интерфейс - это общий термин, который широко используется в различных областях. Можно сказать, что это как бы точка взаимосвязи между сущностями. Данный термин был адаптирован к программированию и играет ключевую роль в объектно-ориентированном программировании (ООП). В ООП интерфейс определяется как “фрагмент кода, определяющий набор операций, которые должен реализовать другой код”.

История интерфейса

Несмотря на то, что многие считают, что идея интерфейса была первоначально введена в программирование именно в Java, на самом деле она была введена Брэдом Коксом и Томом Лав, создателями Objective C, с концепцией протокола.

Причина, по которой в Java имеются интерфейсы, в том, чтобы улучшить наследование в C++. Можно сказать, что Java была преемницей C++, и в C++ они использовали модель, включающую множественное наследование. Множественное наследование является более сложным и проблематичным, чем модель одиночного наследования, которая использовалась в Java. Кроме того, гораздо сложнее реализовать множественное наследование в компиляторе.

Интерфейсы были введены в качестве замены множественного наследования. Как ни странно, интерфейсы были введены в Java не для того, чтобы создать “более чистый, более модульный и четко разделенный код”, а скорее просто для того, чтобы компенсировать тот факт, что Java не поддерживает множественное наследование. Однако в наши дни именно для этого и нужны интерфейсы.

Написание интерфейса

В этом примере мы создадим класс CarService. Мы знаем, что хотим, чтобы наш класс CarService имел метод под названием drive. Когда привод вызывается в классе CarService, мы собираемся заставить все автомобили в нашем сервисе ездить.

package ru.upread.javacourse;

public class CarService {

	public void drive() {
		BMW bmw = new BMW();
		Porsche porsche = new Porsche();
		Mercedes mercedes = new Mercedes();
		bmw.drive();
		porsche.drive();
		mercedes.drive();
	}
}
Как вы можете видеть в примере выше, наш CarService создает еще три объекта. На данный момент класс CarService тесно связан с этими другими классами автомобилей. Каждый автомобиль - это свой собственный класс, без какой-либо реальной связи, кроме того, что у каждого из них есть метод привода. Это то, чего мы не хотим, и я объясню почему более подробно позже.

Вот где мы можем улучшить наш код с помощью интерфейса. В нашем коде есть три разных автомобиля. Все эти машины могут ездить, и вы уже можете видеть, что у нас есть три различных способа вождения. Мы могли бы просто создать класс Car и значение carType в этом классе, но метод drive в этом гипотетическом классе заставит все наши различные типы ездить одинаково. Это проблема, потому что разные автомобили ездят по-разному. Например, конкретные типы автомобилей (BMW, Mercedes и Porsche) имеют свои собственные уникальные двигатели. С другой стороны, мы уже признали, что все эти автомобили ездят, и у них также есть другие сходства, такие как четыре колеса и две оси. Эти общие функции могут быть сгруппированы вместе и доступны без знания конкретного типа автомобиля с помощью интерфейса.

package ru.upread.javacourse;

public interface Car {
	void drive();
}
Теперь мы определили интерфейс под названием Car, который содержит объявление для метода drive. Обратите внимание, что по умолчанию все методы в интерфейсе являются “публичными абстрактными”, поэтому нам не нужно включать эти модификаторы в наши методы, и не следует этого делать, потому что это просто загромождает код. Абстрактный метод требует, чтобы любой класс, реализующий этот интерфейс, обеспечивал конкретную реализацию абстрактного метода. Аналогично, все переменные уровня класса, объявленные в интерфейсе, имеют модификаторы по умолчанию “public static final”. Как правило, хотя вы можете, вы не хотите включать константы в интерфейс. Если вы создаете константу под названием “MAX_SPEED” на уровне интерфейса, вы добавляете конкретные значения к интерфейсу. Цель интерфейсов - быть "легкими", без каких-либо реализаций. Подобно контракту или чертежу, интерфейсы определяют "что’, но не" как’. Эти детали реализации должны быть помещены в класс или даже лучше в перечисление.

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

Давайте модифицируем наш класс BMW так, чтобы он “реализовывал” интерфейс автомобиля. Это определяет BMW как тип автомобиля, и он будет придерживаться контракта или роли, указанной автомобилем. В любом классе, реализующем интерфейс, необходимо переопределить все абстрактные методы интерфейса. В этом случае BMW должен переопределить метод привода. Мы также собираемся реализовать заготовки древесины, активов, и имущественных интерфейсы. Чтобы реализовать несколько интерфейсов, разделите каждое имя интерфейса запятой.

public class BMW implements Car, Loggable, Asset, Property {

	public void drive() {
		System.out.println("BMW driving...");
	}

	public int value() {
		return 80000;
	}

	public String owner() {
		return "Marcus";
	}

	public String message() {
		return "I am the car of Yurii";
	}
}
Для каждого из интерфейсов, которые я реализовал, мне пришлось переопределить метод, как я сделал выше. Теперь мы можем вернуться к нашему классу обслуживания автомобилей. Предположим, что мы внедрили автомобиль для BMW, Mercedes и Porsche, мы можем очистить наш код. Первое, что мы можем сделать, это создать экземпляр всех наших типов автомобилей как Car:

Car bmw = new BMW();
Car porsche = new Porsche();
Car mercedes = new Mercedes();
Объекты по-прежнему все свои специфические типы, однако мы ссылаемся с интерфейсом к объекту. Таким образом, наша ссылочная переменная позволит нам использовать только методы, предоставляемые данным интерфейсом, и теперь объект играет определенную “роль” в данном контексте. Мы также реализуем другие интерфейсы Loggable, Asset и Property, которые позволят нам использовать только различные наборы методов. Эти "линзы", в качестве которых может выступать наша референтная переменная, позволяют объекту BMW выполнять различные роли в различных контекстах.

Теперь мы можем использовать "автомобиль” для всех трех автомобилей, и это сделает наш код гораздо более гибким. Даже если мы добавим новые типы автомобилей, которые реализуют интерфейс автомобиля в более позднее время, мы все еще можем иметь дело с ними, даже не зная, что они будут существовать, когда мы писали CarService. Кроме того, поскольку все наши автомобили фактически реализуют интерфейс Car, мы можем еще больше очистить наш код, используя a для каждого цикла. Мы также можем теперь получить все наши автомобили из базы данных, потому что независимо от типа автомобиля, все они могут быть сохранены в одном массиве.

public class CarService {
	public void drive() {
     [...] //динамическое извлечение автомобилей из базы данных

        for (Car car : cars) {
              car.drive();
          }
     }
}
Теперь у нашего CarService больше нет никаких конкретных реализаций. Это называется “развязка”. Класс CarService использует и знает только интерфейс автомобиля, а не какие-либо конкретные типы автомобилей.

Плюсы и минусы интерфейса

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

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

С другой стороны, интерфейс играет важную роль в том, чтобы развязать Java-код. Объявление ссылочной переменной типа interface позволяет заменять различные типы автомобилей во время выполнения. Например наш класс CarService может справиться с любой БМВ или Мерседес, основанные на различных сценариях.

На практике большие команды могут использовать эту функцию очень эффективно. Интерфейс определяет контракт, и различные подгруппы могут работать над различными классами независимо, придерживаясь одних и тех же основных рекомендаций, предоставляемых интерфейсом. Повторяю, вы не должны использовать интерфейс только ради того, чтобы иметь его, но когда вы используете его правильно, это один из самых мощных инструментов, которые может предложить Java.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегистатьи IT, уроки по java, java, интерфейс




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Мотивирующая книга о побеге и не только
Русификация и регистрация на форуме MyBB
Разумная анонимность в сети