装饰模式

概述

23种设计模式之一,英文叫DecoratorPattern,中文也叫装饰模式、修饰模式。装饰模式是在不改变类文件和不使用继承的情况下,运行期动态扩展一个对象的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口(没有接口可以直接继承自原来的类)。修饰模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰模式是在运行时增加行为。

UML

实现

Component.java,接口。

public interface Component {   void operation();}

ConcreteComponent.java,原有类实现(需要扩展)。

public class ConcreteComponent implements Component {   public void operation() {      System.out.println("具体对象的操作");   }}

Decorator.java,抽象修饰类。

public abstract class Decorator implements Component {   protected Component component;   public Decorator(Component component) {      this.component = component;   }   public void operation() {      if (component !=null)        component.operation();   }}

ConcreteDecoratorA.java,实际修饰类A。

public class ConcreteDecoratorA extends Decorator {   public ConcreteDecoratorA(Component component) {      super(component);   }   @Override   public void operation() {      super.operation();      System.out.println("对象A扩展的操作");   }}

ConcreteDecoratorB.java,实际修饰类B。

public class ConcreteDecoratorB extends Decorator {   public ConcreteDecoratorB(Component component) {      super(component);   }   @Override   public void operation() {      super.operation();      System.out.println("对象B扩展的操作");   }}

DecoratorTest.java,客户端。

public class DecoratorTest {   public static void main(String[] args) {      Component component =         new ConcreteDecoratorB(        new ConcreteDecoratorA(        new ConcreteComponent()));      component.operation();   }}

输出结果:

具体对象的操作对象A扩展的操作对象B扩展的操作

上面客户端的调用方式是不是和如下的代码有些类似,没错,Java中的I/O类库使用的就是装饰模式。

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(""));

上面就是装饰模式的模型,如果有不明白,可以结合代码、UML、定义一起看一下。

实例

需求

一个窗口系统中的窗口,允许这个窗口内容滚动,我们希望给它添加水平或垂直滚动条(维基百科)。

实现

Window.java,窗口接口。

public interface Window {   public void draw();   public String getDescription();}

SimpleWindow.java,简单窗口,不带任何修饰。

public class SimpleWindow implements Window {   public void draw() {  // draw window   }   public String getDescription() {      return "simple window";   }}

WindowDecorator.java,窗口装饰抽象类。

public abstract class WindowDecoratorimplements Window {   protected Window decoratedWindow;// the Window being decorated   public WindowDecorator(Window decoratedWindow) {      this.decoratedWindow = decoratedWindow;   }}

HorizontalScrollBarDecorator.java,横向滚动条装饰类。

public 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";   }}

VerticalScrollBarDecorator.java,纵向滚动条装饰类。

public 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";   }}

DecoratedWindowTest.java,客户端。

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());   }}

输出结果:

simple window, including vertical scrollbars, including horizontal scrollbars

将不同的装饰区分开来,并且和原有的窗口分开,这样通过包装,我可以创建一个只带横向(纵向)滚动条的窗口,也可以创建不带滚动条的窗口,任意组合。

总结

装饰模式是不使用继承的情况下,可以动态扩展一个类,并且比继承更灵活(上面的实例)。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

jQuery Validate自定义各种验证方法jQuery Validate自定义各种验证方法

472
来自专栏coolblog.xyz技术专栏

Spring IOC 容器源码分析 - 创建原始 bean 对象

本篇文章是上一篇文章(创建单例 bean 的过程)的延续。在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程。本篇文章,我们就从战术的层...

1895
来自专栏Jacklin攻城狮

Objective-C Runtime:深入理解类与对象

常说Objective-C是一门动态语言,那么问题来了,这个动态表现在那些方面呢?

1014
来自专栏一“技”之长

Objective-C关于id引发的一些思考 原

    Objective-C是面向对象语言,但其中又并非全部是对象。在初学这门语言时,我常常从意识上将NS开头的类型与C语言原本的那些类型分割开来,假装他们之...

776
来自专栏LIN_ZONE

java基础---->Java的格式化输出

  在JavaSe5中,推出了C语言中printf()风格的格式化输出。这不仅使得控制输出的代码更加简单,同时也给与Java开发者对于输出格式与排列更大的控制能...

311
来自专栏滕先生的博客

OC最实用的runtime总结,面试、工作你看我就足够了!前言什么是runtime?如何应用运行时?

32212
来自专栏光变

2.2 ASM-类-接口和组件

ASM API对编译类进行生成和编辑,都是基于抽象类ClassVisitor实现的(参照表格 2.4)。 该类中的每一个方法都对应class文件中的同名的结构部...

591
来自专栏WD学习记录

ViewBag与ViewData

ViewBag.CurrentTime等同于ViewData["CurrentTime"]

492
来自专栏iOS技术杂谈

NSCopying和NSCoding对象序列化反序列化基础详解你要知道的NSCopying、NSCoding协议及对象序列化和反序列化都在这里

你要知道的NSCopying、NSCoding协议及对象序列化和反序列化都在这里 转载请注明出处 https://cloud.tencent.com/devel...

4138
来自专栏Java Web

Java 8——Lambda表达式

本文内容大部分来自《Java 8实战》一书 前言 在上一篇文章中,我们了解了利用行为参数化来传递代码有助于应对不断变化的需求,它允许你定义一个代码块来表示一个...

3113

扫码关注云+社区