`
安静思考
  • 浏览: 12669 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

设计模式之装饰者模式

阅读更多

一、功能描述    

         装饰者模式可以在运行时期动态的扩展一个类对象的功能,向一个类对象而不是类增加额外的功能。装饰者模式可以看做是继承的替代,两者的不同处是:继承是在编译期间增加类(不是对象)的功能,而装饰者模式则是在运行时动态的添加功能到单个对象。

二、实现描述

         动态的向一个对象添加功能是由称之为装饰者的类来完成的,在创建这个装饰者的类的过程中,需要将原始被包装对象当做参数传递给装饰者的构造器。然后由这个装饰器利用原始类提供的基本功能进而实现额外的功能,需要注意的是装饰器的类必须与原始类具有相同接口。

三、实现过程

      这里用一个例子来描述实现过程。假设我们有一个实现了Window接口的窗口类,现在我们需要对这个窗口增加一个滚动功能,也就是需要在窗口上增加水平跟竖直滚动条,在Window接口中并没有增加滚动条功能的方法,要实现这个功能,我们可以写一个这个窗口类的子类ScrollingWindow,在这个子类中将窗口滚动功能加上,或者我们可以写一个具有滚动功能的装饰器类ScrollingWindowDecorator,然后将这个装饰器类动态的将这个功能增加到一个已存在的Window对象中。这么看来,这两种方式都可以。

        如果我们想增加边界功能到 Window上并且Window没有提供增加边界的方法 。这时,对于 ScrollingWindow这种实现方式来说,我们想增加边界到Window上,我们必须创建两个子类分别是:WindowWithBorder ScrollingWindowWithBorder。很明显,如果我们还想增加功能的时候这个问题就会引起类爆炸的问题。而对于装饰者这种实现方式,我们仅仅增加一个具有边界功能的装饰类BorderedWindowDecorator 即可。这样运行时,我们可以用 BorderedWindowDecorator或者 ScrollingWindowDecorator来装饰已存在的窗口对象或者两个装饰器同时使用。

四、具体实现

        参考上面的例子,一步步实现这个装饰器模式

  •  首先定义一个Window接口,提供一些基本的方法
// the Window interface
interface Window {
    public void draw(); // draws the Window
    public String getDescription(); // returns a description of the Window
}

 

  •  提供这个接口的简单实现
// implementation of a simple Window without any scrollbars
class SimpleWindow implements Window {
    public void draw() {
        // draw window
    }
 
    public String getDescription() {
        return "simple window";
    }
}

 

  •  定义装饰器的抽象类,所有的装饰器都会继承该抽象类,这个抽象类需要实现Window接口。

// abstract decorator class - note that it implements Window
abstract class WindowDecorator implements Window {
    protected Window decoratedWindow; // the Window being decorated
 
    public WindowDecorator (Window decoratedWindow) {
        this.decoratedWindow = decoratedWindow;
    }
}

 

  •  实现竖直滚动条装饰器
// the first concrete decorator which adds vertical scrollbar functionality
class VerticalScrollBarDecorator extends WindowDecorator {
    public VerticalScrollBarDecorator (Window decoratedWindow) {
        super(decoratedWindow);
    }
 
    public void draw() {
        drawVerticalScrollBar();
        decoratedWindow.draw();
    }
 
    private void drawVerticalScrollBar() {
        // draw the vertical scrollbar
    }
 
    public String getDescription() {
        return decoratedWindow.getDescription() + ", including vertical scrollbars";
    }
}

 

  •  实现水平滚动条装饰器
// the second concrete decorator which adds horizontal scrollbar functionality
class HorizontalScrollBarDecorator extends WindowDecorator {
    public HorizontalScrollBarDecorator (Window decoratedWindow) {
        super(decoratedWindow);
    }
 
    public void draw() {
        drawHorizontalScrollBar();
        decoratedWindow.draw();
    }
 
    private void drawHorizontalScrollBar() {
        // draw the horizontal scrollbar
    }
 
    public String getDescription() {
        return decoratedWindow.getDescription() + ", including horizontal scrollbars";
    }
}

 

  • 测试代码

public class DecoratedWindowTest {
    public static void main(String[] args) {
        // create a decorated Window with horizontal and vertical scrollbars
        Window decoratedWindow = new HorizontalScrollBarDecorator (
                new VerticalScrollBarDecorator(new SimpleWindow()));
 
        // print the Window's description
        System.out.println(decoratedWindow.getDescription());
    }
}

 

 

五、组成结构

        装饰者模式的组织结构可以由下面的图来说明:

下面分别介绍图中元素:

  • Component

        为被装饰的对象定义的接口。

  • ConcreteComponent 

        被装饰对象的接口实现类。

  • Decorator 

        维持一个Component对象的引用,并与Component接口保持一致(继承这个接口)

  • ConcreteDecorator 

        代表固定功能的装饰器类。

 

六、java类库中使用装饰者模式的例子

 

        在java类库中,大量的用到了装饰者模式,其中最突出的就是在java.io包中了。一开始我们学习java的io流的时候,可能看到这么多的类会一头雾水,但是,只要理解了装饰者模式,那么对于io包中的类便会一目了然了。比如说:FileInputStream类,就是一个被装饰的对象类,我们可以用BufferedInputStream去装饰它,也可以用LineNumberInputStream去装饰它,当然也可以两者一起来装饰。BufferedInputStream和LineNumberInputStream都继承自FilterInputStream,而FilterInputStream是一个抽象的装饰类。

下面这个图能更好的理解java的io包中的类的组织形式:



 






  • 大小: 23.8 KB
  • 大小: 53.7 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics