欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

什么是裝飾器模式

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

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

優(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ì)外,全部由代理類來完成;裝飾是增強(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í)候,并沒有給鑒權(quán)部分設(shè)置緩存;二期開發(fā)考慮到性能問題,想要給鑒權(quán)部分加上緩存,這里就選擇了使用裝飾器模式進(jìn)行處理;

這里使用的緩存是spring的 spring-cache,不了解沒關(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);
????}
}

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

(這個(gè)類沒有 @Component, 沒有直接交給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);
????}
}

接下來還需要將這個(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ù),只不過沒有使用緩存;只要方法名命名一致,只需修改注入的字段就可以升級(jí)完成,升級(jí)成本還是很低的。

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

小結(jié)

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

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

相關(guān)文章

  • java實(shí)現(xiàn)批量下載 多文件打包成zip格式下載

    java實(shí)現(xiàn)批量下載 多文件打包成zip格式下載

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)批量下載、將多文件打包成zip格式下載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Java代理的幾種實(shí)現(xiàn)方式總結(jié)

    Java代理的幾種實(shí)現(xiàn)方式總結(jié)

    本文將通過例子說明java代理的幾種實(shí)現(xiàn)方式,并比較它們之間的差異,文中通過代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友可以參考下
    2023-12-12
  • Java?volatile關(guān)鍵字特性講解下篇

    Java?volatile關(guān)鍵字特性講解下篇

    JMM要求保證可見性、原子性、有序性,volatile可以保證其中的兩個(gè),本篇文章具體驗(yàn)證volatile的可見性,不原子性和禁重排,同時(shí)解決volatile的不保證原子性,讓代碼具有原子性
    2022-12-12
  • java 字節(jié)流和字符流的區(qū)別詳解

    java 字節(jié)流和字符流的區(qū)別詳解

    這篇文章主要介紹了java 字節(jié)流和字符流的區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • SpringBoot連接MySql數(shù)據(jù)庫(kù)的原理及代碼示例

    SpringBoot連接MySql數(shù)據(jù)庫(kù)的原理及代碼示例

    SpringBoot是一款流行的Java開發(fā)框架,它可以輕松地連接各種類型的數(shù)據(jù)庫(kù),包括關(guān)系型數(shù)據(jù)庫(kù)和非關(guān)系型數(shù)據(jù)庫(kù),本文將介紹SpringBoot是如何連接數(shù)據(jù)庫(kù)的,包括其原理和代碼示例,需要的朋友可以參考下
    2023-07-07
  • Spring MVC的文件上傳和下載以及攔截器的使用實(shí)例

    Spring MVC的文件上傳和下載以及攔截器的使用實(shí)例

    這篇文章主要介紹了Spring MVC的文件上傳和下載以及攔截器的使用實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • java獲取日期的方法

    java獲取日期的方法

    這篇文章介紹了java獲取日期的方法,有需要的朋友可以參考一下
    2013-10-10
  • JUC之CountdownLatch使用詳解

    JUC之CountdownLatch使用詳解

    這篇文章主要介紹了JUC之CountdownLatch使用詳解,CountdownLatch 用來進(jìn)行線程同步協(xié)作,等待所有線程完成倒計(jì)時(shí),
    其中構(gòu)造參數(shù)用來初始化等待計(jì)數(shù)值,await() 用來等待計(jì)數(shù)歸零,countDown() 用來讓計(jì)數(shù)減一,需要的朋友可以參考下
    2023-12-12
  • 詳解Java讀取Jar中資源文件及示例代碼

    詳解Java讀取Jar中資源文件及示例代碼

    這篇文章主要介紹了詳解Java讀取Jar中資源文件及實(shí)現(xiàn)代碼的相關(guān)資料,在開發(fā)java項(xiàng)目的時(shí)候,經(jīng)常會(huì)用到j(luò)ar包,這里就說下如何讀取,需要的朋友可以參考下
    2017-07-07
  • 如何利用Java使用AOP實(shí)現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換

    如何利用Java使用AOP實(shí)現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換

    這篇文章主要介紹了如何利用Java使用AOP實(shí)現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換,AOP也是我們常說的面向切面編程,AOP在我們開發(fā)過程中應(yīng)用也比較多,在這里我們就基于AOP來實(shí)現(xiàn)一個(gè)數(shù)據(jù)字典轉(zhuǎn)換的案例
    2022-06-06

最新評(píng)論