日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
如何優(yōu)雅的使用裝飾器模式

哈嘍,大家好,我是指北君。裝飾器設(shè)計(jì)模式大家肯定都聽說(shuō)過,但是有沒有使用過呢,今天本君就跟大家分享一下裝飾器模式應(yīng)該如何使用。

成都創(chuàng)新互聯(lián)主營(yíng)甘井子網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,app軟件定制開發(fā),甘井子h5小程序開發(fā)搭建,甘井子網(wǎng)站營(yíng)銷推廣歡迎甘井子等地區(qū)企業(yè)咨詢

什么是裝飾器模式

裝飾器模式(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ì)外,全部由代理類來(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í)候,并沒有給鑒權(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 deptFindAllChildrenByParentIds(Collection parentIds);

/**
* 獲取數(shù)據(jù)范圍內(nèi)的部門
*/
Set 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 deptFindAllChildrenByParentIds(Collection parentIds) {
Set result = new HashSet<>();
departmentService.departmentChildren(parentIds, result);
return result;
}

@Override
public Set deptFindScopeById(Long userId) {
return nodeScopeService.deptFindScopeById(userId);
}
}

接下來(lái)就是對(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 deptFindAllChildrenByParentIds(Collection parentIds) {
return iDataAccessor.deptFindAllChildrenByParentIds(parentIds);
}

@Cacheable(cacheNames = "dept:scope:userId", key = "#p0", sync = true)
@Override
public Set 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 deptFindAllChildrenByParentIds(Collection parentIds) {
return scopeDataAccessor.deptFindAllChildrenByParentIds(parentIds);
}


public Set 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é)

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


文章題目:如何優(yōu)雅的使用裝飾器模式
文章分享:http://www.dlmjj.cn/article/cohpgio.html