观察者模式(Obsever)
主要用到的知识点:
1.面向对象的设计思想(类 对象)
2.*类和类之间的关系
- a is-a b 泛化(继承 实现)
继承父类 实现接口
- a has-a b 包含(组合 聚合 关联)
一个类对象中存有另一个类对象作为属性
- a use-a b 依赖 (need-a)
一个类对象中有一个方法 使用到另外一个类对象(参数 方法内部创建)
设计一个小案例:体现报社和读者之间的关系
报社–>发报纸
读者–>读报纸
我们先从现实生活的角度出发,去理解这个过程:报社是读者吗?不是;报社包含读者吗?也不是;那只能是 use-a 的依赖关系,即报社依赖读者,读者也依赖报社。
/**
* 这个类是用来描述报社的
*/
public class Baoshe {
private String name;
public Baoshe(String name){
this.name = name;
}
public String getName() {
return name;
}
//生产和刊发报纸
public NewsPaper sendPaper(){
System.out.println(this.name+"发报纸了");
/*这里隐藏了一个关系:报社类使用到了报纸类,报社类依赖报纸类。报纸和报社---->依赖关系。
*这种使用关系是偶然性的、临时性的、非常弱的一种关系。
*(当然也可以是has-a的关系,你可以认为报纸是报社的一部分,而把报纸作为报社的一个属性。)
*/
NewsPaper paper = new NewsPaper("人民日报");
return paper;
}
}
/**
* 这个类是用来描述报纸的类
*/
public class NewsPaper {
//属性
//价格
//日期·······省略了
private String name;
public NewsPaper(String name){
this.name = name;
}
public NewsPaper(){}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public abstract class Reader {
public abstract void readPaper(Baoshe bs);
}
/**
* 这个类是用来描述读者的类
*/
public class ReaderOne extends Reader {
private String name;
public ReaderOne(String name){
this.name = name;
}
//读报纸
public void readPaper(Baoshe bs){
/* 依赖关系:
* 读者类里面的方法参数使用到了报社类,即他们是use-a的依赖关系
*/
//正常情况下,参数传报纸更合理,这里为了简单,不把问题搞得那么复杂
//先获取报纸
NewsPaper paper = bs.sendPaper();
//读报纸
System.out.println(this.name+"读了"+bs.getName()+"报社的"+paper.getName()+"的报纸");
}
}
public class ReaderTwo extends Reader{
private String name;
public ReaderTwo(String name){
this.name = name;
}
public void readPaper(Baoshe bs){
NewsPaper paper = bs.sendPaper();
System.out.println(this.name+"就不读"+bs.getName()+"报社的"+paper.getName()+"的报纸");
}
}
public class ReaderThree extends Reader{
private String name;
public ReaderThree(String name){
this.name = name;
}
public void readPaper(Baoshe bs){
NewsPaper paper = bs.sendPaper();
System.out.println(this.name+"看心情读"+bs.getName()+"报社的"+paper.getName()+"的报纸");
}
}
/**
*测试
*/
public class Test {
//高内聚,低耦合
//高内聚(设计一个类的时候,类中的功能不能是别人做的)
//低耦合(设计一个类的时候,类关系尽量是松弛的)
public static void main(String[] args) {
Baoshe bs = new Baoshe("新华社");
ReaderOne one = new ReaderOne("读者甲");
ReaderTwo two = new ReaderTwo("读者乙");
ReaderThree three = new ReaderThree("读者丙");
//谁类做事?
//读者来做事情
one.readPaper(bs);
two.readPaper(bs);
three.readPaper(bs);
}
}
分析
代码写完了,没有用到观察者设计模式,我们来分析以下有没有什么不好的地方:
- 好多个读者需要创建,很繁琐。这个问题,目前为止处理不了,工厂模式也处理不了,因为工厂制造出来的东西都一样,没啥区别,但是读者的这个对象,你会发现每个读者都不一样,有它的个性,差别太大。
要处理这个问题,以后可以通过IOC的设计思想解决。
IOC控制反转,对象不需要我们创建,让别人帮我们创建好(对象的控制权交给别人去处理)
要想在对象创建的同时,把属性自动注入进入,这叫DI
DI(依赖注入) IOC(控制反转)
AOP基础可以实现 Filter(JavaWEB , 过滤器 , 动态代理)
spring 的两大核心:spring(IOC–DI,AOP)
- 每一个对象都要主动做事情,太麻烦。这个问题正是观察者模式将要解决的。
现实生活中,报社有几个,读者有几个
新华社?一个
读者?多个(多个人,多种类型)
目标对象:报社(一个)
观察者:读者(一堆)
观察者模式:一个对象做事情,一堆对象自动跟着做事情!
由于读者对象可能有很多个,设想假如有100个读者,就要创建100个读者对象,调用100次方法。让读者(也就是多的这一方)主动做事情,事情就变得很麻烦。
如果能让报社(少的一端)主动做事情,事情就变得简单了。
理清关系以后,需要改变以下类的设计。
我们的主要思路是,能否把主动方进行一个扭转,让报社去做事情。
刚才:读者和报社—>依赖关系(use-a)
改变思想:读者(观察者)时刻观察报社(目标)
现在:读者和报社—>包含关系(has-a)
从use-a 改成 has -a ,把读者当作属性,报社包含读者。
意思是,报社中存有好多个读者。
观察者模式实现步骤
- 目标对象中存有很多个观察者
- 设计一个方法,添加/删除 观察者。
- 让目标对象做事情(通常是观察者感兴趣的)
- 通知所有的观察者去做自己该做的事情
观察者模式实现代码:
报社类:
import java.util.ArrayList;
/**
* 这个类是用来描述报社的
*/
public class Baoshe {
private String name;
public Baoshe(String name){
this.name = name;
}
public String getName() {
return name;
}
//===================================
// 1。改变报社和读者的关系
private ArrayList<Reader> observers = new ArrayList<>();
//2.集合里面是没有读者的,
//设计一个方法,目的是添加读者
public void addObserver(Reader reader){
this.observers.add(reader);
}
public void removeObserver(Reader reader){
this.observers.remove(reader);
}
//4.通知所有的观察者做自己该做的事
public void notifyObservers(NewsPaper paper){
for(Reader reader:observers){
reader.readPaper(this,paper);
}
}
//=====================================
//生产和刊发报纸
public NewsPaper sendPaper(){
System.out.println(this.name+"发报纸了");
NewsPaper paper = new NewsPaper("人民日报");
//3. 让目标对象做事情(通常是观察者感兴趣的)
//==============================
this.notifyObservers(paper);//通知观察者
//==============================
return paper;
}
}
报纸类(跟上面那个一样):
/**
* 这个类是用来描述报纸的类
*/
public class NewsPaper {
//属性
//价格
//日期·······省略了
private String name;
public NewsPaper(String name){
this.name = name;
}
public NewsPaper(){}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
读者的抽象类:
public abstract class Reader {
public abstract void readPaper(Baoshe bs,NewsPaper paper);
}
三个不同个性的读者类:
/**
* 这个类是用来描述读者的类
*/
public class ReaderOne extends Reader {
private String name;
public ReaderOne(String name){
this.name = name;
}
@Override
public void readPaper(Baoshe bs,NewsPaper paper){
System.out.println(this.name+"读了"+bs.getName()+"报社的"+paper.getName()+"的报纸");
}
}
package observer;
/**
* 这个类是用来描述读者的类
*/
public class ReaderTwo extends Reader {
private String name;
public ReaderTwo(String name) {
this.name = name;
}
@Override
public void readPaper(Baoshe bs, NewsPaper paper) {
System.out.println(this.name + "就不读" + bs.getName() + "报社的" + paper.getName() + "的报纸");
}
}
package observer;
/**
* 这个类是用来描述读者的类
*/
public class ReaderThree extends Reader {
private String name;
public ReaderThree(String name) {
this.name = name;
}
@Override
public void readPaper(Baoshe bs, NewsPaper paper) {
System.out.println(this.name + "看心情读" + bs.getName() + "报社的" + paper.getName() + "的报纸");
}
}
测试类:
/**
*测试
*/
public class Test {
public static void main(String[] args) {
Baoshe bs = new Baoshe("新华社");
ReaderOne one = new ReaderOne("读者甲");
ReaderTwo two = new ReaderTwo("读者乙");
ReaderThree three = new ReaderThree("读者丙");
bs.addObserver(one);
bs.addObserver(two);
bs.addObserver(three);
//=================================
bs.sendPaper();
}
}