Java design patterns described in (11): Observer Pattern

This article Source: GitHub · Click here || GitEE · Click here

First, the observer mode

1, concept description

The observer pattern is a pattern of behavior of the object, called release - Subscribe (Publish / Subscribe) mode. Observer pattern defines the dependence relationship of one to many observers have multiple objects simultaneously monitor a particular topic subject, theme object when status changes, will notify all observers objects. Redis and commonly used messaging middleware publish-subscribe model is based on the realization of the principle.

2, the core role

  • Abstract thematic roles

Abstract theme role to gather all the unified management of the observer objects, each topic can have one or more viewers. Abstract topic provides an interface, you can add and delete objects observer, also called abstract abstract theme is the role of the observer (Observable) role.

  • Specific thematic roles

The relevant observer status into concrete objects; when the change in the internal state of the specific topic, to all registered observers notice. Specific topics specific role is also known as an observer role.

  • Abstract observer role

Defined as all observers a specific interface to be notified when the update their themes, this interface is called the update interface.

  • Specific observer role

Observer role to achieve specific update interface abstract observer role required, so that the state itself is the theme of the coordination and synchronization status. If necessary, the specific role of the observer can maintain a link to the specific theme object.

3, the source code to achieve

  • Push mode based on message

Object Push the theme topic of the message to the viewer, regardless of whether the observer needs.

/**
 * 观察者设计模式
 */
public class C01_Observer {
    public static void main(String[] args) {
        // 创建主题对象
        ConcreteSubject subject = new ConcreteSubject();
        // 创建观察者对象
        Observer observer1 = new ConcreteObserver("观察者A");
        Observer observer2 = new ConcreteObserver("观察者B");
        // 注册观察者
        subject.attach(observer1);
        subject.attach(observer2);
        // 修改主题状态
        subject.change("New State !");
        /**
         * 主题状态:New State !
         *【观察者A】状态:New State !
         *【观察者B】状态:New State !
         */
    }
}
// 抽象主题角色
abstract class Subject {
    // 保存注册的观察者对象
    private List<Observer> list = new ArrayList<>();
    /**
     * 注册观察者对象
     */
    public void attach (Observer observer){
        list.add(observer);
        System.out.println("注册一个观察者:"+observer.getClass().getName());
    }
    /**
     * 删除观察者对象
     */
    public void delete (Observer observer){
        list.remove(observer);
        System.out.println("删除一个观察者:"+observer);
    }
    /**
     * 通知所有注册的观察者对象
     */
    public void notifyObserver (String newState){
        for (Observer observer : list) {
            observer.update(newState);
        }
    }
}
// 具体主题角色
class ConcreteSubject extends Subject{
    private String state ;
    public String getState (){
        return state ;
    }
    public void change (String newState){
        state = newState;
        System.out.println("主题状态:"+state);
        //状态发生改变,通知各个观察者
        this.notifyObserver(state);
    }
}
// 抽象观察者角色
interface Observer {
    /**
     * 更新接口
     */
    void update (String state);
}
// 具体观察者角色
class ConcreteObserver implements Observer{
    private String name ;
    // 观察者状态
    private String observerState ;
    public ConcreteObserver (String name){
        this.name = name ;
    }
    /**
     * 更新观察者的状态,使其与目标的状态保持一致
     */
    @Override
    public void update(String state) {
        observerState = state ;
        System.out.println("【"+this.name+"】状态:"+observerState);
    }
}
  • Pull-based message mode

Theme objects when notice of the observer, passing a small amount of information. If the observer needs to message content, relating to the object by the observer acquired in the active, equivalent to pull data from the topic viewer object.

The case based on the modified case, the object of the viewer get news theme topic, only the topic they are interested in, it further access to content.

public class C02_Observer_Pull {
    public static void main(String[] args) {
        // 创建主题对象
        ConcreteSubject1 subject = new ConcreteSubject1();
        // 创建观察者对象
        Observer1 observer1 = new ConcreteObserver1("观察者A","JAVA");
        Observer1 observer2 = new ConcreteObserver1("观察者B","MySQL");
        // 注册观察者
        subject.attach(observer1);
        subject.attach(observer2);
        /*
         * 修改主题状态
         * 主题状态:JAVA State !
         * 【观察者A】状态:JAVA State !
         * 主题状态:MySQL State !
         * 【观察者B】状态:MySQL State !
         */
        subject.change("JAVA State !","JAVA");
        subject.change("MySQL State !","MySQL");
    }
}
abstract class Subject1 {
    // 保存注册的观察者对象
    private List<Observer1> list = new ArrayList<>();
    /**
     * 注册观察者对象
     */
    public void attach (Observer1 observer){
        list.add(observer);
    }
    /**
     * 删除观察者对象
     */
    public void delete (Observer1 observer){
        list.remove(observer);
        System.out.println("删除一个观察者:"+observer);
    }
    /**
     * 通知所有注册的观察者对象,传入消息的话题
     */
    public void notifyObservers (String msgTopic){
        for (Observer1 observer : list){
            observer.update(this);
        }
    }
}
class ConcreteSubject1 extends Subject1 {
    private String state ;
    private String msgTopic ;
    public String getState (){
        return state ;
    }
    public String getMsgTopic (){
        return msgTopic ;
    }
    public void change (String newState,String newMsgTopic){
        this.state = newState ;
        this.msgTopic = newMsgTopic ;
        System.out.println("主题状态:"+state);
        this.notifyObservers(msgTopic);
    }
}

interface Observer1 {
    /**
     * 更新接口
     * @param subject 传入主题对象,方面获取相应的主题对象的状态
     */
    void update(Subject1 subject);
}
class ConcreteObserver1 implements Observer1{
    private String name ;
    // 选择话题
    private String msgTopic ;
    // 观察者状态
    private String observerState ;
    public ConcreteObserver1 (String name,String msgTopic){
        this.name = name ;
        this.msgTopic = msgTopic ;
    }
    @Override
    public void update(Subject1 subject) {
        ConcreteSubject1 concreteSubject1 = (ConcreteSubject1)subject ;
        // 只有指定话题才拉取消息
        if (concreteSubject1.getMsgTopic().equals(msgTopic)){
            observerState = concreteSubject1.getState();
            System.out.println("【"+this.name+"】状态:"+observerState);
        }
    }
}

4, compare two models

Push mode is assumed observer needs to know relating to the object data directly push, so that the object is difficult to reuse the observer; pull model is the subject of the object does not know the specific needs of the viewer what data will be transmitted to the viewer itself, taken as needed value.

Two, JDK application

JAVA language java.utill library which provides a class and a Observable Observer interface, support for the observer constituting the JAVA language mode.

1, Observer Interface

This interface defines a method, i.e., update () method, when the observer changes the state of the object, the object viewer notifyObservers () This method is called a method.

package java.util;
/**
 * A class can implement the <code>Observer</code> interface when it
 * wants to be informed of changes in observable objects.
*/
public interface Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     */
    void update(Observable o, Object arg);
}

2, Observable class

The observed classes are subclasses java.util.Observable class. java.util.Observable provide methodological support observer objects.

  • setChanged Method: state observers object changes.
  • notifyObservers: calling all registered observers object update () method.
package java.util;
public class Observable {
    private boolean changed = false;
    private Vector obs;
    /** Construct an Observable with zero Observers. */
    public Observable() {
    obs = new Vector();
    }
    /**将一个观察者添加到观察者聚集上面*/
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
    if (!obs.contains(o)) {
        obs.addElement(o);
    }
    }
    /** 将一个观察者从观察者聚集上删除 */
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }
    public void notifyObservers() {
    notifyObservers(null);
    }
    /**
     * 如果本对象有变化(那时hasChanged 方法会返回true)
     * 调用本方法通知所有登记的观察者,即调用它们的update()方法
     * 传入this和arg作为参数
     */ 
    public void notifyObservers(Object arg) {
        Object[] arrLocal;
    synchronized (this) {      
        if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
    /** 将观察者聚集清空 */
    public synchronized void deleteObservers() {
    obs.removeAllElements();
    }
    /** 将“已变化”设置为true */
    protected synchronized void setChanged() {
    changed = true;
    }
    /** 将“已变化”重置为false */
    protected synchronized void clearChanged() {
    changed = false;
    }
    public synchronized boolean hasChanged() {
    return changed;
    }
    public synchronized int countObservers() {
    return obs.size();
    }
}

3. Applications

public class C03_Observer_JDK {
    public static void main(String[] args) {
        //创建被观察者对象
        MsgSource msgSource = new MsgSource();
        //创建观察者对象,并将被观察者对象登记
        MsgConsumer watcher = new MsgConsumer(msgSource);
        msgSource.setData("Hello,Java");
        msgSource.setData("Bye Java");
    }
}
class MsgSource extends Observable {
    private String data = "";
    public String getData() {
        return data;
    }
    public void setData(String data) {
        if(!this.data.equals(data)){
            this.data = data;
            setChanged();
        }
        notifyObservers();
    }
}
class MsgConsumer implements java.util.Observer {
    // 添加观察者
    public MsgConsumer(Observable msgSource){
        msgSource.addObserver(this);
    }
    // 状态获取
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("消息内容:" + ((MsgSource)o).getData());
    }
}

Third, the summary of the advantages and disadvantages

The main mode of action is the object decoupled observer, the observer will be isolated and the observer.

The program includes a plurality of the observer and the observed multiple, develop and debug more complex and notification messages in Java is the default execution order blocking implementation of a viewer will affect the overall efficiency of the implementation.

Fourth, the source address

GitHub·地址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·地址
https://gitee.com/cicadasmile/model-arithmetic-parent

Guess you like

Origin www.cnblogs.com/cicada-smile/p/11525042.html