Ранее никогда не писал собственные интерфейсы для "упрощения жизни". Почему? Что в них такого интересного?
В комментариях попросили добавить в вопрос мои знания и область работы. Пишу android приложения и... Все. Об интерфейсах не знаю ничего, только то, что можно класс от интерфейса наследовать и переопределить методы. Но зачем? Смысл интерфейсов?
Лично для меня самым наглядным для понимания сущности интерфейсов являются коллекции и все, что с ними связанно. Скорее всего это так, потому что с ними приходилось чаще всего работать.
Дело в том, что я довольно ленивый и принципиально не люблю писать лишний код. Да и одна из главных особенностей ООП - избавление от дублирования логики, за счет правильной архитектурной составляющей. Для данного случая (в общем понимании) и были придуманы интерфейсы и абстрактные классы.
Допустим у меня есть сферический в вакууме метод, делающий какую-то работу с коллекцией:
/*Здесь может быть любой тип коллекции, который реализует соотв. интерфейс.
Причем я использую интерфейс самого "низкого" уровня, т.к.
он полностью покрывает данный функционал (т.е. проход по элементам в цикле)
Также я могу написать любую свою реализацию для этого интерфейса
*/
public void showCollectionAtConsole(Iterable<?> col){
col.forEach(object -> System.out.println(object));
}
Удобство здесь в том, что только в самой Java довольно много реализаций данного интерфейса, (подробнее) и я могу использовать данную логику для каждой из них.
Теперь у меня есть другой метод, реализующий какой-то функционал:
public boolean removeOrAddMyObject (Collection<MyObject> col, MyObject object){
//Если удалил объект - true, иначе - false
boolean isRemove = true;
if (col!=null){
if (col.isEmpty() || !col.remove(object)) {
col.add(object);
isRemove = false;
}
}else throw new IllegalStateException("Коллекция = null");
return isRemove;
}
Здесь мне приходится использовать три метода коллекции: isEmpty(), add(), remove(). Однако все эти методы описаны в интерфейсе Collection и нет нужды в качестве аргумента передавать более "высокий" интерфейс или класс с реализацией. Как я уже писал выше, данное решение позволит мне с чистой совестью переиспользовать неоднократно данный метод для других реализаций.
Также, как мне кажется, отличным примером использования интерфейсов являются Callback'и:
public final class MyClass {
static class MyObject {
int id;
String name;
public MyObject(int id, String name) {
this.id = id;
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name){
this.name = name;
}
@Override
public String toString(){
return "My Object: id = "+id+", name = "+name;
}
}
//Интерфейс коллбэка
interface MyCallback<T extends MyObject> {
void doSome(T myObject);
}
static void doSomeAwesome(MyObject object, MyCallback<MyObject> callback) {
System.out.println(object);
callback.doSome(object);
System.out.println(object);
}
public static void main(String[] args) {
MyObject myObject = new MyObject(1,"someName");
MyCallback<MyObject> callback = new MyCallback<MyObject>() {
@Override
public void doSome(MyObject myObject) {
myObject.setId(2);
myObject.setName("someOtherName");
}
};
doSomeAwesome(myObject,callback);
}
}
Суть сводится к тому, что в интерфейсе коллбэка вы явным образом определяете дженерик (если хотите передавать в метод параметры и/или получать из метода объекты) и описываете контракт. В моем случае это один метод, принимающий на вход аргумент. Теперь, я могу реализовать метод коллбэка на свое усмотрение, и таким образом расширить использование метода doSomeAwesome()
дополнительной логикой.
Если выполнить код на выходе будет:
My Object: id = 1, name = someName
My Object: id = 2, name = someOtherName
UPD: Также следует понимать, что есть и другие контексты для использования интерфейсов:
Интерфейс предоставляет контракт, который должны выполнять все классы, реализующие этот интерфейс, и является абстракцией, показывающей что объект может делать, но как он этот делает - не важно.
На практике это приводит к следующему:
При использовании интерфейсов появляется возможность заменять один класс, реализующий интерфейс, на другой класс, реализующий этот же интерфейс, без переписывания всего кода. Например, если методу передаётся Map
:
public void handle(Map map) { ... }
то не придётся менять описание метода, если потребуется использовать TreeMap
вместо HashMap
.
Аналогично если метод возвращает Map
: он может начать возвращать TreeMap
вместо HashMap
, и трагедии библейских масштабов при этом не случится, так как код, работающий с возвращенным этим методом значением, имеет дело с Map
.
Это увеличивает гибкость кода: проще переключаться с одного источника данных на другой и с одной реализации на другую.
Также это полезно при тестировании, так как позволяет использовать Mock-объекты вместо настоящих.
Если нужно одинаково обрабатывать коллекции элементов (например, ArrayList
и Set
, возвращаемый методом keySet()
у HashMap
), то достаточно описать метод так:
public <T> void handle(Collection<T> elements) { ... }
Использование generics-типа здесь для большей реалистичности. Без использования интерфейса пришлось создавать два метода:
public <T> void handle(ArrayList<T> elements) { ... }
public <T> void handle(Set<T> elements) { ... }
И либо дублировать код, либо, например, во втором методе создавать ArrayList
, добавлять в него все элементы из Set
и вызывать первый метод.
Также использование интерфейсов позволяет объединить разные объекты, реализующий один и тот же интерфейс, в один список и одинаково их обрабатывать:
public interface Animal
{
public void feed();
}
public class Dog implements Animal
{
public void feed() { ... }
}
public class Cat implements Animal
{
public void feed() { ... }
}
List<Animal> animals = new ArrayList<>();
animals.add(new Cat());
animals.add(new Dog());
for (Animal animal : animals)
{
animal.feed();
}
Без использования интерфейса пришлось бы городить "if-else" (или "switch-case") с отдельной реализацией логики для каждого типа животных.
Потому что интерфейс - это абстракция, которая говорит о том, что делать, а не как делать. "упрощение жизни" заключается в том, что интерфейс задает единообразное ожидаемое поведение, и где бы вы его не встретили (если конечно программист не наплевал на контракт интерфейса). Вообще, чтобы понять, что я тут написал, вам бы почитать книги по ООП.
Интерфейсы и в правду упрощают жизнь .Допустим в android для навигации gps Google api
использую интерфейс, для слушателя используют интерфейс (Интерфейсы используются почти везде даже в потоках )А начиная с Java-8 интерфейсы реализуют и тело, так что можно уже писать не только условие но и тело интерфейса .Но дело каждого использовать их или нет .Не всегда программист обязан реализовывать свои интерфейсы.Правила "написание хорошего кода" гласит:сперва составь интерфейсы абстракцию потом реализуй))
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Доброе утроПишу функцию календаря, где есть 2 аргумента месяц и год
Доброго времени сутокПишу программу для чтения и записи данных через NFC