这是我见过最通俗易懂的 装饰者模式 讲解了!

开发 后端
动态给对象增加功能,从一个对象的外部来给对象添加功能,相当于改变了对象的外观,比用继承的方式更加的灵活。

1.什么是装饰者模式

动态给对象增加功能,从一个对象的外部来给对象添加功能,相当于改变了对象的外观,比用继承的方式更加的灵活。

当使用装饰后,从外部系统的角度看,就不再是原来的那个对象了,而是使用一系列的装饰器装饰过后的对象。

2.结构

角色:

  •  Component:组件对象的抽象接口,可以给这些对象动态的增加职责/功能。
  •  ConcreteComponent:具体的组件的对象,实现组件对象的接口,是被装饰器装饰的原始对象,即可以给这个对象动态的添加职责。
  •  Decorator:所有装饰器的抽象父类,实现了组件对象的接口,并且持有一个组件对象(被装饰的对象)。
  •  ConcreteDecorator:具体的装饰器,具体实现向装饰对象添加功能。

3.示例

下面我们用装饰者模式实现如下的功能:更多:设计模式聚合

要求用户输入一段文字,比如 Hello Me,然后屏幕输出几个选项

  •  加密
  •  反转字符串
  •  转成大写
  •  转成小写
  •  扩展或者剪裁到10个字符,不足部分用!补充
  •  用户输入 任意组合,比如 1,3 表示先执行1的逻辑,再执行3的逻辑
  •  根据用户输入的选择,进行处理后,输出结果 
  1. //组件对象的接口  
  2. public interface ICompoment {  
  3.      String display(String str);  
  4.  
  1. //具体的组件对象  
  2. public class DetailCompoment implements ICompoment {  
  3.     @Override  
  4.     public String display(String str) {  
  5.         System.out.println("原来内容:"+str);  
  6.         return str;  
  7.     }  
  8.  
  1. //所有装饰器的父类,实现了组件接口  
  2. public abstract class Decorator implements ICompoment{  
  3.       //持有了一个组件对象  
  4.       protected ICompoment compoment;  
  5.       public Decorator(ICompoment compoment) {  
  6.             this.compoment = compoment;  
  7.       }  
  8.       @Override  
  9.       public String display(String str) {  
  10.             return compoment.display(str);  
  11.       }  
  12.       //对组件对象进行装饰的抽象方法  
  13.       public abstract String transform(String str);  
  14.  
  1. //加密、解密工具类  
  2. public class EnDecodeUtil {  
  3.     private static final char password='a' 
  4.     public static String encodeDecode(String str){  
  5.         char[] chars = str.toCharArray();  
  6.         for (int i = 0; i < chars.length; i++) {  
  7.             chars[i] = (char) (chars[i] ^ password);  
  8.         }  
  9.         return new String(chars);  
  10.     }  
  11.  
  1. //加密装饰器  
  2. public class EncodeDecorator extends Decorator {  
  3.     public EncodeDecorator(ICompoment compoment) {  
  4.         super(compoment);  
  5.     }  
  6.     @Override  
  7.     public String display(String str) {  
  8.         String display = super.display(str);  
  9.         return transform(display);  
  10.     }  
  11.     @Override  
  12.     public String transform(String str) {  
  13.         System.out.println("invoke EncodeDecorator....");  
  14.        return EnDecodeUtil.encodeDecode(str);  
  15.     }  
  16.  
  1. //解密装饰器  
  2. public class DecodeDecorator extends Decorator {  
  3.     public DecodeDecorator(ICompoment compoment) {  
  4.         super(compoment);  
  5.     }  
  6.     @Override  
  7.     public String display(String str) {  
  8.         String display = super.display(str);  
  9.         return transform(display);  
  10.     }  
  11.     @Override  
  12.     public String transform(String str) {  
  13.         System.out.println("invoke DecodeDecorator...");  
  14.         return EnDecodeUtil.encodeDecode(str);  
  15.     }  
  16.  
  1. //反转 装饰器  
  2. public class ReverseDecorator extends Decorator {  
  3.     public ReverseDecorator(ICompoment compoment) {  
  4.         super(compoment);  
  5.     }  
  6.     @Override  
  7.     public String display(String str) {  
  8.         String display = super.display(str);  
  9.         String transformtransform = transform(display);  
  10.         return transform;  
  11.     } 
  12.     @Override  
  13.     public String transform(String str) {  
  14.         System.out.println("invoke ReverseDecorator....");  
  15.         StringBuilder sb = new StringBuilder(str);  
  16.         return sb.reverse().toString();  
  17.     }  
  18.  
  1. //转为大写的装饰器  
  2. public class UpperDecorator extends Decorator {  
  3.     public UpperDecorator(ICompoment compoment) {  
  4.         super(compoment);  
  5.     }  
  6.     @Override  
  7.     public String display(String str) {  
  8.         String display = super.display(str);  
  9.         String transformtransform = transform(display);  
  10.         return transform;  
  11.     }  
  12.     @Override 
  13.      public String transform(String str) {  
  14.         System.out.println("invoke UpperDecorator....");  
  15.         return str.toUpperCase();  
  16.     }  
  17.  
  1. //转为大写的装饰器  
  2. public class UpperDecorator extends Decorator {  
  3.     public UpperDecorator(ICompoment compoment) {  
  4.         super(compoment);  
  5.     }  
  6.     @Override  
  7.     public String display(String str) {  
  8.         String display = super.display(str);  
  9.         String transformtransform = transform(display);  
  10.         return transform;  
  11.     }  
  12.     @Override  
  13.     public String transform(String str) {  
  14.         System.out.println("invoke UpperDecorator....");  
  15.         return str.toUpperCase();  
  16.     }  
  17.  
  1. //转为小写的装饰器  
  2. public class LowerDecorator extends Decorator{  
  3.     public LowerDecorator(ICompoment compoment) {  
  4.         super(compoment);  
  5.     }  
  6.     @Override  
  7.     public String display(String str) {  
  8.         String display = super.display(str);  
  9.         String transformtransform = transform(display);  
  10.         return transform;  
  11.     }  
  12.     @Override  
  13.     public String transform(String str) {  
  14.         System.out.println("invoke lowerDecorator....");  
  15.         return str.toLowerCase();  
  16.     }  
  17.  
  1. //裁剪、扩充装饰器  
  2. public class ExtendOrSplitDecorator extends Decorator {  
  3.     public ExtendOrSplitDecorator(ICompoment compoment) {  
  4.         super(compoment);  
  5.     }  
  6.     @Override  
  7.     public String display(String str) {  
  8.         String display = super.display(str);  
  9.         String transformtransform = transform(display);  
  10.         return transform;  
  11.     }  
  12.     @Override  
  13.     public String transform(String str) {  
  14.         System.out.println("invoke ExtendOrSplitDecorator....");  
  15.         if (str != null) {  
  16.             if (str.length() > 10) {  
  17.                 return str.substring(0,10);  
  18.             }else{  
  19.                 int repeatCount = 10 -str.length();  
  20.                 StringBuilder sb = new StringBuilder(str);  
  21.                 for (int i = 0; i < repeatCount; i++) {  
  22.                     sb.append("!");  
  23.                 }  
  24.                 return sb.toString();  
  25.             }  
  26.         }  
  27.         return null;  
  28.     }  
  29.  
  1. //裁剪、扩充装饰器  
  2. public class ExtendOrSplitDecorator extends Decorator {  
  3.     public ExtendOrSplitDecorator(ICompoment compoment) {  
  4.         super(compoment);  
  5.     }  
  6.     @Override  
  7.     public String display(String str) {  
  8.         String display = super.display(str);  
  9.         String transformtransform = transform(display);  
  10.         return transform;  
  11.     }  
  12.     @Override  
  13.     public String transform(String str) {  
  14.         System.out.println("invoke ExtendOrSplitDecorator....");  
  15.         if (str != null) {  
  16.             if (str.length() > 10) {  
  17.                 return str.substring(0,10);  
  18.             }else{  
  19.                 int repeatCount = 10 -str.length();  
  20.                 StringBuilder sb = new StringBuilder(str);  
  21.                 for (int i = 0; i < repeatCount; i++) {  
  22.                     sb.append("!");  
  23.                 }  
  24.                 return sb.toString();  
  25.             }  
  26.         }  
  27.         return null;  
  28.     }  
  29.  
  1. //测试代码  
  2. public static void main(String[] args) {  
  3.         //将输入内容转为大写,再反转  
  4.         ReverseDecorator reverseDecorator = new ReverseDecorator(new UpperDecorator(new DetailCompoment()));  
  5.         String display = reverseDecorator.display("wo shi zhongguo ren.");  
  6.         System.out.println(display);  
  7.         //将输入内容转为小写,在裁剪或者扩展 
  8.          ExtendOrSplitDecorator decorator = new ExtendOrSplitDecorator(new LowerDecorator(new DetailCompoment()));  
  9.         String display1 = decorator.display("I Love");  
  10.         System.out.println(display1);  
  11.         //将输入内容转为小写,再反转,然后加密  
  12.         EncodeDecorator decorator1 = new EncodeDecorator(new ReverseDecorator(new LowerDecorator(new DetailCompoment())));  
  13.         String display2 = decorator1.display("顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC");  
  14.         System.out.println(display2);  
  15.         System.out.println("++++++++++");  
  16.         //将输入内容先反转、再转为小写,然后加密  
  17.         EncodeDecorator decorator2 = new EncodeDecorator(new LowerDecorator(new ReverseDecorator(new DetailCompoment())));  
  18.         String display3 = decorator2.display("顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC");  
  19.         System.out.println(display3);  
  20.         System.out.println("============");  
  21.         //对上面的加密内容,进行解密  
  22.         DecodeDecorator decodeDecorator = new DecodeDecorator(decorator1);  
  23.         String display4 = decodeDecorator.display("顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC");  
  24.         System.out.println(display4);  
  25.     } 

控制台输出: 

  1. 原来内容:wo shi zhongguo ren.  
  2. invoke UpperDecorator....  
  3. invoke ReverseDecorator....  
  4. .NER OUGGNOHZ IHS OW  
  5. 原来内容:I Love  
  6. invoke lowerDecorator....  
  7. invoke ExtendOrSplitDecorator....  
  8. i love!!!!  
  9. 原来内容:顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC  
  10. invoke lowerDecorator....  
  11. invoke ReverseDecorator....  
  12. invoke EncodeDecorator....  
  13.  URSP[晎硠宧蠭钗A⦆湎玁玬裌倖杍斄A杩SP帕PUXPサ宧杛细頗  
  14. ++++++++++  
  15. 原来内容:顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC  
  16. invoke ReverseDecorator....  
  17. invoke lowerDecorator....  
  18. invoke EncodeDecorator....  
  19.  URSP[晎硠宧蠭钗A⦆湎玁玬裌倖杍斄A杩SP帕PUXPサ宧杛细頗  
  20. ============  
  21. 原来内容:顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC  
  22. invoke lowerDecorator....  
  23. invoke ReverseDecorator....  
  24. invoke EncodeDecorator....  
  25. invoke DecodeDecorator... 
  26.  cda4321:是码密行银 !港珠珍袭偷本日 月21年1491:密机级顶 

4.装饰者模式在jdk中的应用I/O

  •  InputStream 相当于装饰者模式的Component
  •  FileInputStream,ByteArrayInputStream,ObjectInputStream这些对象直接继承了InputStream,相当于装饰者模式中的ConcreteComponent
  •  FilterInputStream 继承了InputStream,并且持有了一个InputStream ,相当于装饰者模式中的Decorator
  •  BufferedInputStream,PushbackInputStream,LineNumberInputStream,DataInputStream继承了FilterInputStream,相当于装饰者模式中的ConcreteDecorator 
  1.  //这里FileInputStream 相当于组件对象,BufferedInputStream这个装饰器装饰了FileInputStream对象  
  2. BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("fileName")));  
  3. byte[] buff = new byte[1024];  
  4. bis.read(buff);  
  5. System.out.println(new String(buff)); 

5.优点、缺点,使用场合

优点:

1.比继承更灵活

  •  从为对象添加功能的角度来看,装饰者模式比继承更为灵活。继承是静态的,一旦继承,所有的子类都有一样的功能。装饰者模式采用把功能分离到每个装饰器当中,
  •  通过对象组合的方式,在运行时动态的组合功能,被装饰对象最终由哪些功能,是由运行时动态组合的功能决定的。  

2.复用功能更容易

  •  装饰模式把一系列复杂的功能分散到每个装饰器中,一般情况下每个装饰器只实现一个功能,使得实现装饰器变得简单,有利于装饰器功能的复用,可以给一个对象添加
  •  多个装饰器,也可以把一个装饰器装饰多个对象,从而实现复用装饰器的功能。

3.简化高层定义

  •  装饰者模式可以通过组合装饰器的方式,为对象添加任意多的功能;因此在高层定义的时候,不必把所有的功能都定义处理,只需要定义最基本的就可以了,在需要的时候可以
  •  通过组合装饰器的方式来完成所需的功能。

缺点:会产生较多的细粒度的对象

  •  装饰模式把一系列复杂的功能分散到每个装饰器中,一般情况下每个装饰器只实现一个功能,这样会产生很多细粒度的对象,并且功能越复杂,细粒度对象越多。

本质:动态组合

注意:装饰者模式只是改变组件对象的外观Facde,并没有改变其内核

使用场合:

  •  如果需要再不影响其他对象的情况下,以动态、透明的方式给对象增加职责,可以使用装饰者模式。
  •  如果不适合使用子类进行扩展的时候,可以考虑使用装饰者模式。装饰者模式使用的是对象组合的方式。
  •  不适合子类扩展:比如扩展功能需要的子类太多,造成子类数量呈爆炸性增长。 

 

 

责任编辑:庞桂玉 来源: Java知音
相关推荐

2019-04-08 20:20:37

2022-06-28 07:31:11

哨兵模式redis

2022-09-23 08:32:53

微服务架构服务

2024-03-26 00:54:42

预测模型数据

2011-10-26 19:57:33

2016-03-25 09:59:38

性能调优LinuxMySQL

2023-06-26 00:19:13

2019-06-19 08:30:47

网络协议IPTCP

2023-09-04 11:32:28

数据诊断模型

2021-05-26 16:12:20

区块链加密货币比特币

2021-06-21 15:57:08

微服务架构数据

2020-06-08 10:50:58

前端TypeScript代码

2023-01-06 09:40:20

项目性能

2019-03-18 08:08:24

知识图谱技术

2021-11-04 08:16:50

MySQL SQL 语句数据库

2022-07-06 08:17:50

C 语言函数选型

2018-01-17 22:36:46

2019-05-20 07:37:00

TCPIP网络协议

2021-05-13 13:20:00

Git命令Linux

2018-03-05 08:35:12

物联网互联网网络技术
点赞
收藏

51CTO技术栈公众号