装饰模式

概述

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 条评论
登录 后参与评论

相关文章

来自专栏海天一树

小朋友学C++(5):构造函数

构造函数,作用是完成对象的初始化工作。 可类比于:int a = 1;这里是给变量a赋初值。 构造函数是一种特殊的函数,首先构造函数名与类名是完全一致的,其次构...

2617
来自专栏python3

python3--object类,继承与派生,super方法,钻石继承问题

{'kind': '波斯猫', 'name': '小黑', 'sex': '公'}

991
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础-day10-代码题-继承&抽象类

Java基础-day10-代码题-继承&抽象类 1.门类继承题: 编写代码,实现如下功能: (1)定义一个门类, 包含3个属性:宽度width 和 高度hei...

4196
来自专栏web前端-

css3动画效果

transform:2D变形: 通过 CSS3 转换,我们能够对元素进行移动、缩放、转动、拉长或拉伸。转换方法:translate()/rotate()/sca...

954
来自专栏前端说吧

JS-随机div颜色

2557
来自专栏海天一树

小朋友学Java(7):继承

在学习Java的继承之前,可以先复习一下C++的继承: http://www.jianshu.com/p/bc9b7ddb141c 一、定义 继承就是子类(派生...

2515
来自专栏生信小驿站

ggplot2 easyplot①

ggplot2.stripchart是一个易于使用的函数(来自easyGgplot2包),使用ggplot2绘图系统和R软件生成条带图。 条形图也被称为一维散点...

1115
来自专栏Android先生

Android开发人员不得不学习的Vue.js基础

Vue是一套用于构建用户界面的渐进式框架。Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一...

702
来自专栏IMWeb前端团队

React 渲染机制解析

React渲染过程 我们都知道使用React可以使得网页的性能有很大的提高,本文具体探究它是通过什么样的渲染机制做到的。 在页面一开始打开的时候,React会调...

3296
来自专栏西安-晁州

js各种继承方式汇总

js中的各种继承实现汇总 首先定义一个父类: function Animal(name) { this.name = name || '动物' this...

3196

扫码关注云+社区