观察者模式

观察者模式的定义:

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

观察者模式的类图:

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

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