观察者模式

观察者模式(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);
	}
}

在这里插入图片描述

分析

代码写完了,没有用到观察者设计模式,我们来分析以下有没有什么不好的地方:

  1. 好多个读者需要创建,很繁琐。这个问题,目前为止处理不了,工厂模式也处理不了,因为工厂制造出来的东西都一样,没啥区别,但是读者的这个对象,你会发现每个读者都不一样,有它的个性,差别太大。

要处理这个问题,以后可以通过IOC的设计思想解决。
IOC控制反转,对象不需要我们创建,让别人帮我们创建好(对象的控制权交给别人去处理)
要想在对象创建的同时,把属性自动注入进入,这叫DI
DI(依赖注入) IOC(控制反转)
AOP基础可以实现 Filter(JavaWEB , 过滤器 , 动态代理)
spring 的两大核心:spring(IOC–DI,AOP)

  1. 每一个对象都要主动做事情,太麻烦。这个问题正是观察者模式将要解决的。

现实生活中,报社有几个,读者有几个
新华社?一个
读者?多个(多个人,多种类型)
目标对象:报社(一个)
观察者:读者(一堆)

观察者模式:一个对象做事情,一堆对象自动跟着做事情!
由于读者对象可能有很多个,设想假如有100个读者,就要创建100个读者对象,调用100次方法。让读者(也就是多的这一方)主动做事情,事情就变得很麻烦。
如果能让报社(少的一端)主动做事情,事情就变得简单了。
理清关系以后,需要改变以下类的设计。
我们的主要思路是,能否把主动方进行一个扭转,让报社去做事情

刚才:读者和报社—>依赖关系(use-a)
改变思想:读者(观察者)时刻观察报社(目标)
现在:读者和报社—>包含关系(has-a)

从use-a 改成 has -a ,把读者当作属性,报社包含读者。
意思是,报社中存有好多个读者。

观察者模式实现步骤

  1. 目标对象中存有很多个观察者
  2. 设计一个方法,添加/删除 观察者。
  3. 让目标对象做事情(通常是观察者感兴趣的)
  4. 通知所有的观察者去做自己该做的事情

观察者模式实现代码:
报社类:

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();
	}
}

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章