转载请注明出处:http://blog.csdn.net/zhaoyanjun6/article/details/56488020

前言

在上面的几篇文章中,着重介绍了Java 中常见的 IO 相关知识,在学习的过程中,发现 IO 包中是用了大量的装饰器模式,为了彻底的学习 IO,今天就来揭开装饰器模式的面纱。

为了弄明白装饰器模式的本质,我查看了很多资料,发现有很多文章要么说的很苦涩,要么举的例子不恰当。

其实我们可以这样理解装饰器模式, 就拿自己举例子,你把自己裸体的样子,想象成被装饰的对象。你的鞋子,你的寸衣,你的外套,你的手表,你的帽子 等等,都是你的装饰物,你和这些装饰物,是装饰和被装饰的关系。

实例展示

好了,现在我们用代码的方法去理解这样概念。

首先,我们发现,不管是裸体的人,还是你的鞋子、帽子,都有展示的功能,我们称之为show 方法。

我们定义一个接口,它具有展示的功能,也就是show() ,

package com.user;

/**
* 定义接口
* @author T
*
*/
public interface AbstractPerson { //具有展示的功能
void show() ;
}

现在应该定义一个裸体的自己了,Me 类

package com.user;

/**
* 定义一个具体的人,就是被装饰者
* @author T
*
*/
public class Me implements AbstractPerson { @Override
public void show() {
System.out.println( "什么都没穿,我展示的是裸体");
} }

下面该定义,鞋子,帽子,手表等 装饰物,等等先别急,我们应该先定义一个鞋子,帽子,手表的抽象父类 AbstractClothes 。 其实抽象的父类有一个构造函数,构造函数里面的参数是抽象的人类,这里的用法很巧妙,这也是能够实现装饰功能的一个必不可少的步骤。

package com.user;

/**
* 定义抽象装饰物
* @author T
*
*/
public abstract class AbstractClothes implements AbstractPerson { AbstractPerson abstractPerson ; public AbstractClothes( AbstractPerson abstractPerson ){
this.abstractPerson = abstractPerson ;
} @Override
public void show() {
abstractPerson.show();
} }

下面开始定义,帽子装饰物  Hat 类, 继承 AbstractClothes 类

package com.user;

/**
* 帽子装饰物
* @author T
*
*/
public class Hat extends AbstractClothes { public Hat(AbstractPerson abstractPerson) {
super(abstractPerson);
} @Override
public void show() {
super.show();
say();
} public void say(){
System.out.println( "我展示一个帽子");
} }

定义鞋子装饰类 Shoes ,   继承 AbstractClothes 类

package com.user;

/**
* 鞋子装饰物
* @author T
*
*/
public class Shoes extends AbstractClothes { public Shoes(AbstractPerson abstractPerson) {
super(abstractPerson);
} @Override
public void show() {
super.show();
say();
} public void say(){
System.out.println( "我展示一双鞋子");
}
}

创建测试类 Test

package com.user;

public class Test {

    public static void main(String[] args) {

        //创建被装饰者
Me me = new Me() ; //裸体的人被装饰了帽子 ,具有了展示帽子的能力
Hat hat = new Hat( me ) ; // 带了帽子的人被装饰了鞋子,具有了展示鞋子的本领
Shoes shoes = new Shoes( hat ) ; shoes.show();
}
}

运行结果:

什么都没穿,我展示的是裸体
我展示一个帽子
我展示一双鞋子

装饰器模式的类图

在学习完了一个小例子之后,我们试着总结出装饰器模式的类图。

装饰器模式类图:

  • Component抽象构件角色:真实对象和装饰对象有相同的接口。这样,客户端对象就能够以与真实对象相同的方式同装饰对象交互。
  • ConcreteCompoent具体构建角色(真实对象):定义一个将要接收附加责任的类。
  • Decorator装饰角色:持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。
  • ConcreteDecorate具体装饰角色:负责给构件对象增加新的功能。

装模式在Java I/O库中的应用

IO流实现细节:

  • Component抽象构件角色:io流中的InputStream,OutputStream,Reader,Writer
  • ConcreteComponent具体构件角色:io流中的FileInputStream,FileOutputStream
  • Decorate装饰角色:持有抽象构件的引用,FilterInputStream,FilterOutputStream
  • ConcreteDecorate具体装饰角色:负责给构件对象添加新的责任,BufferedInputStream,BufferedOutputStream等

优点

  • 扩展对象功能,比继承灵活,不会导致类个数急剧增加。
  • 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象。
  • 具体构件类和具体装饰类可以独立变化,用户可以根据需要自己增加新的 具体构件子类和具体装饰子类。

缺点

  • 产生很多小对象。大量小的对象占据内存,一定程度上影响性能。
  • 装饰模式易出错,调试排查比较麻烦。
 

总结

  • 装饰模式(Decorate)也叫包装模式(Wrapper)
  • 装饰模式降低系统的耦合度,可以动态的增加或删除对象的责任,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类。

参考资料:

Java设计模式学习09——装饰模式

Java与模式:装饰(Decorator)模式

Java 装饰器模式详解的更多相关文章

  1. (十)装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

  2. 涉及模式之 装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

  3. Javascript设计模式之装饰者模式详解篇

    一.前言: 装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象. 装饰者模式的特点: 1. 在不改 ...

  4. JAVA装饰器模式

    Java程序员们应该对java.io对不会陌生,因为java.io包采用了装饰器模式. 一.定义: Decorator装饰器,顾名思义,就是动态地给一个对象添加一些额外的职责,就好比为房子进行装修一样 ...

  5. java 装饰器模式实现代码

    目录 1.实现装饰器模式 1.1.公共接口 1.2.接口实现 1.3.装饰器 1.4.装饰构件 1.5.测试装饰器 上图展示的是io流中的一个装饰者模式的代码结构 1.实现装饰器模式 汽车厂生产汽车实 ...

  6. python装饰器大详解

    1.作用域 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我要理解两点:a.在全局不能访问到局部定 ...

  7. python 函数及变量作用域及装饰器decorator @详解

    一.函数及变量的作用   在python程序中,函数都会创建一个新的作用域,又称为命名空间,当函数遇到变量时,Python就会到该函数的命名空间来寻找变量,因为Python一切都是对象,而在命名空间中 ...

  8. python装饰器使用详解

    装饰器 '''装饰器:就是闭包(闭包的一个应用场景) -- 把要被装饰的函数作为外层函数的参数通过闭包操作后返回一个替代版函数 优点: -- 丰富了原有函数的功能 -- 提高了程序的可拓展性''' 开 ...

  9. 进阶Python:装饰器 全面详解

    进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用 ...

随机推荐

  1. 使用vue开发微信公众号下SPA站点的填坑之旅

    原文发表于本人博客,点击进入使用vue开发微信公众号下SPA站点的填坑之旅 本文为我创业过程中,开发项目的填坑之旅.作为一个技术宅男,我的项目是做一个微信公众号,前后端全部自己搞定,不浪费国家一分钱^ ...

  2. 解决org.apache.shiro.session.UnknownSessionException: There is no session with id的问题

    一.背景 最近在整合了Spring+Shiro+Redis实现tomcat集群session共享的问题之后,发布以后运行以后发现老是会出现:org.apache.shiro.session.Unkno ...

  3. Ajax(javascript)案例

    一.注册案例(Get方式) 1.前台 <%@ page language="java" import="java.util.*" pageEncoding ...

  4. 【IT笔试面试题整理】链表

    如何准备 Linked list questions are extremely common These can range from simple (delete a node ina linke ...

  5. 【PyTorch深度学习60分钟快速入门 】Part0:系列介绍

      说明:本系列教程翻译自PyTorch官方教程<Deep Learning with PyTorch: A 60 Minute Blitz>,基于PyTorch 0.3.0.post4 ...

  6. 第15课-数据库开发及ado.net-数据库介绍,主键,外键,启动数据库,数据库身份验证方式,建表,分离数据库

    第15课-数据库开发及ado.net 数据库介绍,主键,外键,启动数据库,数据库身份验证方式,建表,分离数据库 1.  学习方法 2.  多涨见识 3.  比自己强的人一起,学习更强:比自己更聪明的人 ...

  7. MVC在filter中如何获取控制器名称和Action名称

    使用ActionExecutingContext对象可以获取控制器名称.Action名称.参数名称以及参数值.路由和Action返回值不影响结果. 在代码中 [AttributeUsage(Attri ...

  8. c# 导出text 文本文件

    /// <summary> /// 机构代码信息 /// </summary> public static void ExportT_XQJBQK_SLGAJGDM(DataT ...

  9. <mvn:default-servlet-handler/>标签作用

    servlet在找页面时,走的是dispatcherServlet路线.找不到的时候会报404 加上这个默认的servlet时候,servlet在找不到的时候会去找静态的内容.

  10. JVM调优的总结

    堆大小设置JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64为操作 ...