Классы с будущей совместимостью, которая не сломает будущие модификации - PullRequest
14 голосов
/ 10 марта 2019

Я читал исходный код для Android RecyclerView, и я использовал SimpleOnItemTouchListener и читал документацию по этому классу.Но я не уверен, что понимаю смысл этого:

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

Это потому, что SimpleOnItemTouchListener реализует OnItemTouchListener и обеспечивает поведение по умолчанию?Таким образом, если OnItemTouchListener будет обновлено, SimpleOnItemTouchListener все равно вернет поведение по умолчанию.

Часть о "если интерфейс может измениться".Они говорят о OnItemTouchListener?

Однако, SimpleOnItemTouchListener, кажется, просто имеет пустые методы и ничего больше.

Ответы [ 4 ]

13 голосов
/ 15 марта 2019

Допустим, у вас есть этот интерфейс:

public interface OnItemTouchListener {
    boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
    void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
    void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
}

И вы решаете реализовать это самостоятельно:

public class MyOwnOnItemTouchListener implements OnItemTouchListener {

    @Override
    boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
        boolean result = doSomething(e);
        return result;
    }

    @Override
    void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
        doSomethingElse(rv, e);
        doSomethingMore(rv);
    }

    @Override
    void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        if (disallowIntercept) {
            doADifferentThing();
        }
    }
}

Все хорошо ...
... пока, через шесть месяцев, OnItemTouchListener не будет изменен, чтобы ввести новый метод:

public interface OnItemTouchListener {
    boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
    void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
    void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
    // New method
    void onMultiTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
}

И вдруг ваше приложение больше не будет компилироваться ?

Error: MyOwnOnItemTouchListener is not abstract and does not override abstract method onMultiTouchEvent() in OnItemTouchListener

И это даже не ваша ошибка, вы ничего не изменили! Просто изменился интерфейс и ваш код не обновился с этим изменением.


Чтобы избежать этого , разработчики API предлагают вам класс реализации "по умолчанию" , SimpleOnItemTouchListener, то есть , гарантированно всегда обновленный с интерфейсом , и что вы можете расширить вместо:

public class SimpleOnItemTouchListener implements OnItemTouchListener {
    // empty, override in your class 
    boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { return false; }
    // empty, override in your class 
    void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {}
    // empty, override in your class 
    void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
}

Таким образом, вместо непосредственной реализации интерфейса, вы можете сделать это:

public class MyOwnOnItemTouchListener extends SimpleOnItemTouchListener { //extend Simple instead of implementing interface

    @Override
    boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
        boolean result = doSomething(e);
        return result;
    }

    @Override
    void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
        doSomethingElse(rv, e);
        doSomethingMore(rv);
    }

    @Override
    void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        if (disallowIntercept) {
            doADifferentThing();
        }
    }
}

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

public interface OnItemTouchListener {
    boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
    void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
    void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
    // New method
    void onMultiTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
}
public class SimpleOnItemTouchListener implements OnItemTouchListener {
    // empty, override in your class 
    boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { return false; }
    // empty, override in your class 
    void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {}
    // empty, override in your class 
    void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
    // New method
    // empty, override in your class 
    void onMultiTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {}
}

И теперь, несмотря на эти изменения, MyOwnOnItemTouchListener все равно скомпилирует , даже если он не реализует onMultiTouchEvent, потому что если в любой момент вызывается MyOwnOnItemTouchListener.onMultiTouchEvent(), он просто использует ( пустой) реализация от своего родителя, SimpleOnItemTouchListener.

И Ваше приложение будет продолжать работать ?


Теперь, отвечая на ваши точные вопросы:

Это потому, что SimpleOnItemTouchListener реализует OnItemTouchListener и обеспечивает некоторое поведение по умолчанию?

Да. Хотя здесь «поведением по умолчанию» является «вообще ничего не делать», поэтому вам все равно нужно реализовать методы в своем собственном слушателе, если вы действительно хотите что-то сделать.

Так что, если OnItemTouchListener будет обновлено, SimpleOnItemTouchListener все равно вернет поведение по умолчанию.

Да, именно так.

Часть о "если интерфейс может измениться". Они говорят о OnItemTouchListener?

Да.

Однако, SimpleOnItemTouchListener, похоже, имеет пустые методы и ничего больше.

Да. «Поведение по умолчанию», которое они предоставляют, просто «ничего не делать» Это просто способ избежать сбоев компиляции.
Вы все еще должны реализовать методы осмысленно. Но теперь у вас есть сеть безопасности, если когда-нибудь будут внедрены новые методы.

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

6 голосов
/ 10 марта 2019

Это потому, что SimpleOnItemTouchListener реализует OnItemTouchListener и обеспечивает некоторое поведение по умолчанию?

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

Часть, если интерфейс может измениться. Они говорят о OnItemOnTouchListener?

да, они говорят об изменении интерфейса RecyclerView.OnItemTouchListener:

http://androidxref.com/9.0.0_r3/xref/frameworks/support/v7/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java#OnItemTouchListener

предположим, что они добавляют в RecyclerView.OnItemTouchListener новый метод: void foo(), затем, если вы обновите библиотеку поддержки и вы непосредственно внедрили в свой класс RecyclerView.OnItemTouchListener, вы получите ошибку компилятора (вам нужно будет реализовать foo() в вашем классе). В комментарии , который вы цитируете, команда андроидов обещает, что они будут реализовывать foo () в SimpleOnItemTouchListener , так что если вы расширите его в своем MyOnItemTouchListener, у них уже будет пустая реализация - так нет ошибки компиляции.

5 голосов
/ 18 марта 2019

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

Базовое приложение использует любую версию интерфейса, необходимую для этой части кода. Версия интерфейса V2 будет расширять V1, V3 расширяет V2 и т. Д. Вместо непосредственного вызова всех плагинов у меня есть класс менеджера, который выполняет эту работу. Это позволяет мне гарантировать, что если функция V3 пытается выполнить, я делаю это только на плагинах, которые реализовали версию плагина интерфейса V3.

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

5 голосов
/ 15 марта 2019

Я нахожу это более или менее Адаптер реализация.Поскольку android постоянно развивается, взаимодействия никогда не будут прежними и будут развиваться вместе с ОС.

Здесь можно реализовать корневой интерфейс OnItemTouchListener, чтобы приложение получало контроль над событиями касания, которые были израсходованы или израсходованы.Проще говоря, OnItemTouchListener говорит: " Вы хотите обрабатывать сенсорные события? Реализуйте меня! Но будьте готовы обрабатывать все виды новых жестов, которые я ловлю для вас. Я динамичен "

Теперь другой парень SimpleOnItemTouchListener встает между ними и говорит: "Эй, я могу быть вашим консультантом с OnItemTouchListener. Мы можем договориться о том, что нужно делать. Даже если OnItemTouchListener сходит с ума от новых вещей, я помогу вам сохранять спокойствие и не меняться. Я приму на себя боль и позабочусь, чтобы вас не беспокоили "

Так что все просто, OnItemTouchListener может развиться ввремя с Android.SimpleOnItemTouchListener может эволюционировать с OnItemTouchListener, но не устареет и не станет рудиментарным в любом из текущих поведений.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...