想一个场景
在微信的朋友圈里,在朋友发布了新的状态之后,自己就会受到更新通知,而我们发布一条朋友圈状态后,朋友们也能收到更新通知。这是一个典型的消息订阅,发布模式,换一种话说,这就是观察者模式。
模式介绍
如上场景,就可以用观察者模式来是实现。
简单点,观察者模式到底是什么?
-
观察者模式中,有两种角色,观察者与被观察对象。
-
观察者和被观察对象是多对多关系,一个观察者可以同时观察多个对象,一个对象也可以同时被多个观察者观察;被观察对象同时也可以是观察者。
-
观察者模式虽然是一种固定的模式,但其中也有可供使用者变动的地方,比如被观察对象向观察者发送数据的条件、频次,以及提供数据拉取接口供观察者主动拉取数据。
类图
应用
以下,实现了一个简单的朋友圈收发信息的功能。
先是观察者接口,此接口中只做一件事
- 收到朋友发的朋友圈状态,并处理此状态
//观察者接口
public interface Observer {
void update(StatusContent s);
}
其次是被观察对象接口,此接口至少提供3个方法
- 添加观察者
- 删除观察者
- 向观察者推送数据
//被观察对象接口
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObserver(StatusContent content);
...
}
这是一个消息体对象
//发布消息体
public class StatusContent {
private String name;
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println(name+" : "+content);
}
}
接下来是微信用户类,TA即作为观察者,接收朋友的动态数据,也作为被观察者,向朋友推送自己的状态更新
//用户类
public class WechartUser implements Subject,Observer{
//名字
private String name;
//我的朋友列表
private List<Observer> myFriends;
//我的朋友圈
private List<StatusContent> myFriendsCycle;
public WechartUser(){
myFriends = new ArrayList<>();
myFriendsCycle = new ArrayList<>();
}
public WechartUser(String name){
this.name = name;
myFriends = new ArrayList<>();
myFriendsCycle = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
if(myFriends==null){
myFriends = new ArrayList<>();
}
myFriends.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = myFriends.indexOf(o);
if(i>-1){
myFriends.remove(i);
}
}
/**
* 作为被观察对象,向ta的观察者发送
*/
@Override
public void notifyObserver(StatusContent content) {
if(myFriends!=null&&myFriends.size()>0){
for (Observer o:myFriends){
o.update(content);
}
}
}
/**
* 发布动态
* @param s
*/
public void publish(String s) {
StatusContent content = new StatusContent();
content.setContent(s);
content.setName(this.name);
//更新自己的朋友圈
update(content);
//向朋友推送
notifyObserver(content);
}
/**
* 作为观察者
* @param s
*/
@Override
public void update(StatusContent s) {
if(s!=null){
myFriendsCycle.add(s);
}
}
public void showFriendsCycle(){
System.out.println(name+"的朋友圈\n\t");
System.out.println("----------------------");
if(myFriendsCycle!=null&&myFriendsCycle.size()>0){
for (StatusContent statusContent:myFriendsCycle){
statusContent.show();
}
}
System.out.println("----------------------");
}
}
下面,我们在单元测试类里面来试一下
/**
* 测试:观察者模式下的朋友圈简单实现
*/
public class FriendCycleTest {
@Test
public void test1(){
//新建三个用户
WechartUser zhz = new WechartUser("朱厚照");
WechartUser lj = new WechartUser("刘瑾");
WechartUser wsr = new WechartUser("王守仁");
//刘瑾关注了朱厚照
zhz.registerObserver(lj);
//王守仁关注了朱厚照
zhz.registerObserver(wsr);
//王守仁关注了刘瑾
lj.registerObserver(wsr);
//朱厚照发布动态
zhz.publish("今天去居庸关玩了一圈,真是刺激!");
//刘瑾更新了动态
lj.publish("今天有个叫王守仁的尽然敢骂我?气死我了,让他到贵州龙场扫地去!");
//王守仁更新了动态
wsr.publish(("贵州龙场是个什么鬼地方?我才不去!"));
//查看朱厚照的朋友圈
zhz.showFriendsCycle();
//查看刘瑾的朋友圈
lj.showFriendsCycle();
//查看王守仁的朋友圈
wsr.showFriendsCycle();
}
}
以下是控制台输出
结语
观察者是一种比较常见的设计模式
在观察者模式中,只需要指定订阅与发布的规则,然后就可以尽情的使用它了~
但想要做到恰到好处又不滥用,还需要多加练习
附属:使用Java内置的观察者模式
Java内置的jar包:java.util里面对观察者模式已经做了支持。
只需要调用Observer接口和Observable类就可以来实现
/**
* Created by yili on 17/9/5.
*/
public class WechartUserJ extends Observable implements Observer {
/**
* 名字
*/
private String name;
/**
* 我的朋友圈
*/
private List<StatusContent> myfriendCycle;
public WechartUserJ(String name){
this.name = name;
myfriendCycle = new ArrayList<>();
}
/**
* 发布新状态
* @param s
*/
public void publish(String s){
//调用此方法后才会向观察者发送通知
//控制消息的发送条件
setChanged();
StatusContent content = new StatusContent();
content.setContent(s);
content.setName(this.name);
update(this,content);
notifyObservers(content);
}
/**
* 作为观察者更新观察数据
* @param o
* @param arg
*/
@Override
public void update(Observable o, Object arg) {
if(o instanceof WechartUserJ && arg instanceof StatusContent){
StatusContent statusContent = (StatusContent) arg;
myfriendCycle.add(statusContent);
}
}
public void showFriendsCycle(){
System.out.println(name+"的朋友圈\n\t");
System.out.println("----------------------");
if(myfriendCycle!=null&&myfriendCycle.size()>0){
for (StatusContent statusContent:myfriendCycle){
statusContent.show();
}
}
System.out.println("----------------------");
}
}
JUnit测试
/**
* 使用java内置的观察者模式接口
* Created by liuyili on 17/9/5.
*/
public class FriendCycleJavaInerTest {
@Test
public void test(){
WechartUserJ zhz = new WechartUserJ("朱厚照");
WechartUserJ lj = new WechartUserJ("刘瑾");
WechartUserJ wsr = new WechartUserJ("王守仁");
//刘瑾关注了朱厚照
zhz.addObserver(lj);
//王守仁关注了朱厚照
zhz.addObserver(wsr);
//王守仁关注了刘瑾
lj.addObserver(wsr);
zhz.publish("今天去了居庸关完玩了一圈,真是刺激");
lj.publish("今天有个叫王守仁的居然敢骂我!让他到贵州扫地去!");
wsr.publish("让我去贵州?我才不去!");
zhz.showFriendsCycle();
lj.showFriendsCycle();
wsr.showFriendsCycle();
}
}
控制台输出
可以看到,java内置的观察者模式已经帮我们做掉了一部分工作
不过Observable类只能通过继承确实一个限制因素