觀察者模式

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

在這裏插入圖片描述

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