最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Java如何優(yōu)雅的使用裝飾器模式

 更新時(shí)間:2022年09月14日 08:27:19   作者:指北君  
裝飾器設(shè)計(jì)模式大家肯定都聽說(shuō)過(guò),但是有沒(méi)有使用過(guò)呢,今天本君就跟大家分享一下裝飾器模式應(yīng)該如何使用,感興趣的小伙伴可以學(xué)習(xí)一下

什么是裝飾器模式

裝飾器模式(Decorator Pattern): 在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)象動(dòng)態(tài)的添加職責(zé);

感覺(jué)和繼承如出一轍,不改變父類,子類可拓展功能;

優(yōu)點(diǎn)

裝飾類和被裝飾類可以獨(dú)立發(fā)展,不會(huì)相互耦合

相比于繼承,更加的輕便、靈活

可以動(dòng)態(tài)擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能,不必修改原本代碼

缺點(diǎn)

會(huì)產(chǎn)生很多的裝飾類,增加了系統(tǒng)的復(fù)雜性。

這種比繼承更加靈活機(jī)動(dòng)的特性,也同時(shí)意味著裝飾模式比繼承易于出錯(cuò),排錯(cuò)也很困難,對(duì)于多次裝飾的對(duì)象,調(diào)試時(shí)尋找錯(cuò)誤可能需要逐級(jí)排查,較為繁瑣。

使用場(chǎng)景

對(duì)已有的目標(biāo)功能存在不足,需要增強(qiáng)時(shí),擴(kuò)展類的功能。

動(dòng)態(tài)增加功能,動(dòng)態(tài)撤銷

裝飾器模式和代理模式的區(qū)別

代理是全權(quán)代理,目標(biāo)根本不對(duì)外,全部由代理類來(lái)完成;裝飾是增強(qiáng),是輔助,目標(biāo)仍然可以自行對(duì)外提供服務(wù),裝飾器只起增強(qiáng)作用。

裝飾器模式強(qiáng)調(diào)的是:增強(qiáng)、新增行為;代理模式強(qiáng)調(diào)的是:對(duì)代理的對(duì)象施加控制,但不對(duì)對(duì)象本身的功能進(jìn)行增強(qiáng)。

裝飾器模式:生效的對(duì)象還是原本的對(duì)象;代理模式:生效的是新的對(duì)象(代理對(duì)象)

裝飾器和代理的區(qū)別

裝飾器的簡(jiǎn)單實(shí)現(xiàn)

場(chǎng)景:天氣太熱了,喝點(diǎn)兒冰水解解暑;加點(diǎn)兒檸檬片,讓果汁好喝點(diǎn)兒

先定義一個(gè)喝水的接口

public?interface?Drink?{
????/**
?????*?喝水
?????*/
????void?drink();
}

寫一個(gè)接口的實(shí)現(xiàn)

public?class?DrinkWater?implements?Drink?{

????@Override
????public?void?drink()?{
????????System.out.println("喝水");
????}

}

一個(gè)簡(jiǎn)單的裝飾器

public?class?DrinkDecorator?implements?Drink?{

????private?final?Drink?drink;

????public?DrinkDecorator(Drink?drink)?{
????????this.drink?=?drink;
????}

????@Override
????public?void?drink()?{
????????System.out.println("先加點(diǎn)兒檸檬片");
????????drink.drink();
????}

}

開始測(cè)試

public?class?DrinkMain?{
????public?static?void?main(String[]?args)?{
????????Drink?drink?=?new?DrinkWater();
????????drink?=?new?DrinkDecorator(drink);
????????drink.drink();
????}
}

運(yùn)行結(jié)果

先加點(diǎn)兒檸檬片
喝水

一個(gè)簡(jiǎn)單的裝飾器模式例子就寫完了;當(dāng)然這種例子在實(shí)際項(xiàng)目中肯定是用不到的,這里只是先了解一下裝飾器模式

裝飾器模式實(shí)戰(zhàn)

場(chǎng)景: 項(xiàng)目一期開發(fā)的時(shí)候,并沒(méi)有給鑒權(quán)部分設(shè)置緩存;二期開發(fā)考慮到性能問(wèn)題,想要給鑒權(quán)部分加上緩存,這里就選擇了使用裝飾器模式進(jìn)行處理;

這里使用的緩存是spring的 spring-cache,不了解沒(méi)關(guān)系,知道幾個(gè)注解什么意思就行

@Cacheable 表示要對(duì)方法返回值進(jìn)行緩存

@CacheEvict 刪除緩存注解

為了簡(jiǎn)潔,以下代碼均為偽代碼

首先,需要一個(gè)權(quán)限的接口和實(shí)現(xiàn)類

public?interface?IDataAccessor?{
????/**
?????*?根據(jù)部門上級(jí)?id?獲取所有子集部門
?????*/
????Set<Long>?deptFindAllChildrenByParentIds(Collection<Long>?parentIds);

????/**
?????*?獲取數(shù)據(jù)范圍內(nèi)的部門
?????*/
????Set<Long>?deptFindScopeById(Long?userId);

實(shí)現(xiàn)類(注意這里加了@Service, 交給spring處理)

@Service
public?class?ScopeDataAccessorImpl?implements?IDataAccessor?{
????@Autowired
????private?IDepartmentService?departmentService;
????
????@Autowired
????private?INodeScopeService?nodeScopeService;

????@Override
????public?Set<Long>?deptFindAllChildrenByParentIds(Collection<Long>?parentIds)?{
????????Set<Long>?result?=?new?HashSet<>();
????????departmentService.departmentChildren(parentIds,?result);
????????return?result;
????}
????
????@Override
????public?Set<Long>?deptFindScopeById(Long?userId)?{
????????return?nodeScopeService.deptFindScopeById(userId);
????}
}

接下來(lái)就是對(duì)之前的代碼進(jìn)行裝飾,定義一個(gè)裝飾器的實(shí)現(xiàn)類

(這個(gè)類沒(méi)有 @Component, 沒(méi)有直接交給spring管理;加了注解會(huì)報(bào)錯(cuò):找到了2個(gè)bean)

public?class?DataAccessorDecorator?implements?IDataAccessor?{
????private?final?IDataAccessor?iDataAccessor;

????public?DataAccessorDecorator(IDataAccessor?iDataAccessor)?{
????????this.iDataAccessor?=?iDataAccessor;
????}

????@Cacheable(cacheNames?=?"dept:parentId",?key?=?"#p0",?sync?=?true)
????@Override
????public?Set<Long>?deptFindAllChildrenByParentIds(Collection<Long>?parentIds)?{
????????return?iDataAccessor.deptFindAllChildrenByParentIds(parentIds);
????}

????@Cacheable(cacheNames?=?"dept:scope:userId",?key?=?"#p0",?sync?=?true)
????@Override
????public?Set<Long>?deptFindScopeById(Long?userId)?{
????????return?iDataAccessor.deptFindScopeById(nodeId,userId);
????}
}

接下來(lái)還需要將這個(gè)裝飾器的類注冊(cè)到spring中

@Configuration
@ConditionalOnBean({IDataAccessor.class})
public?class?Config?{
????
????@Bean
????@ConditionalOnBean({IDataAccessor.class})
????public?DataAccessorDecorator?dataAccessorDecorator(IDataAccessor?iDataAccessor)?{
????????return?new?DataAccessorDecorator(iDataAccessor);
????}
}

根據(jù)業(yè)務(wù),維護(hù)緩存更新;這里使用的監(jiān)聽部門和員工的變更事件

@Component
public?class?DataScopeEvict?{

????/**
?????*?清空部門相關(guān)緩存
?????*/
????@CacheEvict(cacheNames?=?{"dept:parentId"},?allEntries?=?true)
????public?void?department()?{
????}

????/**
?????*?清空用戶相關(guān)緩存
?????*/
????@CacheEvict(cacheNames?=?{"dept:scope:userId"},?allEntries?=?true)
????public?void?user()?{
????}
}
@Component
public?class?ScopeDataEventListener?{
????@Autowired
????private?DataScopeEvict?evict;
????
?/**
?????*?監(jiān)聽部門變更事件
?????*/
????@EventListener
????public?void?departmentEvent(DepartmentChangeEvent?event)?{
????????//?1?增加?2?刪除?3?上級(jí)部門變更
????????evict.department();
????}

????/**
?????*?監(jiān)聽user變更事件
?????*/
????@EventListener
????public?void?userEvent(UserChangeEvent?event)?{
????????//?2?刪除?3?主部門變更
????????if?(event.getType().equals(2)?||?event.getType().equals(3))?{
????????????evict.user();
????????}
????}
}

一切準(zhǔn)備就緒,使用的時(shí)候直接使用裝飾器類就好了

@Service
public?class?UserService?{
????
????@Autowired
????DataAccessorDecorator?scopeDataAccessor;

????
????public?Set<Long>?deptFindAllChildrenByParentIds(Collection<Long>?parentIds)?{
????????return?scopeDataAccessor.deptFindAllChildrenByParentIds(parentIds);
????}
????
????
????public?Set<Long>?deptFindScopeById(Long?userId)?{
????????return?scopeDataAccessor.deptFindScopeById(userId);
????}
????
}

以上就是一個(gè)將裝飾器模式應(yīng)用到實(shí)際項(xiàng)目的例子;

在這個(gè)例子中,使用裝飾器模式增強(qiáng)了原本的代碼,不修改原本的代碼,原本的代碼也能正確提供服務(wù),只不過(guò)沒(méi)有使用緩存;只要方法名命名一致,只需修改注入的字段就可以升級(jí)完成,升級(jí)成本還是很低的。

這波使用裝飾器模式加緩存的操作寫到項(xiàng)目中,直接讓你的代碼 B ge pull full

小結(jié)

雖然使用裝飾器模式看起來(lái)B格高,但還是要注意自己項(xiàng)目的場(chǎng)景,選擇適合的方式解決問(wèn)題。

以上就是詳解Java如何優(yōu)雅的使用裝飾器模式的詳細(xì)內(nèi)容,更多關(guān)于Java裝飾器模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot中的FailureAnalyzer使用詳解

    SpringBoot中的FailureAnalyzer使用詳解

    這篇文章主要介紹了SpringBoot中的FailureAnalyzer使用詳解,Spring Boot的FailureAnalyzer是一個(gè)接口,它用于在Spring Boot應(yīng)用啟動(dòng)失敗時(shí)提供有關(guān)錯(cuò)誤的詳細(xì)信息,這對(duì)于開發(fā)者來(lái)說(shuō)非常有用,因?yàn)樗梢詭椭覀兛焖僮R(shí)別問(wèn)題并找到解決方案,需要的朋友可以參考下
    2023-12-12
  • springboot跨域過(guò)濾器fetch react Response to preflight request doesn‘t pass access control check問(wèn)題

    springboot跨域過(guò)濾器fetch react Response to p

    這篇文章主要介紹了springboot跨域過(guò)濾器fetch react Response to preflight request doesn‘t pass access control check問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Java實(shí)題演練二叉搜索樹與雙向鏈表分析

    Java實(shí)題演練二叉搜索樹與雙向鏈表分析

    這篇文章主要介紹了Java二叉搜索樹與雙向鏈表,總的來(lái)說(shuō)這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達(dá)的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過(guò)程。希望通過(guò)這道題能給你帶來(lái)一種解題優(yōu)化的思路
    2022-12-12
  • java?hutool工具類處理JSON的使用方法

    java?hutool工具類處理JSON的使用方法

    hutool是一個(gè)java基礎(chǔ)工具類,該工具類經(jīng)過(guò)長(zhǎng)期的發(fā)展,API已經(jīng)非常齊全,下面這篇文章主要給大家介紹了關(guān)于java?hutool工具類處理JSON的使用方法,需要的朋友可以參考下
    2024-04-04
  • Spring?BeanDefinition父子關(guān)系示例解析

    Spring?BeanDefinition父子關(guān)系示例解析

    這篇文章主要為大家介紹了Spring?BeanDefinition父子關(guān)系示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Java依賴倒轉(zhuǎn)原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java依賴倒轉(zhuǎn)原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了Java依賴倒轉(zhuǎn)原則的定義及問(wèn)題由來(lái)解決方案,感興趣的朋友一起看看吧
    2017-08-08
  • java?使用BeanFactory實(shí)現(xiàn)service與dao層解耦合詳解

    java?使用BeanFactory實(shí)現(xiàn)service與dao層解耦合詳解

    這篇文章主要介紹了java?使用BeanFactory實(shí)現(xiàn)service與dao層解耦合詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java調(diào)用構(gòu)造函數(shù)和方法及使用詳解

    Java調(diào)用構(gòu)造函數(shù)和方法及使用詳解

    在Java編程中,構(gòu)造函數(shù)用于初始化新創(chuàng)建的對(duì)象,而方法則用于執(zhí)行對(duì)象的行為,構(gòu)造函數(shù)在使用new關(guān)鍵字創(chuàng)建類實(shí)例時(shí)自動(dòng)調(diào)用,沒(méi)有返回類型,并且名稱與類名相同,本文通過(guò)示例詳細(xì)介紹了如何在Java中使用構(gòu)造函數(shù)和方法,感興趣的朋友一起看看吧
    2024-10-10
  • linux下執(zhí)行java程序的sh腳本分享

    linux下執(zhí)行java程序的sh腳本分享

    這篇文章主要介紹了linux下執(zhí)行java程序的sh腳本,僅供參考,但是設(shè)置的時(shí)候環(huán)境變量是最重要的,我就是環(huán)境變量一直不對(duì),總是按網(wǎng)上查到的來(lái),不明白怎么回事,才一直出錯(cuò),其實(shí)環(huán)境變量就是你要執(zhí)行的java程序所在的位置
    2014-09-09
  • Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過(guò)程

    Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過(guò)程

    這篇文章主要給大家介紹了關(guān)于Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12

最新評(píng)論

化隆| 双辽市| 酒泉市| 吉木乃县| 正安县| 清水县| 乌拉特前旗| 康平县| 高淳县| 晋城| 武川县| 湟源县| 韩城市| 饶平县| 定安县| 蓬莱市| 乌兰察布市| 保定市| 兴业县| 罗田县| 西青区| 于田县| 平昌县| 报价| 浠水县| 民乐县| 海阳市| 资阳市| 高邑县| 株洲县| 个旧市| 北票市| 宁津县| 芦山县| 莫力| 肇东市| 得荣县| 中超| 永嘉县| 鲁甸县| 塘沽区|