[design pattern](2) Observer
前言
在上一个博客中我们介绍了Strategy模式,它是行为型模式麾下的一员大将。那么本博客我们来学习一下行为型模式麾下的另一员大将Observer模式。
思考题
老套路,先来思考下面的问题:
问题:思考报纸订阅的问题,有一个体育报社每天都会有新的体育报道,关注体育新闻的用户会获取每天的报道
首先,我们还是来看一看不使用设计模式的代码:
SportNews.java:
public class SportNews {
private String context;
//用户获取新闻
public String getContext() {
return context;
}
//产生新的新闻
public void newContext(String context) {
this.context = context;
}
}
People.java:
public class People {
private final String name;
private SportNews sportNews;
public People(String name, SportNews sportNews) {
this.sportNews = sportNews;
this.name = name;
}
//读新闻
public void readNews() {
System.out.println(String.format("I am %s,I am looking %s", name, sportNews.getContext()));
}
}
Robot.java:
public class Robot {
private static int num = 0;
private final int id = num++;
private SportNews sportNews;
public Robot(SportNews sportNews) {
this.sportNews = sportNews;
}
public void readNews() {
System.out.println(String.format("Robot:%s,Context:%s", id, sportNews.getContext()));
}
}
测试程序:
TestMain.java:
public class TestMain {
public static void main(String... ars) {
SportNews sportNews = new SportNews();
People xiaoLi = new People("xiao li", sportNews);
People xiaoMin = new People("xiao min", sportNews);
Robot robot = new Robot(sportNews);
sportNews.newContext("H:F 1:1");
xiaoLi.readNews();
xiaoMin.readNews();
robot.readNews();
sportNews.newContext("湖人:火箭 102:103");
xiaoLi.readNews();
xiaoMin.readNews();
robot.readNews();
}
}
print:
I am xiao li,I am looking H:F 1:1
I am xiao min,I am looking H:F 1:1
Robot:0,Context:H:F 1:1
I am xiao li,I am looking 湖人:火箭 102:103
I am xiao min,I am looking 湖人:火箭 102:103
Robot:0,Context:湖人:火箭 102:103
上面的代码展示了xiaoli、xiaomin、Robot是怎样获取新的新闻内容的,每个人都需要调用 readNews 才可以获取新的新闻内容。如果再增加一个人,那么这个人也需要调用相应的方法才可以获取。这就相当于每个人都知道报社的地址,每天都要去报社自己拿新的报纸。那么怎样才能改变这样的关系,让人不需要去报社拿新的报纸,那就是使用观察这模式,下面就让我们来具体的介绍这个模式。
介绍Observser
- 定义: 定义对象之间一对多的关系,当一个对象的状态发生改变时,该对象所有依赖对象都会得到通知。
- 类图:

从上面的类图中可以总结一下几点:
- 抽象主题类(Observable):持有一个 Observer 的集合List,通过 registerObserver 方法可以将 Observer 注册到集合中。通过 notifyServers 方法可以让所有在集合里面的 Observer 都获得通知
- 抽象观察者类(Observer):持有一个 Observable ,其目的是为了在 Observable 的集合中取消订阅。而注册行为是发生在构造函数中
具体主题类(ConcreteObservable):继承了 Observable ,并且实现了父类的抽象方法 changeState ,在该方法中调用了父类的方法 notifyObservers
- 具体观察者类(ConcreteObserver):继承了 Observer ,并且实现了父类的方法 update 方法,该方法是具体观察者要做的动作
重构思考题
通过上面的学习,我们已经基本上了解了观察者模式了,下面我们针对上面提到的问题,使用观察者模式来实现它:
首先,我们定义一个抽象主题类:
Subject.java:
import java.util.List;
import java.util.ArrayList; public abstract class Subject {
protected List<Observer> observers; public Subject() {
observers = new ArrayList<Observer>();
} public boolean registerObserver(Observer observer) {
return observers.add(observer);
} public boolean removeObserver(Observer observer) {
return observers.remove(observer);
} public void notifyObservers(String context) {
for(Observer observer: observers) {
observer.update(context);
}
} public abstract void newContext(String context);
}
然后,我们来实现抽象观察者:
Observer.java:
public abstract class Observer {
private Subject subject;
public Observer(Subject subject) {
this.subject = subject;
subject.registerObserver(this);
}
public abstract void update(String context);
}
之后,实现一个具体主题类:
SportNews.java:
public class SportNews extends Subject {
@Override
public void newContext(String context) {
notifyObservers(String.format("sport news:%s", context));
}
}
最后,实现具体观察者类:
People.java:
public class People extends Observer {
private final String name;
public People(String name, Subject subject) {
super(subject);
this.name = name;
}
@Override
public void update(String context) {
System.out.println(String.format("I am %s,I am looking %s", name, context));
}
}
Robot.java:
public class Robot extends Observer {
private static int num = 0;
private final int id = num++;
public Robot(Subject subject) {
super(subject);
}
@Override
public void update(String context) {
System.out.println(String.format("Robot:%s,Context:%s", id, context));
}
}
测试用例:
TestMain.java:
public class TestMain {
public static void main(String... ars) {
Subject subject = new SportNews();
People xiaoLi = new People("xiao li", subject);
People xiaoMin = new People("xiao min", subject);
Robot robot = new Robot(subject);
subject.newContext("H:F 1:1");
subject.newContext("湖人:火箭 102:103");
}
}
以上就是观察者模式的全部代码,通过使用观察者模式,可以看出我们只需要将观察者注册到主题中。不需要调用观察者的任何方法,就可以自动的获得通知。极大的减少了代码量和维护成本。这就相当于你只要订阅了报纸,每天都会有人给你送过去,而不需要自己去报社拿。
扩展
在我们的java中也定义了观察者模式的接口,并且Java中的事件监听机制就是使用观察者模式实现的,它们分别是 java.util.Observer 和 java.util.Observable 。通过实现这两个接口我们可以实现自己的观察者模式,下面就让我们来看看这两个类。
类图:

简单介绍下上面的类图:
- 抽象主题类(Observable): addObserver 是用来注册观察者的。 notifyObservers 是用来通知所有的观察者的。 setChanged 是用来告知 notifyObservers 状态已经改变,可以通知了。其他的就不做介绍了。
下面让我们使用java提供的观察者模式接口来实现上面的问题:
People.java:
import java.util.Observer;
import java.util.Observable;
public class People implements Observer {
private final String name;
private Observable observable;
public People(String name, Observable o) {
this.name = name;
observable = o;
observable.addObserver(this);
} @Override
public void update(Observable o, Object arg) {
System.out.println(String.format("I am %s,I am looking %s", name, arg.toString()));
}
}
Robot.java:
import java.util.Observer;
import java.util.Observable; public class Robot implements Observer {
private static int num = 0;
private final int id = num++;
private Observable observable; public Robot(Observable observable) {
this.observable = observable;
observable.addObserver(this);
} @Override
public void update(Observable o, Object arg) {
System.out.println(String.format("Robot:%s,Context:%s", id, arg.toString()));
}
}
SportNews.java:
import java.util.Observable;
public class SportNews extends Observable {
public void newContext(String context) {
setChanged();
notifyObservers(context);
}
}
测试用例:
TestMain.java:
public class TestMain {
public static void main(String... ars) {
SportNews sportNews = new SportNews();
People xiaoLi = new People("xiao li", sportNews);
People xiaoMin = new People("xiao min", sportNews);
Robot robot = new Robot(sportNews);
sportNews.newContext("H:F 1:1");
sportNews.newContext("湖人:火箭 102:103");
}
}
以上是本博客的全部内容,希望看完会对你有一定的启发。
[design pattern](2) Observer的更多相关文章
- Design Pattern: Observer Pattern
1. Brief 一直对Observer Pattern和Pub/Sub Pattern有所混淆,下面打算通过这两篇Blog来梳理这两种模式.若有纰漏请大家指正. 2. Use Case 首先我们来面 ...
- Learning JavaScript Design Patterns The Observer Pattern
The Observer Pattern The Observer is a design pattern where an object (known as a subject) maintains ...
- 说说设计模式~大话目录(Design Pattern)
回到占占推荐博客索引 设计模式(Design pattern)与其它知识不同,它没有华丽的外表,没有吸引人的工具去实现,它是一种心法,一种内功,如果你希望在软件开发领域有一种新的突破,一个质的飞越,那 ...
- [转]Design Pattern Interview Questions - Part 4
Bridge Pattern, Composite Pattern, Decorator Pattern, Facade Pattern, COR Pattern, Proxy Pattern, te ...
- [转]Design Pattern Interview Questions - Part 2
Interpeter , Iterator , Mediator , Memento and Observer design patterns. (I) what is Interpreter pat ...
- [转]Design Pattern Interview Questions - Part 1
Factory, Abstract factory, prototype pattern (B) What are design patterns? (A) Can you explain facto ...
- C++ Design Pattern: What is a Design Pattern?
Q: What is a Design Pattern? A: Design Patterns represent solutions to problems what arise when deve ...
- Design Pattern in Simple Examples
Instead of defining what is design pattern lets define what we mean by design and what we mean by pa ...
- java设计模式大全 Design pattern samples in Java(最经典最全的资料)
java设计模式大全 Design pattern samples in Java(最经典最全的资料) 2015年06月19日 13:10:58 阅读数:11100 Design pattern sa ...
随机推荐
- Centos7安装protobuf3.6.1
简介 最近学习go语言,需要安装protobuf,但是网上的教程很多都不太适用于centos7 的系统.现在总结下protobuf在centos7下的安装教程. protobuf是Google开发出来 ...
- Cassandra视图
一.简介 Cassandra作为一个P2P结构的NOSQL数据库,使用与HBase不同的去中心化架构,在国外使用非常广泛,受欢迎程度甚至在Hbase之上.今天这篇文章介绍Cassandra在视图方面设 ...
- Dubbo原理学习
Dubbo源码及原理学习 阿里中间件团队博客 Dubbo官网 Dubbo源码解析 Dubbo源码解析-掘金 Dubbo源码解析-赵计刚 Dubbo系列 源码总结+最近感悟
- P1141零一迷宫
这是一道对于除了我之外其他人都十分简单的搜索题,我终于在这个夜里搞会了. 首先其问可以到达多少个点,并不是走一次可以最多经过几个点,这就解释了为什么不需要回溯,并且递归边界则是让其全部走完即可.于是便 ...
- java体系中OOP,OOD,OOA分别代表什么含义,以及OA,CRM,ERP
OOP:Object Oriented Programming 面向对象程序设计. OOD:Object Oriented Design 面向对象设计. OOA:Object Oriented Ana ...
- Java JPA设置默认值、Timestamp设置、自动获取时间
设置默认值 @Column(name="state",columnDefinition="tinyint default 0") private Integer ...
- jquery遍历标签中自定义的属性方法
在开发中我们有时会对html标签添加属性,如何遍历处理 <ul> <li name="li1" sortid="nav_1">aaaaa ...
- 利用 TCMalloc 优化 Nginx 的性能
TCMalloc 全称为 Thread-Caching Malloc,是谷歌的开源工具 google-perftools 的成员,它可以 在内存分配效率和速度上高很多,可以很大程度提高服务器在高并发情 ...
- SQL SERVER BCP导入导出
bcp是SQL Server中负责导入导出数据的一个命令行工具,它是基于DB-Library的,并且能以并行的方式高效地导入导出大批量的数据.bcp可以将数据库的表或视图直接导出,也能通过SELECT ...
- jupyter notebook添加环境
列出当前kernel: jupyter kernelspec list 删除已有环境:jupyter kernelspec remove NAME 安装新kernel ipython kernel i ...