JavaRush /Java блог /Random /Что такое программирование на интерфейсах? Поиграем в арх...
Сергеев Виктор
40 уровень

Что такое программирование на интерфейсах? Поиграем в архитектора

Статья из группы Random
Может быть, когда-то ты слышал, есть такая штука как "программирование на интерфейсах". Пора познакомиться с этим поближе. Тут будет мало текста и много кода (без логики). Я не смог найти, когда появились первые интерфейсы. Наверно это было очень давно, и интернет об этом забыл. Ну да ладно. Идея интерфейса простая: описать, что мы будем делать без подробностей. Т.е. неважно, как вы это сделаете, важно, что вы сделаете. Зато после того, как я написал эту статью, я нашел хорошую, на похожую тему, тут в группах. Жмакай по ссылке и читай, чем больше, тем лучше! Содержимое:

Зачем это нужно?

Когда код состоит из одного класса, это нафиг не нужно. Но когда классы должны взаимодействовать между собой, а их количество — переваливать за несколько десятков, тут впору задуматься о проектировании. Сначала продумать всю структуру проекта сверху вниз (от максимальной абстракции к реализации). Если над проектом работает несколько человек, то очень удобно договориться, описать интерфейсы взаимодействия классов, потом разобрать эти интерфейсы и начать реализовывать. Получается хорошая параллельность задач, их легко делить, т.к. все обо всем договорились, а подробности никого не волнуют.

Что это дает разработчику?

Разработчику не нужна реализация класса. Это значит, что после того как все договорились, он берет нужные ему интерфейсы и пользуется ими. Реализация будет подставлена, когда будет готова. Давай я покажу свой пример, и потом поговорим дальше. Я решил написать небольшой проект кассы. Она будет помогать выбирать билеты, продавать их, сдавать деньги в банк и брать из банка, менять деньги для понаехавших. Итак, мой архитектурный выдох: P.S. не надо копировать и создавать структуру, для лиги лени я приложил архивчик с кодом в конце статьи ;) Структура:
Что такое программирование на интерфейсах? Поиграем в архитектора - 1
Куча моделек:

package cashbox.model;

public enum Currency {
    USD,
    EUR,
    RUR
}

package cashbox.model;

public interface Direction {
    /**
     * @return город как цель направления, куда едем/летим/двигаемся
     */
    String getCity();
}

package cashbox.model;

/**
 * модель денег
 */
public interface Money {
    /**
     * @return тип валюты
     */
    Currency getCurrency();

    /**
     * @return сумма денег
     */
    long getAmount();
}

package cashbox.model;

public interface Ticket {
    /**
     * @return направление куда двигаемся
     */
    Direction getDirection();

    /**
     * @return цена билета
     */
    Money getPrice();

    /**
     * @return транспорт на котором передвигаемся
     */
    Transport getTransport();
}

package cashbox.model;

public interface Transport {
}

Пара exception:

package cashbox.exception;

public class NoSoMuchMoneyException extends RuntimeException {
}

package cashbox.exception;

import cashbox.model.Money;

public class NoSuchCurrencyException extends RuntimeException {
    private Money money;

    public NoSuchCurrencyException(Money money) {
        this.money = money;
    }

    public NoSuchCurrencyException(String message, Money money) {
        super(message);
        this.money = money;
    }

    public Money getMoney() {
        return money;
    }
}

Касса — самая важная часть:

package cashbox;

import cashbox.exception.NoSoMuchMoneyException;
import cashbox.exception.NoSuchCurrencyException;
import cashbox.model.*;
import javafx.util.Pair;

import java.util.List;
import java.util.Map;

public interface CashBox {

    /**
     * @param direction направление билета
     * @return Стоимость проезда по видам транспорта
     */
    Map<Transport, Money> getPrice(Direction direction);

    /**
     * Продать билет
     * @param money деньги за билет
     * @return пару из билета и сдачи
     */
    Pair<Ticket, Money> sellTicket(Money money);

    /**
     * обмен валюты
     * @param moneyFrom валюта, которую передает клиент
     * @param currency валюта, которую клиент хочет получить, тут будет учитываться только тип валюты,
     *                 количество будет проигнорировано
     * @return Требуемая валюта
     * @throws NoSoMuchMoneyException если недостаточно денег в кассе для обмена
     * @throws NoSuchCurrencyException если нет такой валюты, отсутствующая валюта передается как атрибут
     */
    Money change(Money moneyFrom, Currency currency) throws NoSoMuchMoneyException, NoSuchCurrencyException;

    /**
     * Инкасация - отправить деньги в банк
     * @param money - сумма и валюта, можно передать несколько
     */
    void sendToBank(Money... money);

    /**
     * Запрос денег из банка
     * @param money - сумма и валюта необходимая кассе
     */
    void requestFromBank(Money... money);

    /**
     * Подбор билета.
     * В метод передается либо одно, либо другое, либо вместе.
     * Если оба атрибута null значит вызов некорректный
     * @param transport - желаемый транспорт
     * @param direction - желаемое направление
     * @return список подходящих билетов
     */
    List<Ticket> chooseBy(Transport transport, Direction direction);
}
Первое, что бросается в глаза не подготовленному разработчику, это javadoc. Хотя, наверно, неподготовленному разработчику как раз они привычны. Это некоторые иногда лентяйничают, мой же код и так хорош, без доки ;) Мне даже сейчас на некоторые вещи не хочется писать доку. Ну зачем писать транспорту, что это транспорт? Оставим это на потом! Я постарался доками описать все, что надо. Теперь объясню, почему так писать код удобнее. Смотри, я сейчас могу дать тебе интерфейс CashBox и попросить его реализовать. Он же не трудный? Плюс требуемое поведение описано в документации. Тебе не надо будет ждать, пока кто-то напишет модели или ещё что-то. Ты берешь модели интерфейсов и начинаешь работать на их основе. Теперь ты программируешь на интерфейсах, поздравляю. А теперь главное. Я могу дать тебе задачу реализовать CashBox, а так же ещё кому-то, чтобы у нас было 2 реализации. Например, пригородная и международная касса. Вы сможете писать код параллельно и любой член команды, который будет писать код на основе CashBox, может уже начинать и опираться на интерфейс. Это очень удобно. Многозадачность, чтоб её. Ссылка на код на гугл диске -> тут
Комментарии (5)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
vinsler Уровень 35 Expert
26 апреля 2019
Наверное это 1 и 2 пункт программирования, когда строится внешнее и внутреннее программирование, даже не знаю где можно сейчас найти эту инфу. А теперь это стали называть интерфейсами. А модульность теперь перекачевала в модное слово и направление микросервисы. Я бы отметил наверное по-другому. Когда идет программирование через интерфейсы, есть время на подумать и переделать/доделать, как и в микросервисах. Любую часть можно доработать, а при фундаментальной плите, там придется лопатить все разом. Помимо этого наверное было бы интересно добавить про лямбды/стримы и функциональные интерфейсы, с 1 методом они как раз кстати. ))) А в целом, я бы привел примеры, вот у нас этот код, с интерфейсами, а вот без интерефейсов, что удобнее читается, куда удобнее и проще добавить изменения, что быстрее и понятнее итд итп. Для начала все гуд. ) +1
Сергеев Виктор Уровень 40 Master
26 апреля 2019
Мда... главное то упустил. Зачем тебе интерфейсы, если ыты все пишешь один? Коротко: ты можешь писать один сервис и планировать что будет делать второй. Описывать планы в интерфейсе и пользоватся им. Реализуешь потом. А то бывает так: хм.. хочу написать почтовый сервис. Мы будем получать письма, блин надо проработать модель письма .... написал модель письма. Так теперь письмо надо хранить в ящике, хм надо написать ящик... Ок написал, ящик хранит письмо. Блин, а если бандероль... С интерфейсами: хм.. хочу написать почтовый сервис. Мы будем получать письма, ок убдет у нас что-то типо

public interface Parcel
Нам надо их где-то хранить пусть будет

public interface Box
и все, релизация будет потом. Не надо писать логику методов, можно просто их объявить. Реализуешь когда дойдет время )