接口意味着角色或者功能,一个类实现了一个接口就意味着这个类具有了某种功能,能够为外界提供这种功能。
从接口的角度来看,观察者模式有两种角色,observer和subject(被观察者)
二者之间的关系:主题具有某种状态,体现在代码中就是具有某些字段,这些字段是观察者所感兴趣的。一旦数据发生了改变,就应该让观察者得知,告诉观察者发生了改变。这就是观察者模式的大致概念。
程序中该如何实现?
要让主题持有对观察者的引用才能做到通知观察者,如果有多个观察者?那么主题中必须持有对观察者的引用的list才行。观察者要想对某一个主题感兴趣,就必须把自己注册到主题的list中。因此主题的接口中必须提供注册方法,相应的也要有解除方法。注册完成之后,一旦主题的数据改变,那么主题要能通知list中的观察者,因此也要有notify方法。
关于notify方法,可以在主题的业务方法(即可以改变主题数据的方法)中调用,但是这样notify用处了private method的感觉,不推荐。更好的是让主题的使用者调用,因为接口毕竟是要提供给别人使用的,如果只是在自己的类内调用,没有必要定义为public的。也就是说客户端调用subject.f()改变了数据,那么客户端还要调用subject.notify()来通知,而不是在f内部调用notify。
至于观察者呢?这个角色只要提供handle方法让主题调用即可。这个handle方法就是用来处理主题发生变化后的情况。
Subject接口:
package Subject;
import Observer.Observer;
public interface Subject {
public void register(Observer observer);
public void remove(Observer observer);
public void notifyObr();
}
Observer接口:
package Observer;
public interface Observer {
public void handle();
}
具体的主题Mouse类:
package Subject.Concrete;
import java.util.ArrayList;
import java.util.List;
import Observer.Observer;
import Subject.Subject;
public class Mouse implements Subject{
private List<Observer> observers = new ArrayList<>();
//鼠标x坐标
private int x;
//鼠标y坐标
private int y;
@Override
public void register(Observer observer) {
observers.add(observer);
}
@Override
public void remove(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObr() {
for(Observer o : observers){
o.handle();
}
}
//业务方法,鼠标移动
public void move(int x_inc, int y_inc){
this.x = x + x_inc;
this.y = y + y_inc;
notifyObr();
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
具体的观察者类:
package Observer.Concrete;
import Observer.Observer;
public class MouseMoving implements Observer{
@Override
public void handle() {
// TODO Auto-generated method stub
System.out.println("mouse moves...");
}
}
客户端:
package Test;
import Observer.Concrete.MouseMoving;
import Subject.Concrete.Mouse;
public class Test {
public void test(){
MouseMoving mouseMoving = new MouseMoving();
Mouse mouse = new Mouse();
mouse.register(mouseMoving);
mouse.move(1, 1);
mouse.notifyObr();
}
}
结果:
总结:
1,观察者角色和主题角色
2,通知机制就是在主题里面加一个观察者的list
事件机制是程序设计中常用的机制,其实现可以基于观察者模式。主题角色不变,观察者角色变成了监听器角色,本质并没有什么大的改变。还加入了事件的概念,之前主题在通知观察者的时候,并没有传递任何参数给观察者,而事实上,观察者在处理变化的时候,需要得到变化的具体情况,可以把主题的具体变化封装在事件中,传递给观察者。
事件接口:
package Event;
public interface Event {
public String getSource();
public void setSource(String source);
}
鼠标事件:
package Event;
public class MouseEvent implements Event{
private String source;
@Override
public String getSource() {
return source;
}
@Override
public void setSource(String source) {
this.source = source;
}
}
观察者接口:
package Observer;
import Event.Event;
public interface Observer {
public void handle(Event event);
}
客户端:
package Test;
import Event.Event;
import Event.MouseEvent;
import Observer.Concrete.MouseMoving;
import Subject.Concrete.Mouse;
public class Test {
public void test(){
MouseMoving mouseMoving = new MouseMoving();
Mouse mouse = new Mouse();
mouse.register(mouseMoving);
mouse.move(1, 1);
String source = "1,1";
Event event = new MouseEvent();
event.setSource(source);
mouse.notifyObr(event);
}
}