線程安全與觀察者模式(Observer)

觀察者模式的定義與特點(diǎn):

觀察者(Observer)模式的定義:指多個(gè)對(duì)象間存在一對(duì)多的依賴(lài)關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對(duì)象都得到通知并被自動(dòng)更新。這種模式有時(shí)又稱(chēng)作發(fā)布-訂閱模式、模型-視圖模式,它是對(duì)象行為型模式。

觀察者模式是一種對(duì)象行為型模式,其主要優(yōu)點(diǎn)如下:

1. 降低了目標(biāo)與觀察者之間的耦合關(guān)系,兩者之間是抽象耦合關(guān)系。

2. 目標(biāo)與觀察者之間建立了一套觸發(fā)機(jī)制。

它的主要缺點(diǎn)如下:

1. 目標(biāo)與觀察者之間的依賴(lài)關(guān)系并沒(méi)有完全解除,而且有可能出現(xiàn)循環(huán)引用。

2. 當(dāng)觀察者對(duì)象很多時(shí),通知的發(fā)布會(huì)花費(fèi)很多時(shí)間,影響程序的效率。

結(jié)合實(shí)際生活中的例子理解觀察者模式:

在現(xiàn)實(shí)世界中,許多對(duì)象并不是獨(dú)立存在的,其中一個(gè)對(duì)象的行為發(fā)生改變可能會(huì)導(dǎo)致一個(gè)或者多個(gè)其他對(duì)象的行為也發(fā)生改變。例如,某種商品的物價(jià)上漲時(shí)會(huì)導(dǎo)致部分商家高興,而消費(fèi)者傷心;還有,當(dāng)我們開(kāi)車(chē)到交叉路口時(shí),遇到紅燈會(huì)停,遇到綠燈會(huì)行。這樣的例子還有很多,例如,股票價(jià)格與股民、微信公眾號(hào)與微信用戶(hù)、氣象局的天氣預(yù)報(bào)與聽(tīng)眾、小偷與警察等。

在軟件世界也是這樣,例如,Excel 中的數(shù)據(jù)與折線圖、餅狀圖、柱狀圖之間的關(guān)系;MVC 模式中的模型與視圖的關(guān)系;事件模型中的事件源與事件處理者。所有這些,如果用觀察者模式來(lái)實(shí)現(xiàn)就非常方便。

模式的結(jié)構(gòu)與實(shí)現(xiàn):

實(shí)現(xiàn)觀察者模式時(shí)要注意具體目標(biāo)對(duì)象和具體觀察者對(duì)象之間不能直接調(diào)用,否則將使兩者之間緊密耦合起來(lái),這違反了面向?qū)ο蟮脑O(shè)計(jì)原則。

1. 模式的結(jié)構(gòu)

觀察者模式的主要角色如下。

1. 抽象主題(Subject)角色:也叫抽象目標(biāo)類(lèi),它提供了一個(gè)用于保存觀察者對(duì)象的聚集類(lèi)和增加、刪除觀察者對(duì)象的方法,以及通知所有觀察者的抽象方法。

2. 具體主題(Concrete??? Subject)角色:也叫具體目標(biāo)類(lèi),它實(shí)現(xiàn)抽象目標(biāo)中的通知方法,當(dāng)具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),通知所有注冊(cè)過(guò)的觀察者對(duì)象。

3. 抽象觀察者(Observer)角色:它是一個(gè)抽象類(lèi)或接口,它包含了一個(gè)更新自己的抽象方法,當(dāng)接到具體主題的更改通知時(shí)被調(diào)用。

4. 具體觀察者(Concrete Observer)角色:實(shí)現(xiàn)抽象觀察者中定義的抽象方法,以便在得到目標(biāo)的更改通知時(shí)更新自身的狀態(tài)。

觀察者模式結(jié)構(gòu)圖如下:


2. 模式的代碼實(shí)現(xiàn)

```java

package observer;

import java.util.*;

public class ObserverPattern

{

? ? public static void main(String[] args)

? ? {

? ? ? ? Subject subject=new ConcreteSubject();

? ? ? ? Observer obs1=new ConcreteObserver1();

? ? ? ? Observer obs2=new ConcreteObserver2();

? ? ? ? subject.add(obs1);

? ? ? ? subject.add(obs2);

? ? ? ? subject.notifyObserver();

? ? }

}

//抽象目標(biāo)

abstract class Subject

{

? ? protected List<Observer> observers=new ArrayList<Observer>();?

? ? //增加觀察者方法

? ? public void add(Observer observer)

? ? {

? ? ? ? observers.add(observer);

? ? }? ?

? ? //刪除觀察者方法

? ? public void remove(Observer observer)

? ? {

? ? ? ? observers.remove(observer);

? ? }?

? ? public abstract void notifyObserver(); //通知觀察者方法

}

//具體目標(biāo)

class ConcreteSubject extends Subject

{

? ? public void notifyObserver()

? ? {

? ? ? ? System.out.println("具體目標(biāo)發(fā)生改變...");

? ? ? ? System.out.println("--------------");? ? ?


? ? ? ? for(Object obs:observers)

? ? ? ? {

? ? ? ? ? ? ((Observer)obs).response();

? ? ? ? }


? ? }? ? ? ? ?

}

//抽象觀察者

interface Observer

{

? ? void response(); //反應(yīng)

}

//具體觀察者1

class ConcreteObserver1 implements Observer

{

? ? public void response()

? ? {

? ? ? ? System.out.println("具體觀察者1作出反應(yīng)!");

? ? }

}

//具體觀察者1

class ConcreteObserver2 implements Observer

{

? ? public void response()

? ? {

? ? ? ? System.out.println("具體觀察者2作出反應(yīng)!");

? ? }

}

```

應(yīng)用實(shí)例:

利用 Observable 類(lèi)和 Observer 接口實(shí)現(xiàn)原油期貨的觀察者模式實(shí)例。

分析:當(dāng)原油價(jià)格上漲時(shí),空方傷心,多方局興;當(dāng)油價(jià)下跌時(shí),空方局興,多方傷心。本實(shí)例中的抽象目標(biāo)(Observable)類(lèi)在 Java 中已經(jīng)定義,可以直接定義其子類(lèi),即原油期貨(OilFutures)類(lèi),它是具體目標(biāo)類(lèi),該類(lèi)中定義一個(gè) SetPriCe(float price) 方法,當(dāng)原油數(shù)據(jù)發(fā)生變化時(shí)調(diào)用其父類(lèi)的 notifyObservers(Object arg) 方法來(lái)通知所有觀察者;另外,本實(shí)例中的抽象觀察者接口(Observer)在 Java 中已經(jīng)定義,只要定義其子類(lèi),即具體觀察者類(lèi)(包括多方類(lèi) Bull 和空方類(lèi) Bear),并實(shí)現(xiàn) update(Observable o,Object arg) 方法即可。原油期貨的觀察者模式實(shí)現(xiàn)結(jié)構(gòu)圖如下:

代碼實(shí)現(xiàn):

```java

package observer;

import java.util.Observer;

import java.util.Observable;

public class CrudeOilFutures

{

? ? public static void main(String[] args)

? ? {

? ? ? ? OilFutures oil=new OilFutures();

? ? ? ? Observer bull=new Bull(); //多方

? ? ? ? Observer bear=new Bear(); //空方

? ? ? ? oil.addObserver(bull);

? ? ? ? oil.addObserver(bear);

? ? ? ? oil.setPrice(10);

? ? ? ? oil.setPrice(-8);

? ? }

}

//具體目標(biāo)類(lèi):原油期貨

class OilFutures extends Observable

{

? ? private float price;?

? ? public float getPrice()

? ? {

? ? ? ? return this.price;

? ? }

? ? public void setPrice(float price)

? ? {

? ? ? ? super.setChanged() ;? //設(shè)置內(nèi)部標(biāo)志位,注明數(shù)據(jù)發(fā)生變化

? ? ? ? super.notifyObservers(price);? ? //通知觀察者價(jià)格改變了

? ? ? ? this.price=price ;

? ? }

}

//具體觀察者類(lèi):多方

class Bull implements Observer

{?

? ? public void update(Observable o,Object arg)

? ? {

? ? ? ? Float price=((Float)arg).floatValue();

? ? ? ? if(price>0)

? ? ? ? {

? ? ? ? ? ? System.out.println("油價(jià)上漲"+price+"元,多方高興了!");

? ? ? ? }

? ? ? ? else

? ? ? ? {

? ? ? ? ? ? System.out.println("油價(jià)下跌"+(-price)+"元,多方傷心了!");

? ? ? ? }

? ? }

}

//具體觀察者類(lèi):空方

class Bear implements Observer

{?

? ? public void update(Observable o,Object arg)

? ? {

? ? ? ? Float price=((Float)arg).floatValue();

? ? ? ? if(price>0)

? ? ? ? {

? ? ? ? ? ? System.out.println("油價(jià)上漲"+price+"元,空方傷心了!");

? ? ? ? }

? ? ? ? else

? ? ? ? {

? ? ? ? ? ? System.out.println("油價(jià)下跌"+(-price)+"元,空方高興了!");

? ? ? ? }

? ? }

}

```

觀察者模式在線程安全中的實(shí)際應(yīng)用--LogSystem:


說(shuō)明:

?Handler:? Log的處理方式

ConsoleHandler:輸出日志到控制臺(tái)中

FileHandler ? :輸出日志到指定文件中

MemoryHandler :輸出日志到內(nèi)存緩沖區(qū)中,當(dāng)一定的條件滿(mǎn)足的時(shí)候(如某種關(guān)鍵字的日志信息) ? ? ? ? ? ? ? ? ? ? ? ? 再將緩沖區(qū)中的日志輸出

SocketHandler :輸出日志到網(wǎng)絡(luò) socket 中

StreamHandler :輸出日志到輸入輸出流對(duì)象中

?Formatter:Log信息的格式化方式

?Filter:?Log過(guò)濾器的擴(kuò)展

?logging.properties:配置擴(kuò)展的信息

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容