天天看点

浅学设计模式之观察者<Observer>模式及在android中的应用

转自http://www.eoeandroid.com/home.php?mod=space&uid=871316&do=blog&id=48239

最近在学习下设计模式,而加深学习的不错的方法就是把心得写出来吧。记录下自己的理解。现在自己看的书是《head.frist设计模式》这本书。比较不错,想学习设计模式的朋友可以看下这本书。

        观察者<observer>模式(有时又被称为发布-订阅<publish/subscribe>模式、模型-视图<model/view>模式、源-收听者<source/listener>模式或从属者<dependents>模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。(源自百度百科)

           (五月三十一号修正内容)

        看下结构图:

浅学设计模式之观察者<Observer>模式及在android中的应用

     开始一个小例子

observer接口:

[java]

view plaincopy

public interface isubscribe {  

    void getnewpaper();  

}  

实现observer接口的观察者:

个人订阅者:

public class personalsubscriber implements isubscribe {  

    private string strname;  

    public void setnewspapername(string strname){  

        this.strname = strname;  

    }  

    public string getnewspapername(){  

        return strname;  

    @override  

    public void getnewpaper() {  

        // todo auto-generated method stub  

        system.out.println("我是个人用户,我得到了我的报纸:"+getnewspapername());  

企业订阅者:

public class enterprisesubscriber implements isubscribe {  

        system.out.println("我是企业用户,我得到了我的报纸:"+getnewspapername());  

被观察者:subject

public abstract class publish {   

    public list<isubscribe> list;  

    public publish(){  

        list = new arraylist();  

    public void registered(isubscribe isubscribe){  

        list.add(isubscribe);  

    public void unregistered(isubscribe isubscribe){  

        list.remove(isubscribe);  

    public abstract void sendnewspaper();  

这里使用的是抽象类

下面是实现:

public class postoffice extends publish{  

    public void sendnewspaper() {  

        iterator iterator = list.iterator();  

        while(iterator.hasnext()){  

            ((isubscribe) iterator.next()).getnewpaper();  

        }  

测试:

public static void main(string[] args) {  

        postoffice postoffice = new postoffice();  

        //得到个人用户  

        personalsubscriber person = new personalsubscriber();  

        person.setnewspapername("《南方周末》");  

        //得到企业用户  

        enterprisesubscriber enterprise = new enterprisesubscriber();  

        enterprise.setnewspapername("《企业报》");  

        //注册观察者  

        postoffice.registered(person);  

        postoffice.registered(enterprise);  

        //发放报纸  

        postoffice.sendnewspaper();  

测试结果:

我是个人用户,我得到了我的报纸:《南方周末》  

我是企业用户,我得到了我的报纸:《企业报》  

下面是有些错误五月18号版本:后面有错误解析!

        举个例子,张三从邮局订阅了《南方周末》,李四从邮局订阅了《新京报》,王五从邮局里面订阅了《南方都市报》。当报纸抵达邮局的时候,邮局就会把报纸送递订阅者。而不需要订阅者天天到邮局询问报纸是否到达邮局。

       下面开始代码:首先应该是个订阅者接口:

package cn.demo;  

    //从邮局订阅报纸  

    public void registered(postoffice postoffice);  

    //从邮局退订报纸  

    public void unregistered(postoffice postoffice);  

    //获取报纸名称  

    public void getnewspaper();  

第三个方法非必须,前两个方法必须要有。(应修改为前两个非必须,第三个方法必须有)

然后有三个订阅者类:

张三:

public class zhangsan implements isubscribe{  

    private string mname;  

    private string mnewspapername;  

    public zhangsan(string mname, string mnewspapername) {  

        this.mname = mname;  

        this.mnewspapername = mnewspapername;  

    public string getname() {  

        return mname;  

    public string getnewspapername() {  

        return mnewspapername;  

    public void registered(postoffice postoffice){  

        postoffice.registerednewspaper(this);  

    public void unregistered(postoffice postoffice){  

        postoffice.unregisterednewspaper(this);  

    public void getnewspaper() {  

        system.out.println("我是"+getname()+",我收到我订阅的"+getnewspapername());  

李四:

public class lisi implements isubscribe{  

    public lisi(string mname, string mnewspapername) {  

王五:

public class wangwu implements isubscribe{  

    public wangwu(string mname, string mnewspapername) {  

三个订阅者,都有方法订阅报纸,或者取消订阅。其实关于订阅者的信息,是存储在邮局类里面。

邮局类:(邮局类应该继承一个抽象类或者接口(subject),这里没有实现)

import java.util.arraylist;  

import java.util.list;  

public class postoffice {  

    private list<isubscribe> subscribelist = new arraylist<isubscribe>();  

    public void registerednewspaper(isubscribe subscribe) {  

        subscribelist.add(subscribe);  

    public void unregisterednewspaper(isubscribe subscribe) {  

        if (subscribe != null) {  

            subscribelist.remove(subscribe);  

    public void getnewspaper(boolean bool) {  

        if (bool) {  

            sendnewspaper();  

        for(isubscribe subscribe : subscribelist) {  

            subscribe.getnewspaper();  

在这个类里面,有变化通知是使用的sendnewspaper()这个方法,遍历所有的订阅者。

测试类:

        postoffice mpostoffice = new postoffice();  

        isubscribe zhangsan = new zhangsan("张三", "《南方周末》");  

        isubscribe lisi = new lisi("李四", "《新京报》");  

        isubscribe wangwu = new wangwu("王五", "《南方都市报》");  

        //开始订阅报纸  

        zhangsan.registered(mpostoffice);  

        lisi.registered(mpostoffice);  

        wangwu.registered(mpostoffice);  

        //邮局收到报纸,开始发放  

        mpostoffice.getnewspaper(true);  

        //李四退订  

        lisi.unregistered(mpostoffice);  

打印结果:

[html]

我是张三,我收到我订阅的《南方周末》  

我是李四,我收到我订阅的《新京报》  

我是王五,我收到我订阅的《南方都市报》  

这里只是提供了一个简单的例子,而且代码你会发现有冗余,三个订阅者类,几乎是一样,因为没有在类里面添加他们独自的属性,可以用一个person类来替代。这里写这三个类是为了显示清晰。

        关于五月18号的例子,观察者没必要有注册和取消注册的方法。他们的方法的实现也是调用的被观察者的注册和取消注册,不如直接使用被观察者的方法。

         在android中,button.setonclicklistener()这个方式是比较常见的观察者模式:当然,众所周知,onclick是著名的回调方法,在这里不会研究回调,不用太在意。

看下代码:

button button1 = (button)findviewbyid(r.id.button1);  

        button button2 = (button)findviewbyid(r.id.button2);  

        button button3 = (button)findviewbyid(r.id.button3);  

        button1.setonclicklistener(this);  

        button2.setonclicklistener(this);  

        button3.setonclicklistener(this);  

    public void onclick(view v) {  

        switch(v.getid()) {  

        case r.id.button1 :  

//          do some thing         

        case r.id.button2 :  

//          do some thing  

        case r.id.button3 :  

先button.setonclicklistener()进行注册。相当于邮局中的lisi.registered(mpostoffice),此处错误,应该是第一例中的postoffice.registered(person)。onclick响应事件相当于邮局中的

public void sendnewspaper() {  

这个中的subscribe.getnewspaper()这个方法。view.onclicklistener相当于邮局。view也就是button是我们的订阅者,也就相当于张三。我们也可以在getnewspaper中加一些自己的switch判断。

       最后,如果我们的邮局要实现类似button这样的回调这么实现呢?

isubscribe isubscribe;  

        isubscribe.getnewspaper();  

    } 

继续阅读