设计模式:观察者模式(基于 Java)

设计模式:观察者模式(基于 Java)

先给定义:定义了对象之间一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
这是《Head First 设计模式》一书中给出的定义,看起来有点玄乎,云里雾里的,但是简单说来,就是一个 listener(监听),它的用处在于:

主要用于控件的事件的监听和异步处理时的回调。

下面是平时编程中常用的示例。

1. 按钮点击事件的监听

观察者模式用的最多的情况,就是给控件设置各种事件监听了,这里以 Button 控件为例,通过 setOnClickListener() 方法添加观察者对象,当点击按钮时,按钮内部就会回调我们传入的观察者对象中的方法,这里调用的是 onClick() 方法,如下所示:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //获取按钮对象
        Button btnStart = (Button) findViewById(R.id.btn_start);
        //传入观察者对象,监听按钮点击事件
        btnStart.setOnClickListener(new ClickListener());
    }

    /*
     * 声明一个观察者类
     */
    class ClickListener implements View.OnClickListener{        
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this, "按钮事件监听", Toast.LENGTH_SHORT).show();
        }
    }

测试结果:

按钮事件监听

这样,一个简单的观察者模式就实现了,当然,里面大部分用的是系统的实现代码,我们只是使用者。
下面,我们自己写一个网络异步请求观察者模式。

2. 网络异步请求的监听

现如今的编程,网络通讯已经是必不可少的一部分了,当网络请求在线程中运行时,我们必须在主线程中知道当前网络请求的状态与结果,以便给予用户反馈,这个时候,就要用到我们的观察者了。

  • 创建观察者:网络请求监听类

这是自定义的观察者,这里为了偷懒,是以类的形式实现的,这种方法不是很好,一般是采用接口的方式实现。

    /**
     * 网络请求监听类
     */
    public class HttpRequestListener {

        //日志输出标签
        public static final String TAG = "HttpRequestListener";

        //请求成功监听
        //参数类型与个数可以根据需要自己定义
        public void requestCompleted(String response){
            Log.d(TAG,response);
        }

        //请求失败监听
        //参数类型与个数可以根据需要自己定义
        public void requestFailed(Exception e){
            Log.d(TAG,e.getMessage());
        }
    }
  • 创建被观察者:网络请求类

网络请求类,作为被观察者,采用GET方式,分为异步与同步,但是同步请求方法不能在主线程中直接调用。

    /**
     * 网络请求类
     */
    public class HttpUtils {

        //异步监听,使用GET方式
        public void requestGetAsyn(final String url, final HttpRequestListener listener){
            //启动线程
            new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        String response = "";
                        try {
                            //开始网络请求
                            response = requestGet(url);
                            if(listener!=null){
                                //回调观察者对象的方法,请求成功
                                listener.requestCompleted(response);
                            }
                        } catch (IOException e) {
                            if(listener!=null){
                                //回调观察者对象的方法,请求失败
                                listener.requestFailed(e);
                            }
                        }
                    }
                }
            ).start();
        }

        //网络请求,GET方式
        public String requestGet(String url) throws IOException {
            StringBuilder response = new StringBuilder();
            InputStream inputStream;
            BufferedReader reader = null;
            try {
                HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.setReadTimeout(5000);
                urlConnection.setConnectTimeout(5000);
                if(urlConnection.getResponseCode()==200){
                    inputStream = urlConnection.getInputStream();
                    reader = new BufferedReader(new InputStreamReader(inputStream));
                    String line;
                    while ((line = reader.readLine())!=null){
                        response.append(line);
                    }
                }
            } catch (IOException e) {
                throw e;
            }
            finally {
                if (reader != null) {
                    //关闭网络流
                    reader.close();
                }
            }
            return response.toString();
        }
    }
  • 关联观察者与被观察者

创建完观察者与被观察者,接下来就是两者的关联,说专业点就是两者之间建立依赖关系;建立方式其实已经在被观察者中确定了,就是在 requestGetAsyn() 方法中传入观察者对象,当然,这只是其中一种方法,我还想到(看到)一种方法,就是在被观察者中专门声明方法和变量用于建立与解除依赖关系,在本例中,就是在 HttpUtils 类中声明,如下所示:

    //观察者列表
    protected List<HttpRequestListener> listeners = new ArrayList<>();

    //建立依赖关系,添加观察者
    public void addListener(HttpRequestListener listener){
        this.listeners.add(listener);
    }

    //解除依赖关系,删除观察者
    public void removeListener(HttpRequestListener listener){
        this.listeners.remove(listener);
    }

如此调用:

    httpUtils.addListener(new HttpRequestListener());

如此回调即可:

    for (HttpRequestListener requestListener : listeners){
        requestListener.requestCompleted(response);
    }
  • 测试
HttpUtils httpUtils = new HttpUtils();
//添加观察者,可以多次调用,添加多个观察者
httpUtils.addListener(new HttpRequestListener());
//调用异步请求,并传入观察者对象
httpUtils.requestGetAsyn("http://blog.csdn.net/xwdoor",new HttpRequestListener());

测试结果

对了,不要忘了添加网络访问权限,不然报错

<uses-permission android:name="android.permission.INTERNET"/>

3. 书中的代码示例

《Head First 设计模式》这本书中也有几个观察者的例子,如果有兴趣,可以去看看,这里就不再敲出来了,主要是太懒了

4. 总结

作为程序员,写出这篇文章,用了好几个小时,用到的所有代码都是现场用 Android Studio 敲出来,运行了一遍的,所以导致效率有点低,写代码、调试、写文章、调格式,很繁琐的事儿,还好坚持了下来,写完这篇文章,又把观察者模式温习了一遍,感觉挺好的,逐渐感觉到了分享、整理的成就,哈哈。
第一次使用 MarkDown 写文章,写这篇文章也算熟悉了基本语法,有点小激动,小兴奋。
随着写的文章的增多,相信速度会有所提高;最近学习 Android,看视频,敲代码,熟悉之后才会整理分享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值