生活中的场景:微信红点通知,手机起床闹钟
使用场景:1、当一个抽象模型包含两个方面内容,其中一个方面依赖于另一个方面;
2、其他一个或多个对象的变化依赖于另一个对象的变化
3、实现类似广播机制的功能,无需知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播;
4、多层嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知
标准代码结构:抽象主题,具体主题,抽象观察者,具体观察者
具体主题(被观察者)会存储所有观察者,一旦主题发生变化,会逐一通知被观察者
jdk实现观察者模式:被观察者 extends Observable,观察者implements Observer
这里实现了Observer jdk会自动将观察者加入Vector<Observer>集合
例子:用户给社区老师提问的例子
public class Community extends Observable {
private String name = "社区";
private static final Community instance = new Community();
private Community(){}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Community getInstance(){
return instance;
}
public void publishQuestion(Question question){
System.out.println(question.getUsername() + "在" + this.name + "提交了一个问题!");
setChanged();
notifyObservers(question);
}
}
public class Question {
private String username;
private String content;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
public class Teacher implements Observer {
private String name;
public Teacher(String name){
this.name = name;
}
public void update(Observable o, Object arg) {
Community community = (Community)o;
Question question = (Question)arg;
System.out.println("===============");
System.out.println(name + "老师,你好\n" +
"您收到了一个来自" + community.getName() +
"的提问,希望您解答。问题内容为:" +
question.getContent() +"\n" +
"提问者:" + question.getUsername());
}
}
public class Test {
public static void main(String[] args) {
Community community = Community.getInstance();
Teacher tom = new Teacher("tom");
Teacher lily = new Teacher("lily");
community.addObserver(tom);
community.addObserver(lily);
Question question = new Question();
question.setUsername("zhangsan");
question.setContent("观察者模式使用场景是那些?");
community.publishQuestion(question);
}
}
运行结果
zhangsan在社区提交了一个问题!
===============
lily老师,你好
您收到了一个来自社区的提问,希望您解答。问题内容为:观察者模式使用场景是那些?
提问者:zhangsan
===============
tom老师,你好
您收到了一个来自社区的提问,希望您解答。问题内容为:观察者模式使用场景是那些?
提问者:zhangsan
Process finished with exit code 0
谷歌guava实现观察者模式(常用):
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
</dependencies>
public class GuavaEvent {
@Subscribe
public void observer1(Object o){
System.out.println("执行observer1方法,传参为:" + o.toString());
}
@Subscribe
public void observer2(Object o){
System.out.println("执行observer2方法,传参为:" + o.toString());
}
}
public class Test {
public static void main(String[] args) {
//消息总线
EventBus eventBus = new EventBus();
GuavaEvent guavaEvent = new GuavaEvent();
eventBus.register(guavaEvent);
eventBus.post("nihao ");
}
}
结果
执行observer2方法,传参为:nihao
执行observer1方法,传参为:nihao
Process finished with exit code 0
手写一个观察者模式,并模拟鼠标点击事件
被观察者抽象
public class EventListener {
//存储被观察者map
protected Map<String, Event> events = new HashMap<String, Event>(16);
public void addListener(String eventType, Object target, Method callback){
events.put(eventType, new Event(target,callback));
}
//如果没有回调
public void addListener(String eventType, Object target){
try {
//约定Event方法名已on开头
this.addListener(eventType, target, target.getClass().getMethod("on" + toUpperFirstCase(eventType), Event.class));
//events.put(eventType, new Event(target,callback));
}catch (Exception e){
e.printStackTrace();
}
}
private String toUpperFirstCase(String eventType) {
char[] chars = eventType.toCharArray();
chars[0] -= 32;
return String.valueOf(chars);
}
private void trigger(Event event){
event.setSource(this);
event.setTime(System.currentTimeMillis());
try {
if (event.getCallback() != null) {
//用反射调用函数
event.getCallback().invoke(event.getTarget(),event);
}
}catch (Exception e){
e.printStackTrace();
}
}
protected void trigger(String trigger){
if(!this.events.containsKey(trigger)){return;}
trigger(this.events.get(trigger).setTrigger(trigger));
}
}
具体被观察者
public class Mouse extends EventListener{
public void click(){
System.out.println("调用单机方法");
this.trigger(MouseEventType.ON_CLICK);
}
}
public class MouseEventCallback {
//update
public void onClick(Event e){
System.out.println("触发鼠标单击事件");
}
}
public class Event {
//事件源,动作是由谁发出的
private Object source;
//事件触发,要通知谁(观察者)
private Object target;
//观察者给的回应
private Method callback;
//事件的名称
private String trigger;
//事件的时间
private long time;
public Event(Object target, Method callback) {
this.target = target;
this.callback = callback;
}
public Object getSource() {
return source;
}
public Event setSource(Object source) {
this.source = source;
return this;
}
public Object getTarget() {
return target;
}
public Event setTarget(Object target) {
this.target = target;
return this;
}
public Method getCallback() {
return callback;
}
public Event setCallback(Method callback) {
this.callback = callback;
return this;
}
public String getTrigger() {
return trigger;
}
public Event setTrigger(String trigger) {
this.trigger = trigger;
return this;
}
public long getTime() {
return time;
}
public Event setTime(long time) {
this.time = time;
return this;
}
@Override
public String toString() {
return "Event{" +
"source=" + source +
", target=" + target +
", callback=" + callback +
", trigger='" + trigger + '\'' +
", time=" + time +
'}';
}
}
public interface MouseEventType {
String ON_CLICK = "click";
}
public class Test {
public static void main(String[] args) {
//具体观察者
MouseEventCallback callback = new MouseEventCallback();
//被观察者
Mouse mouse = new Mouse();
mouse.addListener(MouseEventType.ON_CLICK, callback);
mouse.click();
}
}
运行结果:
调用单机方法
触发鼠标单击事件
Process finished with exit code 0
网友评论