大话设计模式:观察者模式
观察者模式:
官方定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所依赖者都会收到通知并自动更新。
理解:观察者模式在生活中的例子像在头条中关注了某好友,当好友发布消息时,系统第一时间将信息全部推送给我(推模型),或者只传递消息的部分,自己手动获取另外的部分(拉模型),这样保证了当好友有动态时,我能够收到消息。像这个例子中,可以有两种方式获得消息,其实在观察者模式中提供了两种不同的模型分别是推、拉模型。相当于头条两种发消息方式,第一:发送全部消息内容,第二:发送关键信息,点击关键信息可以查看全部内容。
观察者的角色:
抽象观察者接口:注册到主题上,当主题改变时,会得到主题发送的消息。
抽象主题接口:维护一个观察者的集合,观察者可以在集合中注册和移除,当有消息发送时,主题会遍历所有的观察者,发送消息。
具体观察者:实现抽象观察者,在类内部可以自定义相关符合业务逻辑内容。
具体主题:具体实现抽象主题,实现具体发送观察者消息的方法。
拉模式:
public class Message { private String title; private String content; @Override public String toString() { return "Message{" + "title='" + title + '\'' + ", content='" + content + '\'' + '}'; } public Message() { } public Message(String title, String content) { this.title = title; this.content = content; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
/** * 主题接口: */ public interface Subject { void register(Observer o);//注册观察者 void remove(Observer o);//移除观察者 void update();//向观察者发消息 }
public class SubjectImpl implements Subject { private Message msg; private List<Observer> list; public Message getMsg() { return msg; } public SubjectImpl(){ list = new ArrayList<Observer>(); } @Override public void register(Observer o) { if(!list.contains(o)) list.add(o); } @Override public void remove(Observer o) { list.remove(o); } /** * 当有消息时,遍历观察者发送消息 * @param msg */ public void setMsg(Message msg) { this.msg = msg; update(); } @Override public void update() { for(Observer observer:list){ observer.pull(this); } } }
public interface Observer { void pull(Subject subject); }
public class ObserverImpl implements Observer { public ObserverImpl(String name) { this.name = name; } private String name;//观察者的名字 @Override public void pull(Subject subject) { Message msg = ((SubjectImpl) subject).getMsg(); System.out.println(name+"--title"+msg.getTitle()+"--content"+msg.getContent()); } }
public class Main { public static void main(String[] args) { Message message = new Message("测试观察者的pull模式","怎样测试观察者poll模式?。。。。。。"); ObserverImpl observer1 = new ObserverImpl("观察者1"); ObserverImpl observer2 = new ObserverImpl("观察者2"); SubjectImpl sub= new SubjectImpl(); sub.register(observer1); sub.register(observer2); sub.setMsg(message); } }
在代码中,我们能够感觉到,可以吧抽象主题类由接口转换为抽象类,这样在具体实现类中只需要把消息置入主题中即可。
在拉模式下,主题像观察者只发送少量的关键信息,在实际的上,往往是关键字绑定url链接的方式。
拉模式有点包括:接收信息量少,信息发送快。
推模式:
/** * 主题接口: */ public interface Subject { void register(Observer o);//注册观察者 void remove(Observer o);//移除观察者 void update();//向观察者发消息 }
public class SubjectImpl implements Subject { private Message msg; private List<Observer> list; public Message getMsg() { return msg; } public SubjectImpl(){ list = new ArrayList<Observer>(); } @Override public void register(Observer o) { if(!list.contains(o)) list.add(o); } @Override public void remove(Observer o) { list.remove(o); } public void setMsg(Message msg) { this.msg = msg; update(); } @Override public void update() { for(Observer observer:list){ observer.push(msg); } } }
public interface Observer { void push(Message msg); }
public class ObserverImpl implements Observer { public ObserverImpl(String name) { this.name = name; } private String name;//观察者的名字 @Override public void push(Message msg) { System.out.println(msg); } }
public class Main { public static void main(String[] args) { Message message = new Message("测试观察者的push模式","怎样测试观察者push模式?。。。。。。"); ObserverImpl observer1 = new ObserverImpl("观察者1"); ObserverImpl observer2 = new ObserverImpl("观察者2"); SubjectImpl sub= new SubjectImpl(); sub.register(observer1); sub.register(observer2); sub.setMsg(message); } }
在代码中明显感觉接受者接受的消息可能会变多,但是这样发送消息和接受消息简单。
只需要将消息全部发出和全部接受即可,操作简单。
观察者模式在JAVA
主题对应:java.util.Observable
观察者对应:java.util.Observer
在java中,主题对应的Observable对应是是一个普通类,而不是抽象类或接口,方法中使用synchronized关键字,效率不高,因为不是接口,所以要用继承不能用组合。如果有必要可以自己手动实现主题。