`

装饰器模式(Decorator)

 
阅读更多
装饰器模式的核心思想
Decorator装饰器,顾名思义,就是动态地给一个对象添加一些额外的职责,就好比为房子进行装修一样。因此,装饰器模式具有如下的特征:

Ø    它必须具有一个装饰的对象。

Ø    它必须拥有与被装饰对象相同的接口。

Ø    它可以给被装饰对象添加额外的功能。

用一句话总结就是:保持接口,增强性能。

装饰器通过包装一个装饰对象来扩展其功能,而又不改变其接口,这实际上是基于对象的适配器模式的一种变种。它与对象的适配器模式的异同点如下。

Ø    相同点:都拥有一个目标对象。

Ø    不同点:适配器模式需要实现另外一个接口,而装饰器模式必须实现该对象的接口。

换句话说,对象的适配器模式是把一个对象适配成了另一个对象,而装饰器模式将丰富目标对象的功能但不改变它的接口。如下图所示,对象的适配器模式将一个圆形变成了正方形,而装饰器模式则不改变它的圆形形状,但改变了它的外观颜色。



装饰器模式的模型图如下图所示,共包括如下3个元素。

Ø    接口类Sourcable:定义了目标对象的接口。

Ø    源类Source:是接口Sourcable的一个实现。

Ø    装饰器类:它用来对Source对象进行装饰,但又必须实现Sourcable接口,以不改变Source对象的接口,根据装饰作用的不同,可以拥有多个装饰器类。

为了演示多次装饰的效果,我们这里分别创建了3个装饰器,第一个装饰器Decorator1装饰Source对象,第二个装饰器Decorator2装饰被第一个装饰器装饰后的对象,第三个装饰器Decorator2装饰被第二个装饰器装饰后的对象。



下面来看具体的实现。

(1)Sourcable类定义了一个接口函数operation()。

public interface Sourcable {
    public void operation();

}

(2)Source是Sourcable的一个实现,其函数operation()负责往控制台输出一个字符串:原始类的方法。

public class Source implements Sourcable {
    public void operation() {

        System.out.println("原始类的方法");

    }

}

(3)装饰器类Decorator1采用了典型的对象适配器模式,它首先拥有一个Sourcable对象 source,该对象通过构造函数进行初始化。然后它实现了Sourcable.java接口,以期保持与source同样的接口,并在重写的 operation()函数中调用source的operation()函数,在调用前后可以实现自己的输出,这就是装饰器所扩展的功能。

public class Decorator1 implements Sourcable {
    private Sourcable source;

    public Decorator1(Sourcable source) {
        super();

        this.source = source;

    }

    public void operation() {
        System.out.println("第1个装饰器装饰前");

        source.operation();

        System.out.println("第1个装饰器装饰后");

    }

}

(4)装饰器类Decorator2是另一个装饰器,不同的是它装饰的内容不一样,即输出了不同的字符串。

public class Decorator2 implements Sourcable {
    private Sourcable source;

    public Decorator2(Sourcable source) {
        super();

        this.source = source;

    }

    public void operation() {
        System.out.println("第2个装饰器装饰前");

        source.operation();

        System.out.println("第2个装饰器装饰后");

    }

}

(5)装饰器类Decorator3是第三个装饰器,不同的是它装饰的内容不一样,即输出了不同的字符串。

public class Decorator3 implements Sourcable {
    private Sourcable source;

    public Decorator3(Sourcable source) {
        super();

        this.source = source;

    }

    public void operation() {
        System.out.println("第3个装饰器装饰前");

        source.operation();

        System.out.println("第3个装饰器装饰后");

    }

}

这时,我们就可以像使用对象的适配器模式一样来使用这些装饰器,使用不同的装饰器就可以达到不同的装饰效果。例如,首先需要创建一个源类对象source,然后根据将对象使用Decorator1来装饰,并以此使用Decorator2、 Decorator3进行装饰,装饰后的对象同样具有与source同样的接口。

public class DecoratorTest {
    public static void main(String[] args) {

        // 创建源类对象

        Sourcable source = new Source();

        // 装饰类对象

        Sourcable obj =

            new Decorator1(

                new Decorator2(

                        new Decorator3(source)

                )

            );

        // 调用目标类的方法

        obj.operation();

    }

}

运行该程序的输出如下:

第1个装饰器装饰前

第2个装饰器装饰前

第3个装饰器装饰前

原始类的方法

第3个装饰器装饰后

第2个装饰器装饰后

第1个装饰器装饰后

从输出的结果可以看出,原始类对象source依次被Decorator1、Decorator2、Decorator3进行了装饰。

12.2.2  何时使用装饰器模式
由此可见,装饰模式提供了即插即用的方法,在运行期间决定何时增加何种功能。装饰模式与继承关系的目的都是要 扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式让系统动态地决定“贴上”一个需要的“装饰”,或者除掉一个不需要的装饰。而继承则不 同,继承关系是静态的,它在系统运行前就决定了。可以通过使用不同的具体修饰类及这些装饰类的排列组合,设计可以创造更多不同行为的组合。虽然比继承要灵 活,这意味着它比继承更容易出错。

因此,装饰模式一般在以下情况使用:

Ø    需要扩展一个类的功能,或给一个类增加附加责任。

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

Ø    需要增加由一些基本的排列组合产生大量的功能,从而使继承关系变得不现实。

但也需要注意装饰模式的缺点:由于使用装饰模式可以比使用继承关系需要较少的目的类,但是在另一方面,使用装饰模式会产生比使用继承方式更多的对象。这在使用时进行错误查询变得更困难了,特别是这些对象看上去都很像。

Java中的应用—I/O输入/输出流管道的装饰器模式
Java的I/O库提供了一个称做链接(Chaining)的机制,可以将一个流处理器与另一个流处理器首尾相接,以其中之一的输出为输入,形成一个流管道的链接。

例如,DataInputStream流处理器可以把FileInputStream流对象的输出当做输入,将Byte类型的数据转换成Java的原始类型和String类型的数据,如下图所示。



类似地,向一个文件写入Byte类型的数据不是一个简单的过程。一个程序需要向一个文件里写入的数据往往都是 结构化的,而Byte类型则是原始类型。因此在写的时候必须经过转换。DataOutputStream流处理器可以接收原始数据类型和String数据 类型,而这个流处理器的输出数据则是Byte类型。也就是说DataOutputStream可以将源数据转换成Byte类型的数据,再输出来。

这样一来,就可以将DataOutputStream与FileOutputStream链接起来,程序就可以将原始数据类型和String类型的源数据写入这个链接好的双重管道里面,达到将结构化数据写到磁盘文件里面的目的,如下图所示。



因此,Java I/O库中的所有输入流、输出流的类都采用了装饰器模式,它们可以无限次地进行装饰转换,转换的目标就是得到自己想要的数据类型的流对象。

由流管道的装饰模式也可以得出,凡是具有过滤和管道特征的应用都属于装饰器模式,例如Java EE中的Filter过滤器、UNIX中的管道符等,都属于装饰模式。装饰模式在软件的应用中随处可见。

Java中的应用—Sitemesh装饰器
在开发Web及J2EE应用时,Web页面可能由不同的人所开发,因此开发出来的界面通常会千奇百怪。随着项目进一步的开发,统一界面风格的紧迫性会逐渐浮现出来。

为此,Sitemesh框架出现了。该框架采用了装饰器模式,它通过创建一个包装对象,也就是装饰器来包裹真实的对象。尽管它是由Java语言来实现的,但它能与其他Web应用很好集成。

它为每一个请求的页面进行修饰,附加上其他的内容后再返回给客户端,其实现思路如图所示。


假设用户请求的是body.jsp页面,则Sitemesh会为body.jsp分别添加头部文件header.jsp、菜单栏menu.jsp、底部文件foot.jsp,然后再返回给客户端。这种方式的优点是:

Ø    开发页面body.jsp时,不需要考虑站点布局,因此也不用新建框架页面,JSP页面的数量是实际请求的页面数量。

Ø    要修改站点的布局,只需要修改Sitemesh的装饰配置即可。

显然,Sitemesh的方式更符合人性化的开发方式。这正是由于它使用了装饰器模式,使得我们的开发只需要关注局部,而不用关注待装饰的内容。
分享到:
评论

相关推荐

    PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

    主要介绍了PHP设计模式:装饰器模式Decorator,结合实例形式分析了PHP装饰器模式Decorator相关概念、功能、原理、用法及操作注意事项,需要的朋友可以参考下

    装饰器(Decorator)模式

    装饰器(Decorator)模式 详细教程,简明易懂,非常清晰的,附带有代码示例。

    python使用装饰器(Decorator)的方式实现单例模式

    demo python使用装饰器(Decorator)的方式实现单例模式 functools.wraps 则可以将原函数对象的指定属性复制给包装函数对象, 默认有 __module__、__name__、__doc__,或者通过参数选择

    java设计模式之装饰器模式(Decorator)

    主要为大家详细介绍了java设计模式之装饰器模式Decorator,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    装饰器模式[Decorator]

    NULL 博文链接:https://xiangtui.iteye.com/blog/1033790

    c++设计模式-结构型模式-装饰器模式

    c++设计模式-结构型模式-装饰器模式;QT工程;c++简单源码; 装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

    java实现装饰器模式(Decorator Pattern)

    主要为大家详细介绍了java实现装饰器模式Decorator Pattern,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    设计模式_装饰器模式.zip

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 这种模式创建了一个装饰类,用来包装原有的类,并在...

    C#装饰器模式(Decorator Pattern)实例教程

    主要介绍了C#装饰器模式(Decorator Pattern),以一个完整实例形式讲述了C#装饰器模式的实现过程,有助于深入理解C#程序设计思想,需要的朋友可以参考下

    Java设计模式之装饰模式(Decorator模式)介绍

    主要介绍了Java设计模式之装饰模式(Decorator模式)介绍,本文讲解了为什么使用Decorator、如何使用装饰模式、Jive中的Decorator实现等内容,需要的朋友可以参考下

    装饰器设计模式

    控制访问,装饰器设计的四个名词,装饰器模式与代理模式的区别,

    jouryfirst#weekly-1#175.精读《设计模式 - Decorator 装饰器模式》1

    “就增加功能来说,Decorator 模式相比生成子类更为灵活” 这句话的含义是,组合比继承更灵活,当可拓展的功能很多时,继承方案会产生大量的子类,而组合可以提

    python装饰器decorator介绍

    一、装饰器decorator decorator设计模式允许动态地对现有的对象或函数包装以至于修改现有的职责和行为,简单地讲用来动态地扩展现有的功能。其实也就是其他语言中的AOP的概念,将对象或函数的真正功能也其他辅助的...

    深入了解Python装饰器的高级用法

    原文地址 ... 介绍 我写这篇文章的主要目的是...装饰器 vs 装饰器模式 Decorator模式是一个面向对象的设计模式,它允许动态地往现有的对象添加行为。当你装饰了一个对象,在某种程度上,你是在独立于同一个类的其他实例

    分析Python中设计模式之Decorator装饰器模式的要点

    主要介绍了Python中设计模式之Decorator装饰器模式模式,文中详细地讲解了装饰对象的相关加锁问题,需要的朋友可以参考下

    PHP设计模式之装饰器模式定义与用法详解

    什么是装饰器模式 作为一种结构型模式, 装饰器(Decorator)模式就是对一个已有结构增加”装饰”. 适配器模式, 是为现在有结构增加的是一个适配器类,.将一个类的接口,转换成客户期望的另外一个接口.适配器让原本接口...

    学习php设计模式 php实现装饰器模式(decorator)

    就增加功能来说,Decorator模式相比生成子类更为灵活【GOF95】 装饰模式是以对客户透明的方式动态地给一个对象附加上更多的职责。这也就是说,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不...

Global site tag (gtag.js) - Google Analytics