欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

如何實現(xiàn)觀察者模式及Spring中的事件編程模型

這篇“如何實現(xiàn)觀察者模式及Spring中的事件編程模型”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“如何實現(xiàn)觀察者模式及Spring中的事件編程模型”文章吧。

成都創(chuàng)新互聯(lián)專業(yè)提供成都主機托管四川主機托管成都服務(wù)器托管四川服務(wù)器托管,支持按月付款!我們的承諾:貴族品質(zhì)、平民價格,機房位于中國電信/網(wǎng)通/移動機房,西部信息服務(wù)器租用服務(wù)有保障!

什么是觀察者模式

在現(xiàn)實生活中,觀察者模式處處可見,比如

看新聞,只要新聞開始播放了,就會把新聞推送給訂閱了新聞的用戶,在這里,新聞就是【被觀察者】,而用戶就是【觀察者】。

微信公眾號,如果一個用戶訂閱了某個公眾號,那么便會收到公眾號發(fā)來的消息,那么,公眾號就是【被觀察者】,而用戶就是【觀察者】。

熱水器,假設(shè)熱水器由三部分組成,熱水器,警報器,顯示器,熱水器僅僅負責(zé)燒水,當(dāng)水溫到達設(shè)定的溫度后,通知警報器,警報器發(fā)出警報,顯示器也需要訂閱熱水器的燒水事件,從而獲得水溫,并顯示。熱水器就是【被觀察者】,警報器,顯示器就是【觀察者】。

在這里,可以看到,【觀察者】已經(jīng)失去自主的權(quán)利,只能被動的接收來自【被觀察者】的事件,無法主動觀察?!居^察者】成為了“受”,而【被觀察者】成為了“攻”?!颈挥^察者】只是通知【觀察者】,不關(guān)心【觀察者】收到通知后,會執(zhí)行怎樣的動作。

而在設(shè)計模式中,又把【被觀察者】稱為【主題】。

在觀察者設(shè)計模式中,一般有四個角色:

抽象主題角色(Subject)

具體主題角色(ConcreteSubject)

抽象觀察者角色(Observer)

具體觀察者角色(ConcreteObserver)

其中,【主題】需要有一個列表字段,用來保存【觀察者】的引用,提供兩個方法(虛方法),即【刪除觀察者】【增加觀察者】,還需要提供一個給客戶端調(diào)用的方法,通知各個【觀察者】:你們關(guān)心(訂閱)的事件已經(jīng)推送給你們了。

下面,我就用三種方式來實現(xiàn)觀察者模式。

經(jīng)典

public class News {

private String title;

private String content;

public String getTitle() {

return title;

}

public void setTitle(String title) {

this.title = title;

}

public String getContent() {

return content;

}

public void setContent(String content) {

this.content = content;

}

}

此類不屬于觀察者模式必須的類,用來存放事件的信息。

public interface Subject {

List<People> peopleList = new ArrayList<>();

default void add(People people) {

peopleList.add(people);

}

default void remove(People people) {

peopleList.remove(people);

}

void update();

}

抽象主題角色,在這個角色中,有一個字段peopleList,用來保存【觀察者】的引用,同時定義了兩個接口,這是Java8默認接口實現(xiàn)的寫法。這兩個接口是給客戶端調(diào)用的,用來【刪除觀察者】【增加觀察者】,還提供一個方法,此方法需要被【具體主題角色】重寫,用來通知各個【觀察者】。

public class NewsSubject implements Subject{

public void update() {

for (People people : peopleList) {

News news = new News();

news.setContent("今日在大街上,有人躲在草叢中襲擊路人,還大喊“德瑪西亞萬歲”");

news.setTitle("德瑪西亞出現(xiàn)了");

people.update(news);

}

}

}

具體主題角色,重寫了【抽象主題角色】的方法,循環(huán)列表,通知各個【觀察者】。

public interface People {

void update(News news);

}

抽象觀察者角色,定義了一個接口,【具體觀察者角色】需要重寫這個方法。

下面就是【具體觀察者角色】了:

public class PeopleA implements People {

@Override

public void update(News news) {

System.out.println("這個新聞?wù)婧每?quot;);

}

}

public class PeopleB implements People {

@Override

public void update(News news) {

System.out.println("這個新聞?wù)鏌o語");

}

}

public class PeopleC implements People {

@Override

public void update(News news) {

System.out.println("這個新聞?wù)娑?quot;);

}

}

客戶端:

public class Main {

public static void main(String[] args) {

Subject subject = new NewsSubject();

subject.add(new PeopleA());

subject.add(new PeopleB());

subject.add(new PeopleC());

subject.update();

}

}

運行:

我們學(xué)習(xí)設(shè)計模式,必須知道設(shè)計模式的優(yōu)缺點,那么觀察者設(shè)計模式的優(yōu)缺點是什么呢?

優(yōu)點:

【主題】和【觀察者】通過抽象,建立了一個松耦合的關(guān)系,【主題】只知道當(dāng)前有哪些【觀察者】,并且發(fā)送通知,但是不知道【觀察者】具體會執(zhí)行怎樣的動作。這也很好理解,比如 微信公眾號推送了一個消息過來,它不知道你會采取如何的動作,是 微笑的打開,還是憤怒的打開,或者是直接把消息刪了,又或者把手機扔到洗衣機洗刷刷。

符合開閉原則,如果需要新增一個【觀察者】,只需要寫一個類去實現(xiàn)【抽象觀察者角色】即可,不需要改動原來的代碼。

缺點:

客戶端必須知道所有的【觀察者】,并且進行【增加觀察者】和【刪除觀察者】的操作。

如果有很多【觀察者】,那么所有的【觀察者】收到通知,可能需要花費很久時間。

當(dāng)然以上優(yōu)缺點,是最直觀的,可以很容易理解,并且體會到的。其他優(yōu)缺點,可以自行百度。

Lambda

在介紹這種寫法之前,有必要介紹下函數(shù)式接口,函數(shù)式接口的概念由來已久,一般來說只定義了一個虛方法的接口就叫函數(shù)式接口,在Java8中,由于Lambda表達式的出現(xiàn),讓函數(shù)式接口大放異彩。

我們僅僅需要修改客戶端的代碼就可以:

public static void main(String[] args) {

Subject subject = new NewsSubject();

subject.add(a -> System.out.println("已閱這新聞"));

subject.add(a -> System.out.println("假的吧"));

subject.add(a -> System.out.println("昨天就看過了"));

subject.update();

}

運行結(jié)果:

利用Lambda表達式和函數(shù)式接口,可以省去【具體觀察者角色】的定義,但是個人認為,這并非屬于嚴格意義上的觀察者模式,而且弊端很明顯:

客戶端需要知道觀察者的具體實現(xiàn)。

如果觀察者的具體實現(xiàn)比較復(fù)雜,可能代碼并沒有那么清晰。

所以這種寫法,具有一定的局限性。

借用大神的一句話

設(shè)計模式的出現(xiàn),是為了彌補語言的缺陷。

正是由于語言的升級,讓某些設(shè)計模式發(fā)生了一定的變化,除了觀察者模式,還有模板方法模式、責(zé)任鏈模式等,都由于 Lambda表達式的出現(xiàn),而出現(xiàn)了一些變化。

JDK

在Java中,本身就提供了一個接口:Observer,一個子類:Observable,其中Observer表示【觀察者】,Observable表示【主題】,可以利用這兩個子類和接口來實現(xiàn)觀察者模式:

public class NewsObservable extends Observable {

public void update() {

setChanged();

notifyObservers();

}

}

public class People1 implements Observer {

@Override

public void update(Observable o, Object arg) {

System.out.println("小編真無聊");

}

}

public class People2 implements Observer {

@Override

public void update(Observable o, Object arg) {

System.out.println("開局一張圖,內(nèi)容全靠編");

}

}

客戶端:

public static void main(String[] args) {

NewsObservable newsObservable = new NewsObservable();

newsObservable.addObserver(new People1());

newsObservable.addObserver(new People2());

newsObservable.update();

}

運行結(jié)果:

在這里,我不打算詳細介紹這種實現(xiàn)方式,因為從Java9開始,Java已經(jīng)不推薦這種寫法了,而推薦用消息隊列來實現(xiàn)。是不是很開心,找到一個借口不去研究Observable,Observer 這兩個東西了。

Spring中的事件編程模型

Spring中的事件編程模型就是觀察者模式的實現(xiàn),SpringBoot就利用了Spring的事件編程模型來完成一些操作,這里暫時不表。

在Spring中定義了一個ApplicationListener接口,從名字就知道它是一個監(jiān)聽器,是監(jiān)聽Application的事件的,那么Application又是什么,就是ApplicationContext,ApplicationContext內(nèi)置了幾個事件,其中比較容易理解的是:

ContextRefreshedEvent

ContextStartedEvent

ContextStoppedEvent

ContextClosedEvent

從名稱上來看,就知道這幾個事件是什么時候被觸發(fā)的了。

下面我演示下具體的用法,比如我想監(jiān)聽ContextRefreshedEvent事件,如果事件發(fā)生了,就打印一句話。

@Component

public class MyListener implements ApplicationListener{

@Override

public void onApplicationEvent(ApplicationEvent applicationEvent) {

if(applicationEvent  instanceof ContextRefreshedEvent){

System.out.println("刷新了");

}

}

}

@Configuration

@ComponentScan

public class AppConfig {

}

public static void main(String[] args) {

AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);

}

運行結(jié)果:

當(dāng)時學(xué)習(xí)Spring,看到Spring提供了各式各樣的接口來讓程序員們對Spring進行擴展,并且沒有任何侵入性,我不得不佩服Spring的開發(fā)者們。這里也是,我們可以看到在客戶端找不到任何關(guān)于“訂閱事件”的影子。

這種實現(xiàn)方式不是太好,可以看到我們在方法內(nèi)部做了一個判斷:接收到的事件是否為ContextRefreshedEvent。

偉大的Spring還提供了泛型的ApplicationListener,我們可以通過泛型的ApplicationListener來完善上面的代碼:

@Component

public class MyListener implements ApplicationListener<ContextRefreshedEvent> {

@Override

public void onApplicationEvent(ContextRefreshedEvent event) {

System.out.println("刷新了");

}

}

我們還可以利用Spring中的事件編程模型來自定義事件,并且發(fā)布事件:

首先,我們需要定義一個事件,來實現(xiàn)ApplicationEvent接口,代表這是一個Application事件,其實上面所說的四個內(nèi)置的事件也實現(xiàn)了ApplicationEvent接口:

public class MyEvent extends ApplicationEvent {

public MyEvent(Object source) {

super(source);

}

}

還需要定義一個監(jiān)聽器,當(dāng)然,在這里需要監(jiān)聽MyEvent事件:

@Component

public class MyListener implements ApplicationListener<MyEvent> {

@Override

public void onApplicationEvent(MyEvent event) {

System.out.println("我訂閱的事件已經(jīng)到達");

}

}

現(xiàn)在有了事件,也有了監(jiān)聽器,是不是還少了發(fā)布者,不然誰去發(fā)布事件呢?

@Component

public class MyEventPublish implements ApplicationEventPublisherAware {

private ApplicationEventPublisher publisher;

@Override

public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

this.publisher = applicationEventPublisher;

}

public void publish(Object obj) {

this.publisher.publishEvent(obj);

}

}

發(fā)布者,需要實現(xiàn)ApplicationEventPublisherAware 接口,重寫publish方法,顧名思義,這就是發(fā)布方法,那么方法的參數(shù)obj是干嘛的呢,作為發(fā)布者,應(yīng)該需要知道我要發(fā)布什么事件,以及事件來源(是誰觸發(fā)的)把,這個obj就是用來存放這樣的數(shù)據(jù)的,當(dāng)然,這個參數(shù)需要我們手動傳入進去。setApplicationEventPublisher是Spring內(nèi)部主動調(diào)用的,可以簡單的理解為初始化發(fā)布者。

現(xiàn)在就剩最后一個角色了,監(jiān)聽器有了,發(fā)布者有了,事件也有了,對,沒錯,還少一個觸發(fā)者,畢竟要有觸發(fā)者去觸發(fā)事件?。?/p>

@Component

public class Service {

@Autowired

private  MyEventPublish publish;

public void publish() {

publish.publish(new MyEvent(this));

}

}

其中publish方法就是給客戶端調(diào)用的,用來觸發(fā)事件,可以很清楚的看到傳入了new MyEvent(this),這樣發(fā)布者就可以知道我要觸發(fā)什么事件和是誰觸發(fā)了事件。

當(dāng)然,還需要把一切交給Spring管理:

@Configuration

@ComponentScan

public class AppConfig {

}

客戶端:

public static void main(String[] args) {

AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);

context.getBean(Service.class)。publish();;

}

以上就是關(guān)于“如何實現(xiàn)觀察者模式及Spring中的事件編程模型”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)站題目:如何實現(xiàn)觀察者模式及Spring中的事件編程模型
標(biāo)題鏈接:http://aaarwkj.com/article28/ijhicp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、域名注冊、網(wǎng)站策劃、Google、虛擬主機定制開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站
日本高清加勒比免费在线| 欧美大片免费在线播放| 人妻少妇中文字幕在线播放| 免费黄片视频大全在线播放| 精品国产乱码一区二区三区四区| 97超频在线观看免费| 一区二区三区在线观看日本视频| 亚洲精品国产熟女av| 亚洲男人天堂中文字幕| 在线免费观看日本91| 熟妇激情欧美在线播放视频| 97成人在线免费视频| 伊人色综合久久天天五月婷| 欧美精品国产亚洲另类| 中文字幕黄色三级视频| 日日躁夜夜躁久久狠狠躁| 久久精品91久久久| 久久精品人妻少妇一区二| 亚洲男女尻逼片视频网站| 在线中文字幕日韩有码| 亚洲激情视频久久精品| 国产福利三级在线观看| 中文字幕一区二区不卡顿| 熟妇人妻中文字幕在线| 日本精品在线小视频| 欧美欧成人一区二区三区a∨| 成人短篇在线视频夫妻刺激自拍| 日韩精品一区三区二区| 精品国产不卡在线观看| 亚洲天堂av在线播放| 亚洲黄色艳情视频录像| 精品中文人妻中文字幕| 开裆丝袜高跟啪啪高潮av| 日韩亚洲中文一区三级黄片| 性色乱码一区二区三区| 欧美日韩亚洲激情一区| 人妻av在线中文字幕| 五月婷婷少妇中文字幕| 日韩高清在线一区二区三区| 欧美日本黄色一级视频| 国产成人综合亚洲国产|