Java设计模式:装饰设计模式
来源:互联网 发布:大学生数据统计分析 编辑:程序博客网 时间:2024/06/07 02:23
设计背景:
中秋节快到了,到了吃月饼的时候了。假如月饼只有吃的功能,不具备送礼的功能(不允许对原功能进行增加)。但是我想用月饼送礼,我想给月饼添加一个送礼的功能又该怎么办呢?
装饰模式可以做到这一点,我们只需要创建一个月饼盒,将月饼添加到其中,让月饼盒拥有送礼的功能就可以了。
像这样的例子还有很多都是大同小异,下面我们就来学习一下装饰模式。
通过一个图形的例子初识装饰设计模式
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。
RedShapeDecorator 是实现了 ShapeDecorator 的实体类。
DecoratorPatternDemo,我们的演示类使用 RedShapeDecorator 来装饰 Shape 对象。
步骤 1
创建一个接口。
Shape.java
public interface Shape { void draw();}
步骤 2
创建实现接口的实体类。
Rectangle.java
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Shape: Rectangle"); }}
Circle.java
public class Circle implements Shape { @Override public void draw() { System.out.println("Shape: Circle"); }}
步骤 3
创建实现了 Shape 接口的抽象装饰类。
ShapeDecorator.java
public abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape){ this.decoratedShape = decoratedShape; } public void draw(){ decoratedShape.draw(); } }
步骤 4
创建扩展了 ShapeDecorator 类的实体装饰类。
RedShapeDecorator.java
public class RedShapeDecorator extends ShapeDecorator { public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); } @Override public void draw() { decoratedShape.draw(); setRedBorder(decoratedShape); } private void setRedBorder(Shape decoratedShape){ System.out.println("Border Color: Red"); }}
步骤 5
使用 RedShapeDecorator 来装饰 Shape 对象。
DecoratorPatternDemo.java
public class DecoratorPatternDemo { public static void main(String[] args) { Shape circle = new Circle(); Shape redCircle = new RedShapeDecorator(new Circle()); Shape redRectangle = new RedShapeDecorator(new Rectangle()); System.out.println("Circle with normal border"); circle.draw(); System.out.println("\nCircle of red border"); redCircle.draw(); System.out.println("\nRectangle of red border"); redRectangle.draw(); }}
步骤 6
验证输出。
Circle with normal borderShape: CircleCircle of red borderShape: CircleBorder Color: RedRectangle of red borderShape: RectangleBorder Color: Red
我来简单说一下这个例子:有一个图形接口Shape,有两个类实现了这个接口,他们分别是矩形Rectangle和圆形Circle。这两个子类都有draw方法显示自己是啥图形,但是你不甘心,想让Circle和Rectangle这两个类在不增加方法的前提下实现显示自身颜色的功能。不能修改类却要类能实现额外的功能,这怎么可能?所以我们采用装饰设计模式,我们创建了抽象装饰类ShapeDecorator 实现 Shape接口。再创建扩展了 ShapeDecorator 类的实体装饰类RedShapeDecorator.java再看下面这句话:
Shape redRectangle = new RedShapeDecorator(new Rectangle());
通过RedShapeDecorator把Rectangle”装饰“一下,你会惊奇的发现在不增加Rectangle方法的前提下,Rectangle的draw方法“增强了”(改变了)。
这里Rectangle就是月饼,RedShapeDecorator是月饼盒,经过月饼盒的装饰它就有了别的功能!
装饰设计模式的特点
(1)装饰者和被装饰者有相同的接口(或有相同的父类)。
(2)装饰者保存了一个被装饰者的引用。
(3)装饰者接受所有客户端的请求,并且这些请求最终都会返回给被装饰者。
(4)在运行时动态地为对象添加方法,不必改变对象的结构。
(5)装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
(6) 动态增加功能,动态撤销。
(7)缺点:多层装饰比较复杂
装饰设计模式其实就在你身边
装饰者模式在Java中经常出现的地方就是JavaIO。提到JavaIO,脑海中就冒出了大量的类:InputStream、FileInputStream、BufferedInputStream……等,真是头都大了,其实,这里面大部分都是装饰类,只要弄清楚这一点就容易理解了。我们来看看JavaIO是怎样使用装饰者模式的。
从字符流来分析,我们知道,有两个基类,分别是InputStream和OutputStream,它们也就是我们上面所述的Component基类。接着,它有如下子类:FileInputStream、StringBufferInputStream等,它们就代表了上面所述的ConcreteComponent,即装饰对象。此外,InputStream还有FilterInputStream这个子类,它就是一个抽象装饰者,即Decorator,那么它的子类:BufferedInputStream、DataInputStream等就是具体的装饰者了。那么,从装饰者模式的角度来看JavaIO,是不是更加容易理解了呢?
下面,我们来自己实现自己的JavaIO的装饰者。要实现的功能是:把一段话里面的每个单词的首字母大写。我们先新建一个类:UpperFirstWordInputStream.java
public class UpperFirstWordInputStream extends FilterInputStream { private int cBefore = 32; protected UpperFirstWordInputStream(InputStream in) { //由于FilterInputStream已经保存了装饰对象的引用,这里直接调用super即可 super(in); } public int read() throws IOException{ //根据前一个字符是否是空格来判断是否要大写 int c = super.read(); if(cBefore == 32) { cBefore = c; return (c == -1 ? c: Character.toUpperCase((char) c)); }else{ cBefore = c; return c; } }}
接着编写一个测试类:InputTest.java
public class InputTest { public static void main(String[] args) throws IOException { int c; StringBuffer sb = new StringBuffer(); try { //这里用了两个装饰者,分别是BufferedInputStream和我们的UpperFirstWordInputStream InputStream in = new UpperFirstWordInputStream(new BufferedInputStream(new FileInputStream("test.txt"))); while((c = in.read()) >= 0) { sb.append((char) c); } System.out.println(sb); } catch (FileNotFoundException e) { e.printStackTrace(); } }}
(注意:上面的test.txt文件需要你自行创建,放到同一个文件夹内即可,内容可随意填写。)
最后,我们看下运行结果:
Here Are Some Words.
本文有大范围的摘抄结合自己的理解,希望能帮助到有疑惑的朋友。
参考资料:
http://www.runoob.com/design-pattern/decorator-pattern.html
http://blog.csdn.net/a553181867/article/details/52108423
- Java装饰设计模式
- Java 装饰设计模式
- Java 装饰设计模式
- java 装饰设计模式
- Java 装饰设计模式
- java 装饰设计模式
- Java装饰设计模式
- Java 装饰设计模式
- Java装饰设计模式
- Java 设计模式 --装饰模式
- Java 设计模式-----装饰模式
- java设计模式-装饰模式
- java设计模式---装饰模式
- java设计模式-装饰模式
- 【Java设计模式】装饰模式
- java设计模式-装饰模式
- java设计模式--装饰模式
- java设计模式---装饰模式
- Android属性动画完全解析
- 视频质量参考与无参考测试
- Android7.0 获取蓝牙设备电量
- Java EE eclipse安装之后新建Dynamic Web Project项目报错 Project facet Java version 1.8 is not supported.
- Sql性能优化之LIKE模糊查询
- Java设计模式:装饰设计模式
- jzoj5347. 【NOIP2017提高A组模拟9.5】遥远的金字塔 容斥
- 常见浏览器兼容性问题与解决方案?
- 使用Unity 实现依赖注入
- tomcat--1--because there was insufficient free space available after evicting expired cache entries
- hdu 1757 A Simple Math Problem(矩阵快速幂)
- mySQL之约束条件
- java面向对象(二)之继承
- 关于js浅拷贝深拷贝的思考