0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

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

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-08 14:25 ? 次閱讀

什么是裝飾器模式

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

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

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

  1. 裝飾類和被裝飾類可以獨(dú)立發(fā)展,不會相互耦合
  2. 相比于繼承,更加的輕便、靈活
  3. 可以動態(tài)擴(kuò)展一個實(shí)現(xiàn)類的功能,不必修改原本代碼

缺點(diǎn)

  1. 會產(chǎn)生很多的裝飾類,增加了系統(tǒng)的復(fù)雜性。
  2. 這種比繼承更加靈活機(jī)動的特性,也同時意味著裝飾模式比繼承易于出錯,排錯也很困難,對于多次裝飾的對象,調(diào)試時尋找錯誤可能需要逐級排查,較為繁瑣。

使用場景

  1. 對已有的目標(biāo)功能存在不足,需要增強(qiáng)時,擴(kuò)展類的功能。
  2. 動態(tài)增加功能,動態(tài)撤銷

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

  • 代理是全權(quán)代理,目標(biāo)根本不對外,全部由代理類來完成;裝飾是增強(qiáng),是輔助,目標(biāo)仍然可以自行對外提供服務(wù),裝飾器只起增強(qiáng)作用。
  • 裝飾器模式強(qiáng)調(diào)的是: 增強(qiáng)、新增行為 ;代理模式強(qiáng)調(diào)的是: 對代理的對象施加控制,但不對對象本身的功能進(jìn)行增強(qiáng) 。
  • 裝飾器模式:生效的對象還是原本的對象;代理模式:生效的是新的對象(代理對象)

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

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

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

先定義一個喝水的接口

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

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

public class DrinkWater implements Drink {

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

}

一個簡單的裝飾器

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();
    }

}

開始測試

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

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

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

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

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

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

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

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

@CacheEvict 刪除緩存注解

為了簡潔,以下代碼均為偽代碼

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

public interface IDataAccessor {
    /**
     * 根據(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);
    }
}

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

(這個類沒有 @Component, 沒有直接交給spring管理;加了注解會報(bào)錯:找到了2個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);
    }
}

接下來還需要將這個裝飾器的類注冊到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 上級部門變更
        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)備就緒,使用的時候直接使用裝飾器類就好了

@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);
    }
    
}

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

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

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

小結(jié)

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

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8254

    瀏覽量

    149942
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    223

    瀏覽量

    26579
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4670

    瀏覽量

    67761
收藏 人收藏

    評論

    相關(guān)推薦

    適配器模式代理模式區(qū)別

      代理模式  組成:  抽象角色:通過接口或抽象類聲明真實(shí)角色實(shí)現(xiàn)的業(yè)務(wù)方法。  代理角色:實(shí)現(xiàn)抽象角色,是真實(shí)角色的代理,通過真實(shí)角色的業(yè)務(wù)邏輯方法來實(shí)現(xiàn)抽象方法,并可以附加自己的
    發(fā)表于 10-22 15:17

    MCU模式和RGB模式區(qū)別

    模式(也寫成MPU模式的)。只有TFT模塊才有RGB接口。但應(yīng)用比較多的就是MCU模式和RGB模式,區(qū)別有以下幾點(diǎn):1.MCU接口:會解碼命
    發(fā)表于 11-03 08:53

    適配器模式、裝飾模式代理模式區(qū)別

    適配器模式、裝飾模式代理模式都屬于設(shè)計(jì)模式中的結(jié)
    發(fā)表于 10-18 15:53 ?1.7w次閱讀
    適配器<b class='flag-5'>模式</b>、<b class='flag-5'>裝飾</b><b class='flag-5'>器</b><b class='flag-5'>模式</b>、<b class='flag-5'>代理</b><b class='flag-5'>模式</b>的<b class='flag-5'>區(qū)別</b>

    適配器模式代理模式區(qū)別

    適配器模式:適配器模式有時候也稱包裝樣式或者包裝。將一個類的接口轉(zhuǎn)接成用戶所期待的。代理模式:為其他對象提供一種代理以控制對這個對象的訪問。
    發(fā)表于 01-12 11:56 ?5232次閱讀
    適配器<b class='flag-5'>模式</b>和<b class='flag-5'>代理</b><b class='flag-5'>模式</b>的<b class='flag-5'>區(qū)別</b>

    適配器模式裝飾模式區(qū)別

    裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態(tài)地?cái)U(kuò)展一個對象的功能。它是通過創(chuàng)建一個包裝對象,也就是裝飾來包裹真實(shí)的對象。在計(jì)算機(jī)編程中,適配器模式(有時候也稱包裝樣式或者包
    發(fā)表于 01-15 10:31 ?6909次閱讀
    適配器<b class='flag-5'>模式</b>和<b class='flag-5'>裝飾</b><b class='flag-5'>模式</b>的<b class='flag-5'>區(qū)別</b>

    西門子PLC的等時模式和非等時模式區(qū)別

    西門子PLC的等時模式和非等時模式區(qū)別說明。
    發(fā)表于 04-23 15:58 ?3次下載

    LCD MCU模式和RGB模式

    應(yīng)用比較多的就是MUC模式和RGB模式區(qū)別有以下幾點(diǎn):1.MCU接口:會解碼命令,由timing generator產(chǎn)生時序信號,驅(qū)動COM和SEG驅(qū)。RGB接口:在寫LCD re
    發(fā)表于 10-28 09:50 ?19次下載
    LCD MCU<b class='flag-5'>模式</b>和RGB<b class='flag-5'>模式</b>

    GoF給裝飾模式的定義

    的源碼,就會發(fā)現(xiàn) middleware 功能的實(shí)現(xiàn)用的就是裝飾模式(Decorator Pattern)。
    的頭像 發(fā)表于 06-29 10:22 ?714次閱讀

    GoF設(shè)計(jì)模式代理模式

    它是一個使用率非常高的設(shè)計(jì)模式,在現(xiàn)實(shí)生活中,也是很常見。比如,演唱會門票黃牛。假設(shè)你需要看一場演唱會,但官網(wǎng)上門票已經(jīng)售罄,于是就當(dāng)天到現(xiàn)場通過黃牛高價(jià)買了一張。在這個例子中,黃牛就相當(dāng)于演唱會門票的代理,在正式渠道無法購買門票的情況下,你通過
    的頭像 發(fā)表于 10-17 09:45 ?800次閱讀

    嵌入式C語言軟件設(shè)計(jì)之裝飾模式(Decorator Pattern)

    裝飾模式(Decorator Pattern),是結(jié)構(gòu)型設(shè)計(jì)模式的一種,裝飾
    發(fā)表于 03-01 10:55 ?348次閱讀

    演示裝飾模式的用法

    裝飾模式(Decorator Pattern)允許向一個現(xiàn)有的對象添加新的功能,同時又不改變其結(jié)構(gòu)。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是
    的頭像 發(fā)表于 06-08 11:16 ?499次閱讀
    演示<b class='flag-5'>裝飾</b><b class='flag-5'>器</b><b class='flag-5'>模式</b>的用法

    設(shè)計(jì)模式結(jié)構(gòu)性:代理模式

    代理模式(Proxy Pattern)中,一個類代表另一個類的功能。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式。
    的頭像 發(fā)表于 06-09 15:27 ?746次閱讀
    設(shè)計(jì)<b class='flag-5'>模式</b>結(jié)構(gòu)性:<b class='flag-5'>代理</b><b class='flag-5'>模式</b>

    設(shè)計(jì)模式代理模式的使用場景

    設(shè)計(jì)模式在我看來更像是一種設(shè)計(jì)思維或設(shè)計(jì)思想,它就像《孫子兵法》一樣,為你的項(xiàng)目工程提供方向,讓你的項(xiàng)目工程更加健壯、靈活,延續(xù)生命力。本文即將分享的是設(shè)計(jì)模式的其中一種:代理模式。
    的頭像 發(fā)表于 10-08 14:34 ?752次閱讀
    設(shè)計(jì)<b class='flag-5'>模式</b>中<b class='flag-5'>代理</b><b class='flag-5'>模式</b>的使用場景

    示波器滾動模式與標(biāo)準(zhǔn)模式區(qū)別

    示波器滾動模式與標(biāo)準(zhǔn)模式區(qū)別? 示波器是一種電子測試儀器,它用于顯示電壓隨時間變化的波形圖。示波器可以設(shè)置為兩種顯示模式:滾動模式和標(biāo)準(zhǔn)
    的頭像 發(fā)表于 11-07 10:13 ?1884次閱讀

    網(wǎng)絡(luò)橋接模式是什么? 網(wǎng)絡(luò)橋接模式和路由模式區(qū)別

    網(wǎng)絡(luò)橋接模式是一種網(wǎng)絡(luò)連接方式,它可以將多個設(shè)備連接在一起,使它們可以相互通信。在網(wǎng)絡(luò)橋接模式下,每個設(shè)備都可以直接與其他設(shè)備通信,而不需要經(jīng)過路由或其他中間設(shè)備。這種連接方式通常用于局域網(wǎng)中
    的頭像 發(fā)表于 05-10 13:48 ?3270次閱讀