干完活抽点时间写一下第二个,观察者模式,定义如下:
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
这里用例子说话,某动物园里,饲养员给动物们提供了一份食物报刊,动物们感兴趣的可以自己订阅,订阅后有食物变动都会通知它们。
观察者模式中,被观察者需要实现一个主题抽象(模式中讲的抽象可以是抽象类或者接口),而这里的主题就是食物报刊;而观察者要实现观察者抽象,这里的观察者就是动物们。
主题和观察者抽象代码如下:
package head_first.observer.self;
public interface Subject {
public void registerObserver(Observer o);//注册观察者
public void removeObserver(Observer o);//取消订阅
public void notifyObservers();//通知观察者
}
package head_first.observer.self;
public interface Observer {
public void update(String name, int number);
}
具体主题(被观察者)食物报刊如下:
package head_first.observer.self;
import java.util.ArrayList;
public class FoodData implements Subject {
ArrayList<Observer> observers;//主题队列
String name; //食物
int number; //食物数量
public FoodData(){
observers = new ArrayList<Observer>();
}
/**
* 注册观察者
*/
public void registerObserver(Observer o) {
observers.add(o);
}
/**
* 取消观察者
*/
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0)
observers.remove(o);
}
/**
* 通知观察者
*/
public void notifyObservers() {
for(int i=0;i<observers.size();i++){
Observer o = observers.get(i);
o.update(name, number);
}
}
private void measurementsChanged(){
notifyObservers();
}
/**
*更新食物消息
*/
public void setMesurements(String name, int number){
this.name = name;
this.number = number;
measurementsChanged();//更新消息后通知观察者
}
}
然后是观察者具体类老鼠和狗:
package head_first.observer.self;
import head_first.observer.weatherwatch.DisplayElement;
public class MouseObserver implements DisplayElement, Observer {
private String name; // 食物
private int number; // 食物数量
private Subject foodData;
public MouseObserver(Subject foodData) {
this.foodData = foodData;
this.foodData.registerObserver(this);
}
public void display() {
System.out.println("I'm mouse : the name of food is: " + name + ", number is: "
+ number);
}
public void update(String name, int number) {
this.name = name;
this.number = number;
display();
}
public void removeSubject(){
this.foodData.removeObserver(this);
}
}
package head_first.observer.self;
import head_first.observer.weatherwatch.DisplayElement;
/**
* DisplayElement是观察者的一个消息通知模板接口
*/
public class DogObserver implements DisplayElement, Observer {
// 订阅者想知道的东西
private String name;
private int number;
private Subject foodData;
public DogObserver(Subject foodData) {
this.foodData = foodData;
this.foodData.registerObserver(this);
}
public void update(String name, int number) {
this.name = name;
this.number = number;
display();
}
/**
* 收到的消息
*/
public void display() {
System.out.println("I'm dog : the name of food is: " + name + ", number is: "
+ number);
}
/**
* 退订报刊
*/
public void removeSubject(){
this.foodData.removeObserver(this);
}
}
DisplayElement代码:
package head_first.observer.weatherwatch;
public interface DisplayElement {
public void display();
}
接下来让我们测试一下吧:
package head_first.observer.self;
public class FoodTest {
public static void main(String[] args) {
FoodData foodData = new FoodData();
//老鼠和狗都订阅了食物报刊
MouseObserver mouse = new MouseObserver(foodData);
DogObserver dog = new DogObserver(foodData);
foodData.setMesurements("apple", 3);
foodData.setMesurements("Dog Food", 5);
System.out.println("--------------------");
//总是没有喜欢吃的,老鼠退订了
mouse.removeSubject();
foodData.setMesurements("rice", 4); //有稻米了,可惜老鼠不知道咯~
}
}
这是运行结果:
I'm mouse : the name of food is: apple, number is: 3
I'm dog : the name of food is: apple, number is: 3
I'm mouse : the name of food is: Dog Food, number is: 5
I'm dog : the name of food is: Dog Food, number is: 5
--------------------
I'm dog : the name of food is: rice, number is: 4
之前老鼠和狗都能收到消息,可是老鼠退订后就收不到消息了,自然也错过了稻米的美味~~
利用观察者模式,主题是拥有状态的对象,并且可以控制这些状态。
而观察者使用这些状态,虽然这些状态并不属于他们,有许多观察者依赖主题来告诉他们状态何时改变。
主题是真正拥有数据的人,观察者依赖于主题,在数据变化时更新,这样便是实现了观察者与具体数据之间的解耦和,是一种更干净的OO设计。
设计原则
为了交互对象之间的松耦合设计而努力。
———————松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。
当然,jdk里有java内置的观察者模式
java.util.Observer和java.util.Observable。不过跟上述例子的差异是Observable是类。
JAVA内置的观察者模式运作方式:
如何把对象变成观察者:
观察者实现观察者接口(java.util.Observer),然后调用Observable对象的addObserver()方法,退订是调用deleteObserver()即可。
被观察者如何送出通知:
首先,扩展java.util.Observable类,然后
1、先调用setChanged()方法,标记状态已经改变的事实。
2、调用两种notifyObservers()方法其中之一:
notifyObservers()或 notifyObservers(Object arg)
观察者接受通知:
观察者实现了更新的方法update(Observable o, Object arg),以主题对象为第一个参数,可以让观察者知道哪个主题通知他的,arg就是notifyObservers(Object arg)中的参数。
java.util.Observable的黑暗面:
Observable是一个类,它违反了“针对抽象编程,而非针对实现编程”的原则,限制了使用和复用,它的子类必须继承它,但此时如果想同时具有另一个超类的行为,便没办法了,java不支持多继承。
还有Observable类中有些方法被定义成protected(比如setChanged()),这就意味着只有继承Observable,才能创建Observable的实例并组合到你自己的对象中,违反了“多用组合,少用继承”的原则。
另外,swing和GUI中也有好多观察者模式的使用,可以好好研究下。