在我们日常生活中,有些人会有订阅报纸的经历,当我们订阅时,都能定时的收到报纸,当我么取消订阅时,就不会再收到报纸。
当然,互联网普及之后,报纸逐渐减少。但是类似的也有许多,例如微信的公众号,当我们订阅了公众号时,公众号有新文章发布时就会推送到我们的微信上。
用户3关注公众号
公众号把用户3添加到关注用户列表中,有新文章时推送给关注用户列表中
用户2取消关注,公众号把用户2从关注用户列表中移除,有新文章时不再推送给用户2
以上便是观察这模式
介绍
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。
结构图
时序图
案例
案例就采用模拟公众号订阅的机制
注:以下代码只是提供个思路
主题抽象类(公众号)
public abstract class Subject {
List<UserObeserver> userList = new ArrayList<UserObeserver>();
public void addUser(UserObeserver userObeserver){
userList.add(userObeserver);
}
public void delUser(UserObeserver userObeserver){
userList.remove(userObeserver);
}
public void pushArticle(String articleContent){
for (UserObeserver userObeserver : userList) {
userObeserver.receiveArticle(this,articleContent);
}
}
public abstract String getSubjectName();
}
公众号1
public class ConcreteSubject1 extends Subject{
@Override
public String getSubjectName() {
return "公众号1";
}
}
公众号2
public class ConcreteSubject2 extends Subject{
@Override
public String getSubjectName() {
return "公众号2";
}
}
订阅者接口(用户)
public interface UserObeserver {
void receiveArticle(Subject subject, String articleContent);
}
用户1
public class ConcreteUserObeserver1 implements UserObeserver {
@Override
public void receiveArticle(Subject subject,String articleContent) {
System.out.println("我是读者1,公众号名称:"+subject.getSubjectName()+" 推出的新的文章内容是"+articleContent);
}
}
用户2
public class ConcreteUserObeserver2 implements UserObeserver {
@Override
public void receiveArticle(Subject subject,String articleContent) {
System.out.println("我是读者2,公众号名称:"+subject.getSubjectName()+" 推出的新的文章内容是"+articleContent);
}
}
测试类
public class Client {
public static void main(String[] args) {
ConcreteSubject1 subject1 = new ConcreteSubject1();
ConcreteSubject2 subject2 = new ConcreteSubject2();
ConcreteUserObeserver1 user1 = new ConcreteUserObeserver1();
ConcreteUserObeserver2 user2 = new ConcreteUserObeserver2();
//读者1、2都订阅公众号1,读者2订阅了公众号2
subject1.addUser(user1);
subject1.addUser(user2);
subject2.addUser(user2);
//公众号发布消息
System.out.println("第一篇");
subject1.pushArticle("1.今天天气不错!");
subject2.pushArticle("1.今天天气很不错!");
//读者1取消关注公众号1,想去关注公众号2,读者2取消关注公众号2
subject1.delUser(user1);
subject2.delUser(user2);
subject2.addUser(user1);
System.out.println("第二篇");
subject1.pushArticle("2.今天天气一般般!");
subject2.pushArticle("2.今天天气很一般般!");
}
}
测试结果
总结
这一模式中的关键对象是观察目标和观察者,一个目标可以有任意数目的与之相依赖的观察者,一旦目标的状态发生改变,所有的观察者都将得到通知。
观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
JDK中有内置的观察者模式,Observer接口和Observable类,有兴趣的可以了解下。
延伸
观察者模式中观察者有没有可能变成主题,也就是观察者既可以保持自身的身份又可以发布新的消息?
当然可以,想现在的微博,你关注别人,你就能获得那个人发布的消息,如果他也关注你,那么他也能收到你发布的消息。微信朋友圈亦是如此,当你们成为微信好友是,双方都能收到彼此发的朋友圈。
用户1
public class User1 extends Subject implements UserObeserver{
@Override
public void receiveArticle(Subject subject, String articleContent) {
System.out.println("我是用户1,"+subject.getSubjectName()+" 推出的新的文章内容是"+articleContent);
}
@Override
public String getSubjectName() {
return "用户1";
}
}
用户2
public class User2 extends Subject implements UserObeserver{
@Override
public void receiveArticle(Subject subject, String articleContent) {
System.out.println("我是用户2,"+subject.getSubjectName()+" 推出的新的文章内容是"+articleContent);
}
@Override
public String getSubjectName() {
return "用户2";
}
}
测试类
public class Client {
public static void main(String[] args) {
User1 user1 = new User1();
User2 user2 = new User2();
//用户1和用户2互相加为好友
user1.addUser(user2);
user2.addUser(user1);
user1.pushArticle("1.今天天气不错!");
user2.pushArticle("1.今天天气很不错!");
//用户2把用户1给屏蔽了(注:应该从用户1中去掉用户2中的观察者)
System.out.println("用户2把用户1给屏蔽了");
user1.delUser(user2);
user1.pushArticle("1.今天天气不错!");
user2.pushArticle("1.今天天气很不错!");
}
}
测试类中的用户2把用户1给屏蔽了,有些人可能思路转不过来,为什么用户2把用户1给屏蔽了,用户1要去删除用户2的对象?
换个思路就是用户2不想在收到用户1的消息,所以用户1中维护的观察者列表中要删除这个对象。
代码见Github地址