揭开观察者设计模式的神秘面纱,手把手教你写监听器

我们在写代码的时候,遇到最常用的就是监听器了。那么实际中,我们也要进行事件的监听。而有些事件是业务逻辑需要实现的,跟随事物变化动态变化的。假如说我们要实现一个事件,有位置的监听,有颜色的监听,有坐标的监听,有速度的监听,那么这么多监听的事件。那么我们就需要这么多个监听器。这些监听器如何被管理呢。我们可以创造一个类似管理员身份的神秘角色,这个角色就是一个监听器池说一个监听器池,可以移除和增加监听器。当我们触发某一事件的时候,需要这些监听器全部执行监听。

现在我们来模拟一下按钮Button的实现。

新建一个点击事件的接口Clickable.java。只负责执行点击事件。

public interface Clickable {
    //点击事件
    void onClick();
}

新建一个按钮类MyButton并且实现点击事件接口Clickable,这样就要求我们实现onClick方法。

public class MyButton implements Clickable {
    @Override
    public void onClick() {
        //执行所有监听器里的方法,监听器1,监听器2 ...

    }
}

那么此时,监听器又干什么了呢?我们都知道监听器都是接口对象。就相当于一个管理员。点击事件的接口对象就相当于一个事件。而事件的具体内容就通过方法onClick()来体现。

那么既然管理员管理事件,我们先创建管理员(监听器接口),然后管理事物( onClick() )。

监听器接口如下:

public interface OnClickListener {
    void onClick(Clickable clickable);
}

与此同时,我们需要增加监听器,写一个设置监听器的方法。对这个接口进行回调。

</pre><pre name="code" class="java">  public void setOnClickListener(OnClickListener onClickListener){
        if(onClickListener!=null){
            onClickListener.onClick(this);
        }
    }

这样的话,当我们设置监听的时候,从外部引入的OnClickListener接口对象不为空,就会执行OnClickListener接口中的onClick()方法。

接下来,我们可以实现这个监听器接口用来作为得到OnClickListener接口对象的方式。这个地方可能比较难理解。我们应该知道,如果一个类实现了某个接口,通过实例化这个类对象而得到相应的接口对象。

下面我们来新建一个颜色监听器。如果颜色改变,这里我默认为true。实际上这里可以进行颜色的判断。当发生变化的时候,我们需要向外界暴露一个方法,供外界调用,所以我们在类里面再新建一个抽象方法。当外部匿名构造这个类对象的时候同时也会实现这个类的方法。

 public static abstract  class OnColorListener implements OnClickListener{

        @Override
        public void onClick(Clickable clickable) {
            if(true){
                colorChanged();
            }
        }
        public  abstract void colorChanged();
    }

接下来我们再新建一个位置监听器。同样和上面一样,代码如下:

 public static abstract  class OnCoordinateListener implements OnClickListener{

        @Override
        public void onClick(Clickable clickable) {
            if(true){
                coordinateChanged();
            }
        }
        public  abstract void coordinateChanged();
    }

再接下来我们需要一个焦点监听器。同上,

    public static abstract  class OnFocusListener implements OnClickListener{

        @Override
        public void onClick(Clickable clickable) {
            if(true){
                onFocusChanged();
            }
        }
        public  abstract void onFocusChanged();
    }

这三个类实现了OnClickListener接口,那么我们只要匿名构造这三个对象便可以得到OnClickListener接口对象。同时也实现了OnclickListener里面的接口方法。在这个方法里面,我们分别进行了相应监听目的的变化监听。当某某发生改变的时候,我们就向外界提供一个方法,供调用者去实现。所以把这个类改成了抽象类,同时提供了抽象方法。外界如何调用的呢。我们可以看到setOnClickListener方法

  public void setOnClickListener(OnClickListener onClickListener){
        if(onClickListener!=null){
            onClickListener.onClick(this);
        }
    }

我们看到这里,我们便知道,传进来的OnClicklistener接口对象可以由它具体的实现类的匿名对象得到,也可以由它自身的接口对象得到。所以传进来的参数可以是以下几种

  • OnClickListener
  • FocusListener
  • OnCoordinateListener
  • OnColorListener

这几种的匿名对象。其实质是OnClickListener对象。为什么也可以传后面三个呢?

OnClickListener onClickListener = new FocusListener();

同时也可以

OnClickListener onClickListener() = new OnCoordinateListener();

或者其他两种的匿名对象也是可以的。

好了到目前为止,咱们的完整的代码是这样的。

public class Button implements Clickable{
    String color;
    int x,y;
    public void setOnClickListener(OnClickListener onClickListener){
        if(onClickListener!=null){
            onClickListener.onClick(this);
        }
    }

    @Override
    public void click() {
        //执行所有监听器操作
    }

    public interface OnClickListener{
        public void onClick(Clickable clickable);
    }

    public static abstract  class OnColorListener implements OnClickListener{

        @Override
        public void onClick(Clickable clickable) {
            if(true){
                colorChanged();
            }
        }
        public  abstract void colorChanged();
    }
    public static abstract  class OnCoordinateListener implements OnClickListener{

        @Override
        public void onClick(Clickable clickable) {
            if(true){
                coordinateChanged();
            }
        }
        public  abstract void coordinateChanged();
    }
    public static abstract  class OnFocusListener implements OnClickListener{

        @Override
        public void onClick(Clickable clickable) {
            if(true){
                onFocusChanged();
            }
        }
        public  abstract void onFocusChanged();
    }
}

上面的代码我估计大家都能看懂。接下来,我们就要对这几个监听器的接口对象进行管理了,我们可以分开管理也可以统一管理,如何分开管理这些接口对象呢?我们可以新建三个监听器的List集合对象。同时增加它的add和remove方法。但是我们没必要这样干,为什么呢?上面我解释过,匿名构造得到的OnColorListener对象或者OnCoordinateListener亦或者是OnFocusListener接口对象也好,其实质都是OnClickListener接口对象。所以我们只需要一个集合管理这些监听器就可以了。

  private static List<OnClickListener> onClickListeners =new ArrayList<OnClickListener>();

    private void addClickListener(OnClickListener onClickListener){
        onClickListeners.add(onClickListener);
    }

    private void remove(OnClickListener onClickListener){
        onClickListeners.remove(onClickListener);
    }

这样我们就可以自由得管理这些监听器了,我们知道当我们setOnClickListener的时候,新建一个OnClickListener匿名对象的时候,我们需要把它加入到池中,也就是这个list集合中。代码如下:

  public void setOnClickListener(OnClickListener onClickListener){
        if(onClickListener!=null){
            onClickListener.onClick(this);
        }
        addClickListener(onClickListener);
    }

ok。说了这么多,再来看看我们的此时的完整代码。

package com.example.chenlei.myapplication.widget;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by chenlei on 2016/10/24.
 */

public  class Button implements Clickable{
    String color;
    int x,y;
    public void setOnClickListener(OnClickListener onClickListener){
        if(onClickListener!=null){
            onClickListener.onClick(this);
        }
        addClickListener(onClickListener);
    }

    @Override
    public void click() {
        //执行所有监听器操作
    }

    public  interface OnClickListener{
        public void onClick(Button button);
    }
    private static List<OnClickListener> onClickListeners =new ArrayList<OnClickListener>();

    private void addClickListener(OnClickListener onClickListener){
        onClickListeners.add(onClickListener);
    }

    private void remove(OnClickListener onClickListener){
        onClickListeners.remove(onClickListener);
    }

    public static abstract  class OnColorListener implements  OnClickListener{

        @Override
        public void onClick(Button button) {
            if(true){
                colorChanged();
            }
        }
        public  abstract void colorChanged();
    }
    public static abstract  class OnCoordinateListener implements OnClickListener{

        @Override
        public void onClick(Button button) {
            if(true){
                coordinateChanged();
            }
        }
        public  abstract void coordinateChanged();
    }
    public static abstract  class OnFocusListener implements OnClickListener{

        @Override
        public void onClick(Button button) {
            if(true){
                onFocusChanged();
            }
        }
        public  abstract void onFocusChanged();
    }
}

如果我们需要执行所有被监听对象工作的时候,我们该怎么做呢?

  @Override
    public void click() {
        //执行所有监听器操作
        for(OnClickListener onClickListener :onClickListeners){
            onClickListener.onClick(this);
        }
    }

我们只需要遍历一下集合中的监听器就可以了。好了,那么接下来咱们看看怎么使用吧!

public class MainActivity extends AppCompatActivity {
    private TextView tx;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tx = (TextView) findViewById(R.id.tx);
        Button button =new Button();
        button.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(Button button1) {
                Log.e("TAG","我是回调方法");
            }
        });
        Button button1 =new Button();
        button1.setOnClickListener(new Button.OnColorListener() {
            @Override
            public void colorChanged() {
                Log.e("TAG","颜色改变后需要干神马");
            }
        });
        Button button2 =new Button();
        button2.setOnClickListener(new Button.OnCoordinateListener() {
            @Override
            public void coordinateChanged() {
                Log.e("TAG","坐标改变后需要干神马");
            }
        });
        Button button3 =new Button();
        button3.setOnClickListener(new Button.OnFocusListener() {
            @Override
            public void onFocusChanged() {
                Log.e("TAG","焦点改变后需要干神马");
            }
        });
    }

}

打印出的Log结果如下图:

时间: 2024-10-13 22:13:10

揭开观察者设计模式的神秘面纱,手把手教你写监听器的相关文章

揭开webRTC媒体服务器的神秘面纱——WebRTC媒体服务器&amp;开源项目介绍

揭开webRTC媒体服务器的神秘面纱--WebRTC媒体服务器&开源项目介绍 WebRTC生态系统是非常庞大的.当我第一次尝试理解WebRTC时,网络资源之多让人难以置信.本文针对webRTC媒体服务器和相关的开源项目(如kurento,janus,jitsi.org等)做一些介绍.并且将尝试降低理解WebRTC的业务价值所需要的技术门槛. 何为WebRTC服务器? 自从WebRTC诞生之初以来,该技术的主要卖点之一是它可以进行点对点(browser-to-browser)通信,而几乎不需要服务

手把手教你写专利申请书/如何申请专利

http://blog.csdn.net/johnsuna/article/details/3492145 手把手教你写专利申请书·如何申请专利 摘要小前言(一)申请前的准备工作    1.申请前查询    2.其他方面的考虑    3.申请文件准备(二)填写专利申请系列文档    1.实际操作步骤    2.具体操作    3.经验分享.注意事项(三)关于费用(四)其他的话参考资源提示常见问题的问与答 摘要: 如何写好专利申请?由于很多专利申请人都是第一次申请,因此,可能有一种神秘和些许恐惧.

手把手教你写专利申请书/怎样申请专利

手把手教你写专利申请书·怎样申请专利 摘要小前言(一)申请前的准备工作    1.申请前查询    2.其它方面的考虑    3.申请文件准备(二)填写专利申请系列文档    1.实际操作步骤    2.详细操作    3.经验分享.注意事项(三)关于费用(四)其它的话參考资源提示常见问题的问与答 摘要: 怎样写好专利申请?由于非常多专利申请人都是第一次申请,因此,可能有一种神奇和些许恐惧.本文写的是怎样写专利申请书,手把手教你写专利申请并提供申请专利时的注意事项,专利申请费用及费用减缓等相关參

Android开发之手把手教你写ButterKnife框架(二)

欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52664112 本文出自:[余志强的博客] 上一篇博客Android开发之手把手教你写ButterKnife框架(一)我们讲了ButterKnife是什么.ButterKnife的作用和功能介绍以及ButterKnife的实现原理. 本篇博客主要讲在android studio中如何使用apt. 一.新建个项目, 然后创建一个module名叫processor 新建m

手把手教你写Sublime中的Snippet

手把手教你写Sublime中的Snippet Sublime Text号称最性感的编辑器, 并且越来越多人使用, 美观, 高效 关于如何使用Sublime text可以参考我的另一篇文章, 相信你会喜欢上的..Sublime Text 2使用心得 现在介绍一下Snippet, Snippets are smart templates that will insert text for you and adapt it to their context. Snippet 是插入到文本中的智能模板并

手把手教你写Windows 64位平台调试器

本文网页排版有些差,已上传了doc,可以下载阅读.本文中的所有代码已打包,下载地址在此. -------------------------------------------------------------------------------------------------------------------------------------------------------------- 手写一个调试器有助于我们理解hook.进程注入等底层黑客技术具体实现,在编写过程中需要涉及大

手把手教你写电商爬虫-第三课 实战尚妆网AJAX请求处理和内容提取

系列教材: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 看完两篇,相信大家已经从开始的小菜鸟晋升为中级菜鸟了,好了,那我们就继续我们的爬虫课程. 上一课呢一定是因为对手太强,导致我们并没有完整的完成尚妆网的爬虫. 吭吭~,我们这一课继续,争取彻底搞定尚妆网,不留任何遗憾. 我们先回顾一下,上一课主要遗留了两个问题,两个问题都和ajax有关. 1.由于是ajax加载下一页,导致下一页url并不会被系统自动发现. 2.商品页面的价格是通过a

手把手教你写电商爬虫-第四课 淘宝网商品爬虫自动JS渲染

系列教程: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 手把手教你写电商爬虫-第三课 实战尚妆网AJAX请求处理和内容提取 老规矩,爬之前首先感谢淘宝公布出这么多有价值的数据,才让我们这些爬虫们有东西可以搜集啊,不过淘宝就不用我来安利了 广大剁手党相信睡觉的时候都能把网址打出来吧. 工欲善其事,必先利其器,先上工具: 1.神箭手云爬虫,2.Chrome浏览器 3.Chrome的插件XpathHelper 不知道是干嘛的同学请移步第一课

手把手教你写电商爬虫-第五课 京东商品评论爬虫 一起来对付反爬虫

系列教程: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 手把手教你写电商爬虫-第三课 实战尚妆网AJAX请求处理和内容提取 手把手教你写电商爬虫-第四课 淘宝网商品爬虫自动JS渲染 四节课过去了,咱们在爬虫界也都算见过世面的人,现在再来一些什么ajax加载之类的小鱼小虾应该不在话下了,即使是淘宝这种大量的ajax,我们 祭上我们的核武器,也轻松应对了,这一课主要是来看看除了技术上的页面处理外,我们还会遇上更棘手的问题,就是反爬虫,当然现