设计模式-观察者模式

前言

先简要说说观察者模式的定义与组成吧。

观察者模式定于与组成

通俗来讲,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象在状态上发生变化时,通知所有观察者对象,让它们可以主动的更新自己。观察者模式主要分为四部分:抽象主题角色;抽象观察者角色;具体主题角色;具体观察者角色。
接下来看看我自定义的观察者模式吧。


自定义观察者模式

  • 先说说需求吧:
通过观察者模式来实现一个简单的消息订阅。
  • 接下来说说具体的设计抽象:
想想观察者的主要部分,大致可以抽象出这样几个类:Subject(主题),Observer(观察者),ConcreateSubject(具体的主题角色),ConcreteObserver(具体的观察者角色)
抽象出这几个类后,可以画出如下的类图:

  • 具体的代码实现:
抽象角色:
Subject:
public interface Subject {
 
    /**
     * 消息订阅
     * @param observer
     */
    public void subscribe(Observer observer);
 
    /**
     * 广播消息
     */
    public void publish();
 
    /**
     * 退订某个服务
     * @param observer
     */
    public void unSubscribe(Observer observer);
 
    /**
     * 退订全部服务
     */
    public void unSubscribeAllServers();
 
}
AbstractSubject:
public abstract class AbstractSubject implements Subject {
     
    //观察者List
    private List<Observer> observers;
 
    public AbstractSubject() {
        this.observers = Lists.newArrayList();
    }
 
    public void subscribe(Observer observer) {
        if (null == observer) {
            return;
        }
        observers.add(observer);
    }
 
    public void publish() {
        for (Observer observer : observers) {
            observer.update(this);
        }
    }
 
    public void unSubscribe(Observer observer) {
        System.out.println("unsubscribe...\n");
        observers.remove(observer);
    }
 
    public void unSubscribeAllServers() {
        observers.clear();
    }
}
Observer:
public interface Observer {
 
    public void update(Subject subject);
}
具体角色:
ConcreateSubject:
public class ConcreateSubject extends AbstractSubject {
 
    //消息状态
    private int status;
 
    //消息主题
    private String subject;
 
    public ConcreateSubject(String subject) {
        super();
        status = Status.NOT_SEND.getStatus();
        this.subject = subject;
    }
 
    //消息状态变更
    public void changed(int newStatus) {
        this.status = newStatus;
        publish();
    }
 
    public String getSubject() {
        return subject;
    }
 
    public int getStatus() {
        return status;
    }
}
ConcreateObserver:


public class ConcreateObserver implements Observer {
 
    //观察者名字
    private String name;
 
    //订阅主题
    private Subject subject;
 
    public ConcreateObserver(String name, Subject subject) {
        this.name = name;
        this.subject = subject;
        subject.subscribe(this);
    }
 
    //一般仅仅只是通知的时候可以换个名字,但是有业务操作的时候就建议用update
    public void update(Subject subject) {
        ConcreateSubject concreateSubject = (ConcreateSubject) subject;
        System.out.println("observerName = " + this.name + "\n" + concreateSubject.getSubject() + " changed...." + "\n" + "status = " + Status.getStatus(concreateSubject.getStatus()).getStatusName() + "\n");
    }
 
    @Override
    public String toString() {
        return "ConcreateObserver{" +
                "name='" + name + '\'' +
                ", subject=" + subject +
                '}';
    }
}

最后看看具体的调用:

Client:

public class Client {
 
    public static void main(String args[]) {
        //定义一个主题
        ConcreateSubject subject = new ConcreateSubject("com.sankuai.sendMessage");
        //定义两个观察者
        ConcreateObserver sendObserver = new ConcreateObserver("send_message", subject);
        ConcreateObserver reSendMessage = new ConcreateObserver("re_send_message", subject);
        //更改消息状态
        subject.changed(Status.SEND.status);
    }
}

后记

在设计观察者模式的时候一定要注意以下几点:
  1. 首先要明确谁是观察者谁是被观察者,只要明确谁是关注对象,问题也就明白了,一般观察者与被观察者之间是一对多的关系,一个被观察者可以有多个观察者,举个例子吧,比如一个编辑框,有鼠标点击的观察者,还有内容改变的观察者,等等。
  2. 被观察者在发送广播通知的时候,无需指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知;
  3. 被观察者至少需要有三个方法:添加监听者,移除监听者,通知观察者;观察者至少有一个方法:更新,更新当前的内容,并作出处理;
  4. 最后说说该模式应用场景:a.对一个对象的状态的更新需要其他对象同步更新,或者一个对象的更新需要依赖于另外的对象更新;b.对象仅需要将自己的更新通知给其他的对象,不需要知道其他对象的细节,比如消息推送。

推模型和拉模型:

观察者模式根据其侧重的功能还可以分为推模型和拉模型

推模型:被观察者像向观察者推送主题相关信息,不管观察者是否需要,一般这种模型的实现中,会把呗观察者对象中的信息通过update(Object obj)传递给观察者;

拉模型:被观察者在通知观察者的时候,只需要传递少量信息。如果观察者需要更具体的信息,有观察者主动到被观察者对象中获取,相当于是观察者到被观察者对象中拉取数据。一般这种模型的视线中,会把被观察者对象自身通过update方法传递给观察者update(Subject subject),这样在观察者需要获取数据的时候,就可以通过这个引用来获取。


JDK中也支持观察者的模式,具体源码分析也会在后续的博文中给出。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值