這是我見過最通俗易懂的 裝飾者模式 講解了!
作者:佚名
動態給對象增加功能,從一個對象的外部來給對象添加功能,相當于改變了對象的外觀,比用繼承的方式更加的靈活。
1.什么是裝飾者模式
動態給對象增加功能,從一個對象的外部來給對象添加功能,相當于改變了對象的外觀,比用繼承的方式更加的靈活。
當使用裝飾后,從外部系統的角度看,就不再是原來的那個對象了,而是使用一系列的裝飾器裝飾過后的對象。
2.結構
角色:
- Component:組件對象的抽象接口,可以給這些對象動態的增加職責/功能。
- ConcreteComponent:具體的組件的對象,實現組件對象的接口,是被裝飾器裝飾的原始對象,即可以給這個對象動態的添加職責。
- Decorator:所有裝飾器的抽象父類,實現了組件對象的接口,并且持有一個組件對象(被裝飾的對象)。
- ConcreteDecorator:具體的裝飾器,具體實現向裝飾對象添加功能。
3.示例
下面我們用裝飾者模式實現如下的功能:更多:設計模式聚合
要求用戶輸入一段文字,比如 Hello Me,然后屏幕輸出幾個選項
- 加密
- 反轉字符串
- 轉成大寫
- 轉成小寫
- 擴展或者剪裁到10個字符,不足部分用!補充
- 用戶輸入 任意組合,比如 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 transformtransform = 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 transformtransform = transform(display);
- return transform;
- }
- @Override
- public String transform(String str) {
- System.out.println("invoke UpperDecorator....");
- return str.toUpperCase();
- }
- }
- //轉為大寫的裝飾器
- public class UpperDecorator extends Decorator {
- public UpperDecorator(ICompoment compoment) {
- super(compoment);
- }
- @Override
- public String display(String str) {
- String display = super.display(str);
- String transformtransform = 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 transformtransform = 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 transformtransform = 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 class ExtendOrSplitDecorator extends Decorator {
- public ExtendOrSplitDecorator(ICompoment compoment) {
- super(compoment);
- }
- @Override
- public String display(String str) {
- String display = super.display(str);
- String transformtransform = 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.比繼承更靈活
- 從為對象添加功能的角度來看,裝飾者模式比繼承更為靈活。繼承是靜態的,一旦繼承,所有的子類都有一樣的功能。裝飾者模式采用把功能分離到每個裝飾器當中,
- 通過對象組合的方式,在運行時動態的組合功能,被裝飾對象最終由哪些功能,是由運行時動態組合的功能決定的?! ?/li>
2.復用功能更容易
- 裝飾模式把一系列復雜的功能分散到每個裝飾器中,一般情況下每個裝飾器只實現一個功能,使得實現裝飾器變得簡單,有利于裝飾器功能的復用,可以給一個對象添加
- 多個裝飾器,也可以把一個裝飾器裝飾多個對象,從而實現復用裝飾器的功能。
3.簡化高層定義
- 裝飾者模式可以通過組合裝飾器的方式,為對象添加任意多的功能;因此在高層定義的時候,不必把所有的功能都定義處理,只需要定義最基本的就可以了,在需要的時候可以
- 通過組合裝飾器的方式來完成所需的功能。
缺點:會產生較多的細粒度的對象
- 裝飾模式把一系列復雜的功能分散到每個裝飾器中,一般情況下每個裝飾器只實現一個功能,這樣會產生很多細粒度的對象,并且功能越復雜,細粒度對象越多。
本質:動態組合
注意:裝飾者模式只是改變組件對象的外觀Facde,并沒有改變其內核
使用場合:
- 如果需要再不影響其他對象的情況下,以動態、透明的方式給對象增加職責,可以使用裝飾者模式。
- 如果不適合使用子類進行擴展的時候,可以考慮使用裝飾者模式。裝飾者模式使用的是對象組合的方式。
- 不適合子類擴展:比如擴展功能需要的子類太多,造成子類數量呈爆炸性增長。
責任編輯:龐桂玉
來源:
Java知音