观察者模式

观察者模式的定义:

定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。

观察者模式的类图:
1200369-20180412161351508-1269189510.png

根据类图自定义主题、观察者接口:

package observer;

/**
 * 主题接口
 * @author 发挥哥
 *
 */
public interface Subject {
    /**
     * 注册观察者
     * @param observer 观察者对象
     */
    void registerObserver(Observer observer);
    /**
     * 移除观察者
     * @param observer 观察者对象
     */
    void removeObserver(Observer observer);
    /**
     * 通知所有观察者
     */
    void notifyObservers();
}
package observer;

/**
 * 观察者接口
 * @author 发挥哥
 *
 */
public interface Observer {
    /**
     * 主题通知所有观察者,执行该方法
     * @param msg
     */
    void update(String msg);
}

创建主题类和观察者类:

package observer;

import java.util.ArrayList;
import java.util.List;
import observer.Subject;

/**
 * 自定义主题类,实现自定义主题接口
 * @author 发挥哥
 *
 */
public class TestSubject implements Subject {
    /**
     * 所有注册到该主题的观察者
     */
    private List<Observer> observers=new ArrayList<>();
    /**
     * 主题的状态
     */
    private String msg;

    @Override
    public void registerObserver(Observer observer) {
        // TODO Auto-generated method stub
        if(observers!=null&&observer!=null)
            observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        // TODO Auto-generated method stub
        if(observers.contains(observer)) {
            observers.remove(observer);
        }
    }

    @Override
    public void notifyObservers() {
        // TODO Auto-generated method stub
        observers.stream().forEach(observer->{
            observer.update("主题更新了,大家注意:"+this.msg);
        });
    }
    
    /**
     * 编辑主题的状态后,通知所有观察者
     * @param msg
     */
    public void editMsg(String msg) {
        this.msg = msg;
        notifyObservers();
    }
}
package observer;

/**
 * 观察者1
 * @author 发挥哥
 *
 */
public class Test1Observer implements Observer {
    /**
     * 创建观察者对象时,将其注册到指定的主题
     * @param subject
     */
    public Test1Observer(Subject subject) {
        subject.registerObserver(this);
    }

    /**
     * 当主题状态变化时,通过调用该方法通知观察者
     */
    @Override
    public void update(String msg) {
        // TODO Auto-generated method stub
        System.out.println(this.getClass().getName()+"收到主题发来的消息:"+msg);
    }

}
package observer;

/**
 * 观察者2(仅为测试,实现与观察者1一样)
 * @author 发挥哥
 *
 */
public class Test2Observer implements Observer {
    
    public Test2Observer(Subject subject) {
        subject.registerObserver(this);
    }

    @Override
    public void update(String msg) {
        // TODO Auto-generated method stub
        System.out.println(this.getClass().getName()+"收到主题发来的消息:"+msg);
    }

}

创建测试方法:

package observer;

public class TestMain {

    public static void main(String[] args) {
        //创建主题
        TestSubject subject=new TestSubject();
        //创建观察者1并注册到主题
        Observer observer1=new Test1Observer(subject);
        //创建观察者2并注册到主题
        Observer observer2=new Test2Observer(subject);
        //主题进行2次状态修改
        subject.editMsg("第一次调整!");
        subject.editMsg("第二次调整!");
    }
}

测试结果如下:

observer.Test1Observer收到主题发来的消息:主题更新了,大家注意:第一次调整!
observer.Test2Observer收到主题发来的消息:主题更新了,大家注意:第一次调整!
observer.Test1Observer收到主题发来的消息:主题更新了,大家注意:第二次调整!
observer.Test2Observer收到主题发来的消息:主题更新了,大家注意:第二次调整!

以上是自定义主题和观察者接口及其实现,JDK中已经帮我们实现了观察者模式,借助于java.util.Observable和java.util.Observer:

package java.util;

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 {
    void update(Observable o, Object arg);
}

类java.util.Observable和接口java.util.Observer比较简单,直接借此创建主题和观察者类:

package observer.jdk;

import java.util.Observable;
/**
 * 主题1
 * @author 发挥哥
 *
 */
public class MySubject extends Observable {
    private String msg;

    /**
     * 编辑主题消息,并将变动标志置true,通知所有观察者,再将标志置false
     * @param msg
     */
    public void editMsg(String msg) {
        if(msg==null) {
            this.msg = msg;
            setChanged();
            notifyObservers("主题将消息置空!");
            clearChanged();
            return;
        }
        if(this.msg!=null&&msg!=null&&this.msg.equals(msg)) {
            return;
        } 
        
        this.msg = msg;
        setChanged();
        notifyObservers("主题更新消息:"+this.msg);
        clearChanged();     
    }
}
package observer.jdk;

import java.util.Observable;
/**
 * 主题2(仅为测试,与观察者1实现一样)
 * @author 发挥哥
 *
 */
public class OtherSubject extends Observable {
    private String msg;

    public void editMsg(String msg) {
        if(msg==null) {
            this.msg = msg;
            setChanged();
            notifyObservers("主题将消息置空!");
            clearChanged();
            return;
        }
        if(this.msg!=null&&msg!=null&&this.msg.equals(msg)) {
            return;
        } 
        
        this.msg = msg;
        setChanged();
        notifyObservers("主题更新消息:"+this.msg);
        clearChanged();     
    }
}
package observer.jdk;

import java.util.Observable;
import java.util.Observer;
/**
 * 观察者
 * @author 发挥哥
 *
 */
public class MyObserver implements Observer {
    /**
     * 通过该方法将观察者自己注册到主题
     * @param observable
     */
    public void registerToSubject(Observable observable) {
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println(this.getClass().getName()+"收到主题"+o.getClass().getName()+"更新消息:"+arg);
    }
}

编写测试方法:

package observer.jdk;

public class MyTest {
    public static void main(String[] args) {
        //创建主题1、主题2
        MySubject subject1=new MySubject();
        OtherSubject subject2=new OtherSubject();
        //创建观察者
        MyObserver observer=new MyObserver();
        //将观察者注册到主题1、主题2
        observer.registerToSubject(subject1);
        observer.registerToSubject(subject2);
        //主题1、主题2分别更新状态
        subject1.editMsg("主题一更新");
        subject2.editMsg("主题二更新");
    }
}

测试结果如下:

observer.jdk.MyObserver收到主题observer.jdk.MySubject更新消息:主题更新消息:主题一更新
observer.jdk.MyObserver收到主题observer.jdk.OtherSubject更新消息:主题更新消息:主题二更新

比较好的观察者模式应用是微信公众号,公众号就是我们的主题,粉丝就是观察者。功能如下:

  • 1、公众号就是主题,业务就是推送新消息;
  • 2、观察者订阅主题,有新的消息自动送来;
  • 3、当不想要此主题消息时,取消订阅即可;

总结:

观察者模式的实现方式是在观察者调用主题的addObserver方法将自己添加到主题持有的观察者列表里,主题在需要的时候调用notifyObservers遍历观察者列表,并分别调用观察者的update方法。

打个比方,主题就是婚介所,多个观察者就是多个未婚大龄男青年,男青年注册会员之后将自己的联系方式交给婚介所,婚介所在合适的时候(比如来了适龄女青年),就会挨个给注册的男青年打电话通知。

转载于:https://www.cnblogs.com/kibana/p/8808388.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值