装饰模式(包装模式)

模式动机

一般有两种方式可以实现给一个类或对象增加行为:

? 继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。

? 关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)。

装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。

模式定义

装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。

模式结构

装饰模式包含如下角色:

Component: 抽象构件

ConcreteComponent: 具体构件

Decorator: 抽象装饰类

ConcreteDecorator: 具体装饰类

模式分析

与继承关系相比,关联关系的主要优势在于不会破坏类的封装性,而且继承是一种耦合度较大的静态关系,无法在程序运行时动态扩展。在软件开发阶段,关联关系虽然不会比继承关系减少编码量,但是到了软件维护阶段,由于关联关系使系统具有较好的松耦合性,因此使得系统更加容易维护。当然,关联关系的缺点是比继承关系要创建更多的对象。

使用装饰模式来实现扩展比继承更加灵活,它以对客户透明的方式动态地给一个对象附加更多的责任。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。

典型的抽象装饰类代码:

 1 public class Decorator extends Component
 2 {
 3     private Component component;
 4     public Decorator(Component component)
 5     {
 6         this.component=component;
 7     }
 8     public void operation()
 9     {
10         component.operation();
11     }
12 } 

典型的具体装饰类代码:

 1 public class ConcreteDecorator extends Decorator
 2 {
 3     public ConcreteDecorator(Component component)
 4     {
 5         super(component);
 6     }
 7     public void operation()    //在子类的operation方法中增加一个方法
 8     {
 9         super.operation();
10         addedBehavior();
11     }
12     public void addedBehavior()
13     {
14                   //新增方法
15     }
16 } 

实例与解析

实例一:变形金刚

? 变形金刚在变形之前是一辆汽车,它可以在陆地上移动。当它变成机器人之后除了能够在陆地上移动之外,还可以说话;如果需要,它还可以变成飞机,除了在陆地上移动还可以在天空中飞翔。

 1 //抽象构建
 2 public interface Transform
 3 {
 4     public void move();
 5 }
 6
 7 //具体构建
 8 public final class Car implements Transform
 9 {
10     public Car()
11     {
12         System.out.println("变形金刚是一辆车!");
13     }
14
15     public void move()
16     {
17         System.out.println("在陆地上移动!");
18     }
19 }
20
21 //抽象装饰类
22 public class Changer implements Transform
23 {
24     private Transform transform;
25
26     public Changer(Transform transform)
27     {
28         this.transform=transform;
29     }
30
31     public void move()
32     {
33         transform.move();
34     }
35 }
36
37 //具体装饰类
38 public class Robot extends Changer
39 {
40     public Robot(Transform transform)
41     {
42         super(transform);
43         System.out.println("变成机器人!");
44     }
45
46     public void say()
47     {
48         System.out.println("说话!");
49     }
50 }
51
52 //具体装饰类
53 public class Airplane extends Changer
54 {
55     public Airplane(Transform transform)
56     {
57         super(transform);
58         System.out.println("变成飞机!");
59     }
60
61     public void fly()
62     {
63         System.out.println("在天空飞翔!");
64     }
65 }
66
67 //客户端
68 public class Client
69 {
70     public static void main(String args[])
71     {
72         Transform camaro;
73         camaro=new Car();
74         camaro.move();
75         System.out.println("-----------------------------");
76
77         Airplane bumblebee=new Airplane(camaro);
78         bumblebee.move();
79         bumblebee.fly();
80     }
81 }

实例二:多重加密系统

? 某系统提供了一个数据加密功能,可以对字符串进行加密。最简单的加密算法通过对字母进行移位来实现,同时还提供了稍复杂的逆向输出加密,还提供了更为高级的求模加密。用户先使用最简单的加密算法对字符串进行加密,如果觉得还不够可以对加密之后的结果使用其他加密算法进行二次加密,当然也可以进行第三次加密。现使用装饰模式设计该多重加密系统。

  1 //抽象构建
  2 public interface Cipher
  3 {
  4     public String encrypt(String plainText);
  5 }
  6
  7 //具体构建
  8 public class SimpleCipher implements Cipher
  9 {
 10     public String encrypt(String plainText)
 11     {
 12         String str="";
 13         for(int i=0;i<plainText.length();i++)
 14         {
 15             char c=plainText.charAt(i);
 16             if(c>=‘a‘&&c<=‘z‘)
 17             {
 18                 c+=6;
 19             if(c>‘z‘) c-=26;
 20             if(c<‘a‘) c+=26;
 21             }
 22             if(c>=‘A‘&&c<=‘Z‘)
 23             {
 24                 c+=6;
 25             if(c>‘Z‘) c-=26;
 26             if(c<‘A‘) c+=26;
 27             }
 28             str+=c;
 29         }
 30         return str;
 31     }
 32 }
 33
 34 //抽象装饰类
 35 public class CipherDecorator implements Cipher
 36 {
 37     private Cipher cipher;
 38
 39     public CipherDecorator(Cipher cipher)
 40     {
 41         this.cipher=cipher;
 42     }
 43
 44     public String encrypt(String plainText)
 45     {
 46         return cipher.encrypt(plainText);
 47     }
 48 }
 49 //具体装饰类
 50 public class ComplexCipher extends CipherDecorator
 51 {
 52     public ComplexCipher(Cipher cipher)
 53     {
 54         super(cipher);
 55     }
 56
 57     public String encrypt(String plainText)
 58     {
 59         String result=super.encrypt(plainText);
 60         result=reverse(result);
 61         return result;
 62     }
 63
 64     public String reverse(String text)
 65     {
 66         String str="";
 67         for(int i=text.length();i>0;i--)
 68         {
 69             str+=text.substring(i-1,i);
 70         }
 71         return str;
 72     }
 73 }
 74
 75 //具体装饰类
 76 public class AdvancedCipher extends CipherDecorator
 77 {
 78     public AdvancedCipher(Cipher cipher)
 79     {
 80         super(cipher);
 81     }
 82
 83     public String encrypt(String plainText)
 84     {
 85         String result=super.encrypt(plainText);
 86         result=mod(result);
 87         return result;
 88     }
 89
 90     public String mod(String text)
 91     {
 92         String str="";
 93         for(int i=0;i<text.length();i++)
 94         {
 95             String c=String.valueOf(text.charAt(i)%6);
 96             str+=c;
 97         }
 98         return str;
 99     }
100 }
101
102 //客户端
103 public class Client
104 {
105     public static void main(String args[])
106     {
107         String password="sunnyLiu";  //明文
108         String cpassword;       //密文
109         Cipher sc,cc;
110
111         sc=new SimpleCipher();
112         cpassword=sc.encrypt(password);
113         System.out.println(cpassword);
114         System.out.println("---------------------");
115
116         cc=new ComplexCipher(sc);
117         cpassword=cc.encrypt(password);
118         System.out.println(cpassword);
119         System.out.println("---------------------");
120
121         /*
122         ac=new AdvancedCipher(cc);
123         cpassword=ac.encrypt(password);
124         System.out.println(cpassword);
125         System.out.println("---------------------");
126         */
127     }
128 }

模式优缺点

优点

? 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。

? 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。

? 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

? 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点

? 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。

? 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

模式适用环境

在以下情况下可以使用装饰模式:

? 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

? 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。

? 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类)。

模式应用

(1) 在javax.swing包中,可以通过装饰模式动态给一些构件增加新的行为或改善其外观显示。

? 如JList构件本身并不支持直接滚动,即没有滚动条,要创建可以滚动的列表,可以使用如下代码实现:

1 JList list = new JList();
2 JScrollPane sp = new JScrollPane(list); 

(2) 装饰模式在JDK中最经典的实例是Java IO。

? 以InputStream为例:

抽象装饰类:FilterInputStream

1 ……
2 protected volatile InputStream in;
3 protected FilterInputStream(InputStream in) {
4 this.in = in;
5 }
6 …… 

角色分配:

? 抽象构件类:InputStream

? 具体构件类:FileInputStream、ByteArrayInputStream等

? 抽象装饰类:FilterInputStream

? 具体装饰类:BufferedInputStream、DataInputStream等

客户端使用:

1 ……
2 FileInputStream inFS=new FileInputStream("temp/fileSrc.txt");
3 BufferedInputStream inBS=new BufferedInputStream(inFS);
4 //定义一个字节数组,用于存放缓冲数据
5 byte[] data = new byte[1024];
6 inBS.read(data);
7 …… 

模式扩展

装饰模式的简化-需要注意的问题

? 一个装饰类的接口必须与被装饰类的接口保持相同,对于客户端来说无论是装饰之前的对象还是装饰之后的对象都可以一致对待。

? 尽量保持具体构件类Component作为一个“轻”类,也就是说不要把太多的逻辑和状态放在具体构件类中,可以通过装饰类对其进行扩展。

? 如果只有一个具体构件类而没有抽象构件类,那么抽象装饰类可以作为具体构件类的直接子类。

装饰模式的简化

透明装饰模式(多重加密系统)

? 在透明装饰模式中,要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该声明具体构件类型和具体装饰类型,而应该全部声明为抽象构件类型。

1 Cipher sc,cc,ac;
2 sc=new SimpleCipher();
3 cc=new ComplexCipher(sc);
4 ac=new AdvancedCipher(cc); 

半透明装饰模式(变形金刚)

? 大多数装饰模式都是半透明(semi-transparent)的装饰模式,而不是完全透明(transparent)的。即允许用户在客户端声明具体装饰者类型的对象,调用在具体装饰者中新增的方法。

1 Transform camaro;
2 camaro=new Car();
3 camaro.move();
4 Robot bumblebee=new Robot(camaro);
5 bumblebee.move();
6 bumblebee.say(); 

原文地址:https://www.cnblogs.com/WindSun/p/10263459.html

时间: 2024-11-01 14:19:58

装饰模式(包装模式)的相关文章

大话设计模式之装饰模式(包装模式)

装饰模式的结构 转发:http://www.cnblogs.com/java-my-life/archive/2012/04/20/2455726.html 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任.换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同.装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展. 装饰模式的类图如下: 在装饰模式中的角色有: ●

【设计模式】 模式PK:包装模式群PK

1.概述 我们讲了这么多的设计模式,大家有没有发觉在很多的模式中有些角色是不干活的?它们只是充当黔首作用,你有问题,找我,但我不处理,我让其他人处理.最典型的就是代理模式了,代理角色接收请求然后传递到被代理角色处理.门面模式也是一样,门面角色的任务就是把请求转发到子系统.类似这种结构的模式还有很多,我们先给这种类型的模式定义一个名字,叫做包装模式(wrappingpattern).注意,包装模式是一组模式而不是一个.包装模式包括哪些设计模式呢?包装模式包括:装饰模式.适配器模式.门面模式.代理模

包装模式就是这么简单啦

前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 前一篇已经讲解了代理模式了,今天要讲解的就是装饰模式啦~ 在看到FilterInputStream和FilterOutputStream时看到了之前常听见的装饰模式(对IO一定了解的同学可能都会知道那么一句话:在IO用得最多的就是装饰模式了)! 其实无论是代理模式还是装饰模式.本质上我认为就是对原有对象增强的方式~ 那么接下来就开始吧,如果文章有错误的地方请大家多多包涵,不吝在评论区指正哦~ 声明:本文使用JDK1.8 一.对象增强

Java设计模式之包装模式

有时候一个对象的方法可能不是我们想要的功能,我们希望能将这个方法覆写.而对于覆写,我们最直白的感觉就是通过子类继承的方式,但是有时候对于使用web开发而言,我们能知道获取对象的实现接口,而真正对象是属于哪个类我们并不知道,例如Connection接口,HttpServletResponse接口这样的,我们并不知道第三方Jar包或者别的框架具体的实现类,那么我们只能通过已知的接口方式来增强或改写某个对象的方法. 通常增强某个对象方法的方式有三种: ⑴ 使用子类继承某个实现类: ⑵ 使用包装设计模式

7 结构型模式之 - 装饰模式

装饰模式介绍:装饰模式也称为包装模式,是结构型模式之一,其使用一种对客户端透明的方式来动态地扩展对象的功能,同时它也是继承关系的一种替代方案之一.在现实生活中你也可以看见很多装饰模式的例子,或者可以大胆地说装饰模式无处不在,就拿人来说,人需要各式各样的衣着,不管你穿着怎样,但是,对于个人的本质来说是不变的,充其量只是在外面披上一层包装而已,这就是装饰模式,装饰物也许各不相同但是装饰的对象本质是不变的. 装饰模式的定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更加灵

《JAVA与模式》之装饰模式

装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的结构 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任.换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同.装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展. 装饰模式的类图如下: 在装饰模式中的角色有: ● 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象. ● 具体构件(ConcreteComponent)角色

【设计模式】 模式PK:装饰模式VS适配器模式

1.概述 装饰模式和适配器模式在通用类图上没有太多的相似点,差别比较大,但是它们的功能有相似的地方:都是包装作用,都是通过委托方式实现其功能.不同点是:装饰模式包装的是自己的兄弟类,隶属于同一个家族(相同接口或父类),适配器模式则修饰非血缘关系类,把一个非本家族的对象伪装成本家族的对象,注意是伪装,因此它的本质还是非相同接口的对象. 大家都应该听过丑小鸭的故事吧,我们今天就用这两种模式分别讲述丑小鸭的故事.话说鸭妈妈有5个孩子,其中4个孩子都是黄白相间的颜色,而最小的那只也就是叫做丑小鸭的那只,

《java与设计模式》之装饰模式详解&amp;Java IO中的装饰器模式

1 概述 在一个项目中,你会有非常多的因素考虑不到,特别是业务的变更,不时的冒出一个需求是很正常的情况.有三个继承关系的类:Father.Son.GrandSon,我们要在Son类上增强一些功能怎么办?给Son类增加方法吗?那对GrandSon的影响呢?特别是对GrandSon有多个的情况,你会怎么办?认真看完本文,你会找到你的答案. JavaIO中,像下面的嵌套语句是不是很常见,为什么要怎样定义呢?理解装饰模式后,你会找到答案. DataInputStream in = new DataInp

结构型模式 装饰模式

结构型模式 装饰模式 适用于:  装饰者模式(Decorator Pattern)动态的给一个对象添加一些额外的职责.就增加功能来说,此模式比生成子类更为灵活. /** * 结构型模式 装饰模式 * 装饰( Decorator )模式又叫做包装模式. * 通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案. * 装饰模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择地.按顺序地使用装饰功能包装对象. * */ #defi