关于java:设计模式观察者模式

6次阅读

共计 5638 个字符,预计需要花费 15 分钟才能阅读完成。

WX 搜寻:程序员个人修养 查看更多内容

观察者模式(Observer)

观察者模式是 JDK 中应用最多的模式之一,十分有用。观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

定义

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象扭转状态时,它的所有依赖者都会收到告诉并自动更新。

一对多:一个主题能够对应多个观察者。

依赖:观察者是主题的依赖者,在数据变动更新时,这样比起让许多对象管制同一份数据来,能够失去更洁净的 OO 设计。

举例

  • 报社的经营模式:

    1. 报社的业务就是出版报纸。
    2. 向某家报社订阅报纸,只有他们有新报纸出版,就会给你送来。只有你是他们的订户,你就会始终收到新报纸。
    3. 当你不想在看报纸的时候,勾销订阅,他们就不会再送新报纸。
    4. 只有报社还在经营,就会始终有人(或单位)向他们订阅报纸或者勾销订阅报纸。

    出版者 + 订阅者 = 观察者模式

  • 房产中介公司

    1. 中介公司会通过本人的各种渠道获取到很多房源信息。
    2. 须要买房的人会到中介公司或者网上注册本人的购房需要。
    3. 当中介公司有了合乎的房源,就会告诉购房者。
    4. 购房者从而获取到最新的房源信息。

    中介公司 + 购房者 = 观察者模式

类图

代码实现

package com.study.design.Observer.custom;
/**
 * 观察者实现类
 */
public class ConcreteObserver implements Observer{
    // 本地存储 subject 对象是为了之后勾销订阅,如果不须要能够不存
    private Subject subject;

    public ConcreteObserver(Subject subject){
        this.subject = subject;
        // 订阅主题
        subject.registerObserver(this);
    }

    @Override
    public void update(int stat){System.out.println("state update:" + stat);
    }
}
package com.study.design.Observer.custom;

import java.util.ArrayList;
import java.util.List;

public class ConcreteSubject implements Subject{

    List<Observer> observers;

    int stat;

    public ConcreteSubject(){observers = new ArrayList<Observer>();
    }

    @Override
    public void registerObserver(Observer o){observers.add(o);
    }

    @Override
    public void removeObserver(Observer o){int i = observers.indexOf(o);
        if(i > 0){observers.remove(i);
        }
    }

    @Override
    public void notifyObservers(int stat){for(Observer observer : observers){observer.update(stat);
        }
    }

    @Override
    public void updateStat(int stat){
        this.stat = stat;
        notifyObservers(stat);
    }
}
package com.study.design.Observer.custom;

/**
 * 观察者接口
 */
public interface Observer {void update(int stat);
}
package com.study.design.Observer.custom;

/**
 * 主题接口
 */
public interface Subject {void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers(int stat);
    void updateStat(int stat);
}
package com.study.design.Observer.custom;

public class CustomTest {public static void main(String[] args) {
        // 创立主题
        Subject subject = new ConcreteSubject();
        // 创立观察者对象
        Observer observer = new ConcreteObserver(subject);
        // 主题状态更新
        subject.updateStat(1);
    }
}

以上代码展现的是“推”模式,也就是说,在主题数据更新后,由主题对象将最新数据推送给观察者。还能够由观察者被动向主题拉取数据,称为“拉”模式。

在理论开发过程中,如果某个主题负责了多份数据,每个观察者只订阅其中一部分,那么就适宜拉模式。由观察者被动向主题拉取所须要的数据,主题只须要为每份数据提供 get 办法,而且在后续如果主题扩大了性能,新增了更多的数据,那么主题也不须要更新对每个观察者的调用,须要扭转本人来提供更多的 getter 办法即可。

Java 内置的 Observer 模式两种模式都反对。

Java 内置的观察者模式

Java API 中内置了观察者模式。在 java.util 包内蕴含最根本的 Observer 接口与 Observable 类,这和咱们的 Subject 接口与 Observer 接口很类似。Observer 接口与 Observable 类应用上更不便,因为许多性能都曾经当时筹备好了。你甚至能够应用推 (push) 或拉 (pull) 的形式传送数据。

package java.util;
/**
 * 主题类
 * 尽管定义为 class 而非之前的 interface 类型,* 然而对状态的更新 setChanged 和 setChanged 办法被定义为了 protected 类型
 * 所以,在理论开发中还是须要实现一个子类继承自 Observable 
 */
public class Observable {
    /** 主题状态 **/
    private boolean changed = false;
    /** 寄存观察者对象 **/
    private Vector<Observer> obs;
    /** 结构器 **/
    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);
    }
    /** 告诉所有观察者对象,状态曾经更新,可传送任意类型的数据 **/
    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();
    }
    /**
     * 更新状态
     * 发送告诉前,须要先调用该办法,标记状态曾经扭转,否则告诉公布进来
     */
    protected synchronized void setChanged() {changed = true;}
    /**
     * 复原状态
     * 告诉发送实现后,须要复原状态标记
     */
    protected synchronized void clearChanged() {changed = false;}
    /** 获取状态是否更新 **/
    public synchronized boolean hasChanged() {return changed;}
    /** 已注册观察者个数 **/
    public synchronized int countObservers() {return obs.size();
    }
}


package java.util;
/**
 * 观察者接口,通过该接口实现业务解决
 */
public interface Observer {
    /**
     * 接管主题数据更新的告诉
     * @param o: 主题对象
     @ @param arg: 数据对象,依据业务场景,有可能为 null
     */
    void update(Observable o, Object arg);
}

推模式实现代码:

package com.study.design.Observer.jdk.push;

import java.util.Observable;
public class PushObservable extends Observable {

    @Override
    protected synchronized void setChanged() {super.setChanged();
    }
}
package com.study.design.Observer.jdk.push;

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

public class PushObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {System.out.println("update:" + arg.toString());
    }
}
package com.study.design.Observer.jdk.push;

public class PushTest {public static void main(String[] args) {
        // 创立观察者对象
        PushObserver concreteObserver = new PushObserver();
        // 创立主题对象
        PushObservable observable = new PushObservable();
        // 订阅
        observable.addObserver(concreteObserver);
        // 更新主题状态
        observable.setChanged();
        // 发送告诉给观察者
        observable.notifyObservers("PushTest change");
    }
}

拉模式实现步骤:

package com.study.design.Observer.jdk.pull;

import java.util.Observable;

public class PullObservable extends Observable {

    private String data;

    @Override
    protected synchronized void setChanged() {super.setChanged();
    }

    public String getData() {return data;}

    public void setData(String data) {this.data = data;}
}
package com.study.design.Observer.jdk.pull;

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

public class PullObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {if (o instanceof PullObservable){PullObservable pullObservable = (PullObservable)o;
           System.out.println("update:" + pullObservable.getData());
       }
    }
}
package com.study.design.Observer.jdk.pull;

public class PullTest {public static void main(String[] args) {
        // 创立观察者对象
        PullObserver concreteObserver = new PullObserver();
        // 创立主题对象
        PullObservable observable = new PullObservable();
        // 订阅
        observable.addObserver(concreteObserver);
        // 更新数据
        observable.setData("PullTest change");
        // 更新主题状态
        observable.setChanged();
        // 发送告诉给观察者
        observable.notifyObservers();}
}

留神:当有多个观察者时,屡次执行,观察者被调用的执行程序是不统一的。

要点

  • 观察者模式定义了对象之间一对多的关系
  • 主题(也就是可观察者)用一个独特的接口来更新观察者
  • 观察者和可观察者之间用松耦合形式联合,可观察者不晓得观察者的细节,只晓得观察者实现了观察者接口
  • 应用此模式时,你能够从被观察者推或拉数据
  • 有多个观察者时,不能够依赖特定的告诉程序
  • 要留神 java.util.Observable 实现上所带来的的一些问题

WX 搜寻:程序员个人修养 查看更多内容

正文完
 0