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