裝飾者模式 Decoration

来源:http://www.cnblogs.com/lewis0077/archive/2016/12/14/6174374.html
-Advertisement-
Play Games

1.什麼是裝飾者模式 動態給對象增加功能,從一個對象的外部來給對象添加功能,相當於改變了對象的外觀,比用繼承的方式更加的靈活。當使用裝飾後,從外部系統的角度看,就不再是原來的那個對象了,而是使用一系列的裝飾器裝飾過後的對象。 2.結構 3.示例 下麵我們用裝飾者模式實現如下的功能: 要求用戶輸入一段 ...


1.什麼是裝飾者模式

      動態給對象增加功能,從一個對象的外部來給對象添加功能,相當於改變了對象的外觀,比用繼承的方式更加的靈活。當使用裝飾後,從外部系統的角度看,就不再是原來的那個對象了,而是使用一系列的裝飾器裝飾過後的對象。

2.結構

                                                                            

    角色:
    Component:組件對象的抽象介面,可以給這些對象動態的增加職責/功能。
    ConcreteComponent:具體的組件的對象,實現組件對象的介面,是被裝飾器裝飾的原始對象,即可以給這個對象動態的添加職責。
    Decorator:所有裝飾器的抽象父類,實現了組件對象的介面,並且持有一個組件對象(被裝飾的對象)。
    ConcreteDecorator:具體的裝飾器,具體實現向裝飾對象添加功能。

3.示例

   下麵我們用裝飾者模式實現如下的功能:
    要求用戶輸入一段文字,比如 Hello Me,然後屏幕輸出幾個選項
    1 :加密
    2 :反轉字元串
    3:轉成大寫

    4:轉成小寫
    5:擴展或者剪裁到10個字元,不足部分用!補充
    6:用戶輸入 任意組合,比如 1,3 表示先執行1的邏輯,再執行3的邏輯
    根據用戶輸入的選擇,進行處理後,輸出結果

 

//組件對象的介面
public interface ICompoment {

     String display(String str);
}
//具體的組件對象
public class DetailCompoment implements ICompoment {
    @Override
    public String display(String str) {
        System.out.println("原來內容:"+str);
        return str;
    }
}
//所有裝飾器的父類,實現了組件介面
public abstract class Decorator implements ICompoment{
      //持有了一個組件對象
      protected ICompoment compoment;

      public Decorator(ICompoment compoment) {
            this.compoment = compoment;
      }

      @Override
      public String display(String str) {
            return compoment.display(str);
      }
      //對組件對象進行裝飾的抽象方法
      public abstract String transform(String str);
}
//加密、解密工具類
public class EnDecodeUtil {

    private static final char password='a';

    public static String encodeDecode(String str){
        char[] chars = str.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            chars[i] = (char) (chars[i] ^ password);
        }
        return new String(chars);
    }
}
//加密裝飾器
public class EncodeDecorator extends Decorator {

    public EncodeDecorator(ICompoment compoment) {
        super(compoment);
    }

    @Override
    public String display(String str) {
        String display = super.display(str);
        return transform(display);
    }

    @Override
    public String transform(String str) {
        System.out.println("invoke EncodeDecorator....");
       return EnDecodeUtil.encodeDecode(str);
    }
}
//解密裝飾器
public class DecodeDecorator extends Decorator {

    public DecodeDecorator(ICompoment compoment) {
        super(compoment);
    }

    @Override
    public String display(String str) {
        String display = super.display(str);
        return transform(display);
    }

    @Override
    public String transform(String str) {
        System.out.println("invoke DecodeDecorator...");
        return EnDecodeUtil.encodeDecode(str);
    }
}
//反轉 裝飾器
public class ReverseDecorator extends Decorator {

    public ReverseDecorator(ICompoment compoment) {
        super(compoment);
    }

    @Override
    public String display(String str) {
        String display = super.display(str);
        String transform = transform(display);
        return transform;
    }

    @Override
    public String transform(String str) {
        System.out.println("invoke ReverseDecorator....");
        StringBuilder sb = new StringBuilder(str);
        return sb.reverse().toString();
    }

}
//轉為大寫的裝飾器
public class UpperDecorator extends Decorator {
    public UpperDecorator(ICompoment compoment) {
        super(compoment);
    }

    @Override
    public String display(String str) {
        String display = super.display(str);
        String transform = transform(display);
        return transform;
    }

    @Override
    public String transform(String str) {
        System.out.println("invoke UpperDecorator....");
        return str.toUpperCase();
    }
}
//轉為小寫的裝飾器
public class LowerDecorator extends Decorator{
    public LowerDecorator(ICompoment compoment) {
        super(compoment);
    }

    @Override
    public String display(String str) {
        String display = super.display(str);
        String transform = transform(display);
        return transform;
    }

    @Override
    public String transform(String str) {
        System.out.println("invoke lowerDecorator....");
        return str.toLowerCase();
    }
}
//裁剪、擴充裝飾器
public class ExtendOrSplitDecorator extends Decorator {
    public ExtendOrSplitDecorator(ICompoment compoment) {
        super(compoment);
    }

    @Override
    public String display(String str) {
        String display = super.display(str);
        String transform = transform(display);
        return transform;
    }

    @Override
    public String transform(String str) {
        System.out.println("invoke ExtendOrSplitDecorator....");
        if (str != null) {
            if (str.length() > 10) {
                return str.substring(0,10);
            }else{
                int repeatCount = 10 -str.length();
                StringBuilder sb = new StringBuilder(str);
                for (int i = 0; i < repeatCount; i++) {
                    sb.append("!");
                }
                return sb.toString();
            }
        }
        return null;
    }
}
//測試代碼
public static void main(String[] args) {
        //將輸入內容轉為大寫,再反轉
        ReverseDecorator reverseDecorator = new ReverseDecorator(new UpperDecorator(new DetailCompoment()));
        String display = reverseDecorator.display("wo shi zhongguo ren.");
        System.out.println(display);

        //將輸入內容轉為小寫,在裁剪或者擴展
        ExtendOrSplitDecorator decorator = new ExtendOrSplitDecorator(new LowerDecorator(new DetailCompoment()));
        String display1 = decorator.display("I Love");
        System.out.println(display1);

        //將輸入內容轉為小寫,再反轉,然後加密
        EncodeDecorator decorator1 = new EncodeDecorator(new ReverseDecorator(new LowerDecorator(new DetailCompoment())));
        String display2 = decorator1.display("頂級機密:1941年12月 日本偷襲珍珠港! 銀行密碼是:1234ADC");
        System.out.println(display2);
        System.out.println("++++++++++");
        //將輸入內容先反轉、再轉為小寫,然後加密
        EncodeDecorator decorator2 = new EncodeDecorator(new LowerDecorator(new ReverseDecorator(new DetailCompoment())));
        String display3 = decorator2.display("頂級機密:1941年12月 日本偷襲珍珠港! 銀行密碼是:1234ADC");
        System.out.println(display3);

        System.out.println("============");
        //對上面的加密內容,進行解密
        DecodeDecorator decodeDecorator = new DecodeDecorator(decorator1);
        String display4 = decodeDecorator.display("頂級機密:1941年12月 日本偷襲珍珠港! 銀行密碼是:1234ADC");
        System.out.println(display4);
    }

控制台輸出:

原來內容:wo shi zhongguo ren.
invoke UpperDecorator....
invoke ReverseDecorator....
.NER OUGGNOHZ IHS OW
原來內容:I Love
invoke lowerDecorator....
invoke ExtendOrSplitDecorator....
i love!!!!
原來內容:頂級機密:1941年12月 日本偷襲珍珠港! 銀行密碼是:1234ADC
invoke lowerDecorator....
invoke ReverseDecorator....
invoke EncodeDecorator....
 URSP[晎硠宧蠭釵A⦆湎玁玬裌倖杍斄A榪SP帕PUXPサ宧杛細頗
++++++++++
原來內容:頂級機密:1941年12月 日本偷襲珍珠港! 銀行密碼是:1234ADC
invoke ReverseDecorator....
invoke lowerDecorator....
invoke EncodeDecorator....
 URSP[晎硠宧蠭釵A⦆湎玁玬裌倖杍斄A榪SP帕PUXPサ宧杛細頗
============
原來內容:頂級機密:1941年12月 日本偷襲珍珠港! 銀行密碼是:1234ADC
invoke lowerDecorator....
invoke ReverseDecorator....
invoke EncodeDecorator....
invoke DecodeDecorator...
cda4321:是碼密行銀 !港珠珍襲偷本日 月21年1491:密機級頂

 

4.裝飾者模式在jdk中的應用I/O

                                                 

    InputStream 相當於裝飾者模式的Component
    FileInputStream,ByteArrayInputStream,ObjectInputStream這些對象直接繼承了InputStream,相當於裝飾者模式中的ConcreteComponent
    FilterInputStream 繼承了InputStream,並且持有了一個InputStream ,相當於裝飾者模式中的Decorator
    BufferedInputStream,PushbackInputStream,LineNumberInputStream,DataInputStream繼承了FilterInputStream,相當於裝飾者模式中的ConcreteDecorator

 

 //這裡FileInputStream 相當於組件對象,BufferedInputStream這個裝飾器裝飾了FileInputStream對象
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("fileName")));
            byte[] buff = new byte[1024];
            bis.read(buff);
            System.out.println(new String(buff));

 

5.優點、缺點,使用場合

  優點:
    1.比繼承更靈活
    從為對象添加功能的角度來看,裝飾者模式比繼承更為靈活。繼承是靜態的,一旦繼承,所有的子類都有一樣的功能。裝飾者模式採用把功能分離到每個裝飾器當中,
   通過對象組合的方式,在運行時動態的組合功能,被裝飾對象最終由哪些功能,是由運行時動態組合的功能決定的
    2.復用功能更容易
    裝飾模式把一系列複雜的功能分散到每個裝飾器中,一般情況下每個裝飾器只實現一個功能,使得實現裝飾器變得簡單,有利於裝飾器功能的復用,可以給一個對象添加
    多個裝飾器,也可以把一個裝飾器裝飾多個對象,從而實現復用裝飾器的功能
    3.簡化高層定義
    裝飾者模式可以通過組合裝飾器的方式,為對象添加任意多的功能;因此在高層定義的時候,不必把所有的功能都定義處理,只需要定義最基本的就可以了,在需要的時候可以
    通過組合裝飾器的方式來完成所需的功能。

  缺點:會產生較多的細粒度的對象
  裝飾模式把一系列複雜的功能分散到每個裝飾器中,一般情況下每個裝飾器只實現一個功能,這樣會產生很多細粒度的對象,並且功能越複雜,細粒度對象越多。

本質:動態組合
註意:裝飾者模式只是改變組件對象的外觀Facde,並沒有改變其內核

  使用場合:
    如果需要再不影響其他對象的情況下,以動態、透明的方式給對象增加職責,可以使用裝飾者模式。
    如果不適合使用子類進行擴展的時候,可以考慮使用裝飾者模式。裝飾者模式使用的是對象組合的方式。 不適合子類擴展:比如擴展功能需要的子類太多,造成子類數量呈爆炸性增長。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1054. 求平均值 (20) 本題的基本要求非常簡單:給定N個實數,計算它們的平均值。但複雜的是有些輸入數據可能是非法的。一個“合法”的輸入是[-1000,1000]區間內的實數,並且最多精確到小數點後2位。當你計算平均值的時候,不能把那些非法的數據算在內。 輸入格式: 輸入第一行給出正整數N(< ...
  • 讀入一個自然數n,計算其各位數字之和,用漢語拼音寫出和的每一位數字。 輸入格式:每個測試輸入包含1個測試用例,即給出自然數n的值。這裡保證n小於10100。 輸出格式:在一行內輸出n的各位數字之和的每一位,拼音數字間有1 空格,但一行中最後一個拼音數字後沒有空格。 輸入樣例: 輸出樣例: ...
  • 1.自我介紹。2.占領腦袋和丟了腳3.物聯的現實困難4.效率與成本5.智能網關,跑Windows 10 IOT和Ubuntu Mate6.SuperIO到ServerSuperIO發展歷程和解決的實現問題7.一套設備驅動,支持多種IO通訊8.一套設備驅動,統一介面,多種平臺掛載運行9.物聯通訊的級聯... ...
  • 本文地址 原文地址 本文提綱: 1. Nginx的模塊與工作原理 2. Nginx的進程模型 3 . NginxFastCGI運行原理 3.1 什麼是 FastCGI 3.2 NginxFastCGI運行原理 3.3 spawn-fcgi與PHP-FPM 3.4 NginxPHP-FPM 4. Ng ...
  • 在Salesforce中,常常要對各種數據進行處理,已滿足業務邏輯。本篇文章會介紹如何實現從object獲取數據,然後將取得的數據進行一系列簡單處理。 第一步:SongName__c 是一個新建的object,向SongName__c object中插入數據: 列印出SongName__c obje ...
  • 設計文檔模板: 一些其他的思考: 去除一切花俏的建模技巧,我覺得最重要的方向就是去努力分析問題和事物的本質,針對這個本質進行領域建模。這個領域建模,最主要的還是鍛煉的人的事物抽象能力。10個人,建出來的領域模型都不同。本質原因就是大家對同一個問題的理解不同,對事物的本質的理解不同。雖然最終都能解決當 ...
  • package test05;import test06.Car1;public class DuoTai_Test02 { /**多個對象,一個形態 * Tiger、Lion、Snake → Animal *、多個對象,一種形態(類型)。 * 不同對象,表現出同一種形態之後。 * 可以實現同樣的功 ...
  • /** * 內部類 ?? * 定義在一個內部的類,被稱為內部類。 * 內部類里有類體,方法體 * 內部類所在的類,被稱為外部類。 * * ①內部類的意義 * 在一定程度上,起到了代碼的有效保護。 * ②語法 * class Outer{////外部類 * 成員變數 * 成員方法 * class In ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...