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

来源:互联网 发布:淘宝里一键修复有用吗 编辑:程序博客网 时间:2024/04/29 12:42

设计模式:观察者模式(基于 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,看视频,敲代码,熟悉之后才会整理分享。

0 0
原创粉丝点击