程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> java高級---->Java觀察者的原理

java高級---->Java觀察者的原理

編輯:JAVA編程入門知識

  觀察者模式定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態上發生變化時,會通知所有觀察者對象,讓他們能夠自動更新自己。今天我們通過模擬按鈕的處理事件來深入Java觀察者模式的學習。

 

目錄導航

  1.   Java觀察者的簡要說明
  2.   Java的按鈕點擊案例
  3.   使用Java中的Observer來模擬按鈕監聽事件機制
  4.   Java中的Observer原理的說明
  5.   使用自定義的Observer來過濾按鈕監聽事件
  6.   友情鏈接

 

Java觀察者的簡要說明

觀察者模式所涉及的角色有:

  ● 抽象主題(Subject)角色:抽象主題角色把所有對觀察者對象的引用保存在一個聚集(比如ArrayList對象)裡,每個主題都可以有任何數量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象,抽象主題角色又叫做抽象被觀察者(Observable)角色。

  ● 具體主題(ConcreteSubject)角色:將有關狀態存入具體觀察者對象;在具體主題的內部狀態改變時,給所有登記過的觀察者發出通知。具體主題角色又叫做具體被觀察者(Concrete Observable)角色。

  ● 抽象觀察者(Observer)角色:為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己,這個接口叫做更新接口。

  ● 具體觀察者(ConcreteObserver)角色:存儲與主題的狀態自恰的狀態。具體觀察者角色實現抽象觀察者角色所要求的更新接口,以便使本身的狀態與主題的狀態 像協調。如果需要,具體觀察者角色可以保持一個指向具體主題對象的引用。

 

Java的按鈕點擊案例

我們建立一個項目去開始今天的測試。項目結構如下:

demo很簡單,點擊button按鈕,修改button上顯示的文字

package com.huhx.frame;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

/**
 * writer: huhx
 */
public class Jframe extends JFrame {
    private JButton button;

    public Jframe() {
        button = new JButton("text");
        add(button);
        setVisible(true);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                button.setText("world");
            }
        });
    }
    
    public static void main(String[] args) {
        new Jframe();
    }
}

 

使用Java中的Observer來模擬按鈕監聽事件機制

  java中的內置觀察者模式有兩個類:一個是observable被觀察者類,一個是observer觀察者接口。大體上與自定義模式相同,我們編寫程序時只需繼承obervable類,具體實現observer接口就可以了。值得注意的是:調用notifyObservers()方法之前,必須先調用setChanged()方法。這是因為observable類中把 changed變量初始化為false,notifyObservers()方法會先檢查該變量是否為true,如果不為ture,就不會調用 update()方法,這就要我們調用notifyObservers()之前,先用setChanged()方法將changed變量設置為true。

 現在我們以上述例子為引子,使用Java中內置的Observer自己來模擬一個按鈕監聽事件的案例:

一、 創建一個繼承obervable類的被觀察者,在案例中也就是Button,類記為:MyButton

package com.huhx.observer;

import java.util.Observable;
import java.util.Observer;

/**
 * @author huhx 
 */
public class MyButton extends Observable {
    public void addListeners(Observer observer) {
        addObserver(observer);
    }

    public void process(Object args) {
        setChanged();
        notifyObservers(args);
    }

    public void process() {
        process(null);
    }
}

 

二、 創建幾個觀察這個按鈕的觀察者,其實就是按鈕的監聽事件:

模擬點擊事件:

package com.huhx.observer;

import java.util.Observable;
import java.util.Observer;

public class ClickObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        if (arg != null) {
            System.out.println("click: " + arg.toString());
        } else {
            System.out.println("click no arg");
        }
    }
}

模擬按下事件:

package com.huhx.observer;

import java.util.Observable;
import java.util.Observer;

public class PressObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        if (arg != null) {
            System.out.println("press: " + arg.toString());
        } else {
            System.out.println("press no arg");
        }
    }
}

 

三、 然後我們寫一個測試的類,用於模擬按鈕的事件:這裡的process方法模擬真實按鈕的觸發事件,比如我們按下按鈕。

package com.huhx.observer;

import java.util.Observable;
import java.util.Observer;

public class PersonTest {

    public static void main(String[] args) {
        MyButton button = new MyButton();
        button.addObserver(new ClickObserver());

        button.addListeners(new Observer() {
            @Override
            public void update(Observable o, Object arg) {
                System.out.println("observer");
            }
        });
        button.process("huhx");
    }
}

 

五、 它的輸出結果如下:

observer
click: huhx

 

Java中的Observer原理的說明

上述我們通過案例,來模擬了按鈕的監聽事件原理,現在我們通過源碼來詳細的分析它的運行過程:

一、 Observer是一個觀察者可以實現的接口,它的文檔說明如下:

A class can implement the Observer interface when it wants to be informed of changes in observable objects.

 Observer中有一個update()方法:

void update(Observable o, Object arg); // Observable 是觀察者  arg 是notifyObservers方法傳入的參數

 

二、 Observable是一個被觀察者繼承的類,它的文檔說明大致如下:

This class represents an observable object, or "data" in the model-view paradigm. It can be subclassed to represent an object that the application wants to have observed. 

Observable有幾個重要的方法,我們簡單的介紹一下:

void addObserver(Observer o)            // 加入觀察者到Vetor中
protected  void clearChanged()          // 設置change為false
int countObservers()                    // 返回Vetor中觀察者的數量
void deleteObserver(Observer o)         // 從Vetor中刪除指定的觀察者
void deleteObservers()                  // 刪除所有的觀察者
void notifyObservers()                  // 通知Vetor中的觀察者
void notifyObservers(Object arg)        // 通知Vetor中的觀察者,帶參數
boolean hasChanged()                    // 判斷是否發生改變
protected  void setChanged()            // 設置changed為true

 

三、 接下來,我們結合上述的例子來分析Observer的原理:

當執行MyButton button = new MyButton(),由於MyButton是繼承Observable,所以下述代碼會執行。

private boolean changed = false;
private Vector obs;

public Observable() {
    obs = new Vector();
}

當執行button.addObserver(new ClickObserver()),把參數中的Observer存放在上述初始化的Vetor中(為了適應多線程,用的是Vetor)

public synchronized void addObserver(Observer o) {
    if (o == null)
        throw new NullPointerException();
    if (!obs.contains(o)) {
        obs.addElement(o);
    }
}

當執行button.process("huhx"),如果被觀察者發生了改變,就通知Vetor中的觀察者去執行update方法。

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);
}

 

使用自定義的Observer來過濾按鈕監聽事件

上述案例中,我們還無法做到對觀察者的過濾通知,現在我們自己實現一個Observer,來對事件監聽的事件過濾,更好的模擬按鈕的事件機制。

一、 定義一個常量類,用於各種事件的標記:

package com.huhx.myobserver;

/**
 * huhx 陳慧
 */
public class Event {
    // 觸發所有的Listener
    public static final int ALL = -1;
    // 觸發內部定義的Listener
    public static final int DEFAULT = 0;
    public static final int CLICK = 1;
    public static final int PRESS = 2;
    public static final int DOWN = 3;
    public static final int FOCUE = 4;
}

 

 二、 定義一個Listener接口,和Java內置的Observer作用類似,注意方法中的參數是MyObservable

package com.huhx.listener;

import com.huhx.myobserver.MyObservable;

public interface Listener {

    void actionPerformed(MyObservable o, Object arg);
}

 

三、 定義幾個實現Listener的觀察者,也就是事件:

模擬點擊事件:

package com.huhx.listener;

import com.huhx.myobserver.MyObservable;

/**
 * 陳慧
 * @author Linux
 *
 */
public class ClickListener implements Listener {
    @Override
    public void actionPerformed(MyObservable o, Object arg) {
        if (arg != null) {
            System.out.println("click: " + arg);
        } else {
            System.out.println("click");
        }
    }
}

模擬按下事件:

package com.huhx.listener;

import com.huhx.myobserver.MyObservable;

public class PressListener implements Listener {

    @Override
    public void actionPerformed(MyObservable o, Object arg) {
        System.out.println("press");
    }
}

模擬定義在內部類中的事件:

package com.huhx.listener;

import com.huhx.myobserver.MyObservable;

public class DefaultListener implements Listener {

    @Override
    public void actionPerformed(MyObservable o, Object arg) {

    }
}

 

四、 定義一個類似於Observable類的自定義被觀察者:

package com.huhx.myobserver;

import java.util.Vector;

import com.huhx.listener.ClickListener;
import com.huhx.listener.Listener;
import com.huhx.listener.PressListener;

/**
 * 
 * @author huhx
 *
 */
public class MyObservable {
    private boolean changed = false;
    private Vector<Listener> obs;
    Object[] arrLocal;

    public MyObservable() {
        obs = new Vector<>();
    }

    protected synchronized void clearChanged() {
        changed = false;
    }

    public void notifyObserverByEvent(int event, Object args) {
        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }
        notifyFixObserver(event, args);
    }

    private void notifyFixObserver(int event, Object args) {
        Listener listener = null;
        for (int i = arrLocal.length - 1; i >= 0; i--) {
            listener = (Listener) arrLocal[i];
            switch (event) {
            case Event.PRESS:
                if (listener instanceof PressListener)
                    ((PressListener) listener).actionPerformed(this, args);
                break;
            case Event.CLICK:
                if (listener instanceof ClickListener)
                    ((ClickListener) listener).actionPerformed(this, args);
                break;
            case Event.DEFAULT:
                if (listener instanceof Listener)
                    listener.actionPerformed(this, args);
                break;
            case Event.ALL:
                listener.actionPerformed(this, args);
                break;
            default:
                break;
            }
        }
    }

    public void notifyObserverByEvent(int event) {
        notifyObserverByEvent(event, null);
    }

    public void notifyObserverByEvent(Object args) {
        notifyObserverByEvent(Event.ALL, args);
    }

    public synchronized void addListener(Listener listener) {
        if (listener == null)
            throw new NullPointerException();
        if (!obs.contains(listener)) {
            obs.addElement(listener);
        }
    }

    protected synchronized void setChanged() {
        changed = true;
    }
}

 

五、 為了簡化Button的使用,我們仿造Java中的做法,先創建一個AbstractButton,用於處理共公的代碼:

package com.huhx.myobserver;

import com.huhx.listener.Listener;

public class AbstractButton extends MyObservable {
    public void addListeners(Listener listener) {
        addListener(listener);
    }

    public void process(int source, Object args) {
        setChanged();
        switch (source) {
        case Event.CLICK:
            notifyObserverByEvent(Event.CLICK, args);
            break;
        case Event.PRESS:
            notifyObserverByEvent(Event.PRESS, args);
            break;
        case Event.DEFAULT:
            notifyObserverByEvent(Event.DEFAULT, args);
            break;
        case Event.ALL:
            notifyObserverByEvent(Event.ALL, args);
        default:
            break;
        }
    }

    public void process(int source) {
        process(source, null);
    }
}

 

六、 創建一個被觀察者,也就是我們的按鈕Button

package com.huhx.myobserver;

/**
 * 
 * @author Linux
 *
 */

public class MyButtton extends AbstractButton {

}

 

七、 在測試中使用:

package com.huhx.myobserver;

import com.huhx.listener.ClickListener;
import com.huhx.listener.Listener;

public class PersonTest {
    public static void main(String[] args) {
        MyButtton buttton = new MyButtton();
        buttton.addListener(new Listener() {
            @Override
            public void actionPerformed(MyObservable observable, Object object) {
                System.out.println("listener");
                System.out.println(observable + ", object: " + object.toString());
            }
        });

        buttton.addListener(new ClickListener());
        buttton.process(Event.CLICK);
//        buttton.process(Event.DEFAULT, "world");
    }
}

它的輸出結果如下:

click: 陳慧

 

友情鏈接

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved