具有将来兼容性的类,不会破坏以后的修改

时间:2019-03-09 22:43:39

标签: java oop inheritance interface

我正在阅读Android RecyclerView的源代码,并且正在使用SimpleOnItemTouchListener并阅读有关此类的文档。但是我不确定我是否理解这个意思:

  

使用此类的另一个好处是将来的兼容性。由于界面可能会发生变化,我们将始终在此类上提供默认实现,以使您的代码在更新到支持库的新版本时不会中断

这是因为SimpleOnItemTouchListener实现了OnItemTouchListener并提供了一些默认行为吗?因此,如果OnItemTouchListener得到更新,SimpleOnItemTouchListener仍将返回默认行为。

有关“如果界面可能会更改”的部分。他们是在谈论OnItemTouchListener吗?

但是,SimpleOnItemTouchListener似乎只有空方法,而没有其他内容。

4 个答案:

答案 0 :(得分:13)

假设您具有此界面:

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

这甚至不是您的错,您没有进行任何更改!只是界面已更改,并且您的代码不是最新的。< / p>


为避免这种情况,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似乎只有空方法,而没有其他内容。

是的。他们提供的“默认行为”只是“什么都不做”。这只是避免编译失败的一种方法。
您仍然必须以有意义的方式实现这些方法。但是现在,如果引入了新方法,您将拥有一个安全网。

我想说的是您实际上了解它的要旨,只是空的默认实现令人困惑。

答案 1 :(得分:7)

  

这是因为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())。在comment you quote中,Android团队承诺他们将在SimpleOnItemTouchListener中实现foo(),因此,如果在MyOnItemTouchListener中对其进行扩展,它们将已经具有空的实现-因此不会发生编译错误。

答案 2 :(得分:5)

我发现它或多或少是Adapter的实现。随着android的不断发展,交互作用将永远不会相同,并且会随着OS的发展而不断发展。

在这里,可以实现根接口OnItemTouchListener,以便应用程序可以控制已消耗或正在消耗的触摸事件。用简单的话来说,OnItemTouchListener说:“ 您要处理触摸事件吗?实施我!但是请准备好处理我为您捕捉到的各种新手势。我很动态

现在另一个人SimpleOnItemTouchListener介于中间,并说,“嘿,我可以  您的顾问OnItemTouchListener。我们可以就要处理的内容达成协议。即使OnItemTouchListener为新事物着迷,我也会帮助您保持镇定,不要改变。我会忍受的,并确保您不会被打扰”

因此,OnItemTouchListener的简单用法可能会随着Android的发展而变化。 SimpleOnItemTouchListener可能会与OnItemTouchListener一起发展,但不会在任何当前行为中被淘汰或遗迹化。

添加更多内容,因为SimpleOnItemTouchListener为您提供了默认的实现,因此您的代码看起来很简洁,因为您只需要覆盖所需的内容即可。

答案 3 :(得分:5)

我目前正在为我正在处理的项目开发一个插件框架。我试图通过对界面进行版本控制来解决此问题。我确实有像walen所说的基本实现。但是,我担心实现接口而不是基本实现的人员。当然,如果我更改界面并发布,我只会破坏那些决定不扩展基类的插件。

核心应用程序使用该部分代码所需的任何版本的接口。 V2版本的接口将扩展V1,V3扩展V2,等等。我没有直接调用所有插件,而是有一个可以工作的manager类。这样一来,我可以确保如果尝试执行V3功能,则只能在实现了V3版本插件界面的插件上执行。

如果我只是公开基类并从公共API隐藏接口,那么我可能只需要其他人扩展的基础实现就可以实现。不幸的是,由于该接口也是公共的,因此我必须确保不破坏没有扩展基类的开发人员。