`

装饰器模式(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实例详解【结构型】

    装饰器模式(Decorator Pattern)是一种结构型设计模式,主要用于在运行时动态地给对象添加新的职责或行为,而不必改变现有对象的类定义。在面向对象编程中,装饰器模式提供了一种相对于继承更加灵活的方式来增强或...

    装饰器(Decorator)模式

    在《Element of Reusable Object-Oriented Software》中,GOF 对装饰器模式的用意进行了概述:Decorator Pattern――Attaches additional responsibilities to an object dynamically. Decorators provide a ...

    设计模式之装饰模式(Decorator Pattern)

    4. **具体装饰器(Concrete Decorator)**:实现了装饰器接口,为组件增加新的行为或属性。每个具体装饰器都对应一种特定的扩展功能。 装饰模式的优点在于其灵活性,它可以独立于原始对象进行扩展,不需要修改原有...

    装饰器模式[Decorator]

    装饰器模式(Decorator)是一种设计模式,它允许在运行时向对象添加新的行为或责任,而无需修改对象的源代码。这种模式属于结构型模式,是面向对象设计中的一种非常实用的技术。 装饰器模式的核心思想是通过将一个...

    c++-设计模式之装饰模式(Decorator)

    具体装饰器(Concrete Decorator):扩展装饰器的功能,提供额外的行为 总结 装饰模式通过在运行时动态地为对象添加功能,增强了系统的灵活性和可扩展性。它允许在不修改现有代码的情况下添加新的行为,非常适合于...

    设计模式C++学习之装饰模式(Decorator)

    4. 具体装饰(Concrete Decorator):装饰器的实现,添加了具体组件的特定增强功能。每个具体装饰类可以添加不同的行为,从而提供多种装饰方式。 举个例子,假设我们有一个`Coffee`类,表示基础的咖啡。`Coffee`...

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

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

    结构型模式之装饰模式(Decorator)

    4. **具体装饰器(Concrete Decorator)**:实现了装饰器的抽象方法,提供了具体的增强功能。每个具体装饰器都为原始组件增加特定的职责。 装饰模式的工作流程如下: 1. 客户端首先创建一个原始组件对象。 2. 然后...

    通过C#实现设计模式-装饰模式(DecoratorPattern).rar

    3、定义一个抽象的装饰器类Decorator,它实现了IComponent接口,并持有一个IComponent的引用。 4、创建具体的装饰器类了。例如,一个ConcreteDecoratorA类,它添加了额外的行为。 5、创建另一个装饰器...

    C#设计模式之Decorator 装饰模式

    4. 具体装饰器(Concrete Decorator):实现了装饰器的抽象方法,并添加新的行为或职责。 在"C#面向对象设计模式纵横谈(10):(结构型模式) Decorator 装饰模式.pdf"中,你可能会学习到如何定义这些角色以及它们之间...

    设计模式-装饰器模式

    装饰器模式是一种结构型设计模式,它允许在不修改对象本身的情况下动态地为对象添加新的行为或职责。这种模式在软件工程中广泛应用,特别是在需要扩展已有功能而不影响原有代码结构时。在iOS开发中,装饰器模式同样...

    [结构型模式] head first 设计模式之装饰者模式(decorator)

    4. 具体装饰器(Concrete Decorator):实现抽象装饰器接口,负责给组件对象添加新的行为或职责。 在给出的`factory.h`文件中,可能包含一个工厂类,用于创建和组装装饰者模式中的组件和装饰器。工厂方法可以动态地...

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

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

    JAVA设计模式学习12——装饰器模式

    装饰器模式是面向对象设计模式的一种,主要用于在不改变原有对象结构的情况下,动态地为对象增加新的功能。这种模式在Java中尤其常见,因为它允许我们遵循“开闭原则”——对扩展开放,对修改关闭。 装饰器模式的...

    WPF 装饰器Decorator 和 Adorner综合实例

    装饰器模式是一种设计模式,它允许我们在不修改原有对象的基础上,为对象添加新的行为或属性。在WPF中,Decorator类通常用于改变控件的外观,如添加边框、背景等。以标题中提到的"自定义边框"为例,我们可以创建一个...

    java Decorator装饰模式例子

    `Decorator`是装饰器,持有`DecoratorComponent`的引用,并实现了相同的操作方法。`AdditionalFeatureA`和`AdditionalFeatureB`是具体装饰器,分别添加了功能A和功能B。 通过以下代码,我们可以创建一个装饰器链并...

    基于JavaScript装饰器Decorator实现的通信库

    JavaScript装饰器(Decorator)是一种元编程机制,它允许在运行时修改或增强对象的功能,而无需更改其源代码。在JavaScript中,装饰器是函数,它们可以被附加到类声明、方法、访问器、属性或参数上。装饰器提供了一种...

    装饰器模式 完整示例代码

    装饰器模式通常由四个主要组件构成:组件(Component)、具体组件(Concrete Component)、装饰器(Decorator)和具体装饰器(Concrete Decorator)。让我们逐一解析这些角色: 1. **组件(Component)**:这是接口...

Global site tag (gtag.js) - Google Analytics