职责

  装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

  装饰模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能,使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。

  1,不改变原类文件。

  2,不使用继承。

  3,动态扩展。

实现细节

Component抽象构件角色:

  真实对象和装饰对象有相同的接口。这样,客户端对象就能够以与真实对象相同的方式同装饰对象交互。

ConcreteComponent 具体构件角色(真实对象):

   io流中的FileInputStream、FileOutputStream

Decorator装饰角色:

   持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。

ConcreteDecorator具体装饰角色:

  负责给构件对象增加新的责任。

装饰(Decorator)模式代码示例

代码

package com.cnki.decorator;

/**
* 抽象构建
* @author Administrator
*
*/
public interface ICar {
void move();
} //ConcreteComponent 具体构件角色(真实对象)
class Car implements ICar {
@Override
public void move() {
System.out.println("陆地上跑!");
}
} //Decorator装饰角色
class SuperCar implements ICar {
protected ICar car;
public SuperCar(ICar car) {
super();
this.car = car;
} @Override
public void move() {
car.move();
}
} //ConcreteDecorator具体装饰角色
class FlyCar extends SuperCar { public FlyCar(ICar car) {
super(car);
} public void fly(){
System.out.println("天上飞!");
} @Override
public void move() {
super.move();
fly();
} } //ConcreteDecorator具体装饰角色
class WaterCar extends SuperCar { public WaterCar(ICar car) {
super(car);
} public void swim(){
System.out.println("水上游!");
} @Override
public void move() {
super.move();
swim();
} } //ConcreteDecorator具体装饰角色
class AICar extends SuperCar { public AICar(ICar car) {
super(car);
} public void autoMove(){
System.out.println("自动跑!");
} @Override
public void move() {
super.move();
autoMove();
} }

测试

package com.cnki.decorator;

import java.io.FileInputStream;
import java.io.InputStreamReader; public class Client {
public static void main(String[] args) {
Car car = new Car();
car.move(); System.out.println("增加新的功能,飞行----------");
FlyCar flycar = new FlyCar(car);
flycar.move(); System.out.println("增加新的功能,水里游---------");
WaterCar waterCar = new WaterCar(car);
waterCar.move(); System.out.println("增加两个新的功能,飞行,水里游-------");
WaterCar waterCar2 = new WaterCar(new FlyCar(car));
waterCar2.move(); // Reader r = new BufferedReader(new InputStreamReader(new FileInputStream(new File("d:/a.txt")))); }
}

开发中使用的场景

  IO中输入流和输出流的设计

  Swing包中图形界面构件功能

  Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper 类,增强了request对象的功能。

  Struts2中,request,response,session对象的处理

IO流实现细节

  Component抽象构件角色:

  io流中的InputStream、OutputStream、Reader、Writer

  ConcreteComponent 具体构件角色:

  io流中的FileInputStream、FileOutputStream

  Decorator装饰角色:

  持有一个抽象构件的引用:io流中的FilterInputStream、FilterOutputStream

  ConcreteDecorator具体装饰角色:

  负责给构件对象增加新的责任。Io流中的BufferedOutputStream、BufferedInputStream等。

小结  

优点

  装饰模式(Decorator)也叫包装器模式(Wrapper)

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

  扩展对象功能,比继承灵活,不会导致类个数急剧增加

  可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象

  具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类。

  总之呢,装饰器模式就是一个可以非常灵活的动态扩展类功能的设计模式,它采用组合的方式取代继承,使得各个功能的扩展更加独立和灵活。

缺点

  产生很多小对象。大量小对象占据内存,一定程度上影响性能。

  装饰模式易于出错,调试排查比较麻烦。

装饰模式和桥接模式的区别

  两个模式都是为了解决过多子类对象问题。但他们诱因不一样。

  桥模式是对象自身现有机制沿着多个维度变化,是既有部分不稳定。

  装饰模式是为了增加新的功能。

④ 设计模式的艺术-10.装饰(Decorator)模式的更多相关文章

  1. 设计模式C++描述----10.装饰(Decorator)模式

    一. 举例 我之前做过一个文件系统就叫 MyFileSys 吧,后来的话,客户想加入一些附加功能,比如压缩.加密.杀毒之类的操作,这些附加操作没有先后顺序,比如你可以先压缩再加密,也可以先杀毒再压缩, ...

  2. 《Head First 设计模式》ch.3 装饰(Decorator)模式

    设计原则 类应该对修改关闭,对扩展开放(开放-关闭原则).在每个地方使用开放-关闭原则是一种浪费,也没有必要,因为这通常会引入新的抽象层次,增加代码复杂度.需要把注意力集中在设计中最有可能改变的地方. ...

  3. 设计模式(八)装饰器模式Decorator(结构型)

    设计模式(八)装饰器模式Decorator(结构型) 1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法 ...

  4. php设计模式课程---7、装饰器模式如何使用

    php设计模式课程---7.装饰器模式如何使用 一.总结 一句话总结: 装饰器的核心是获取了文章类整个类,而不是获取了文章内容,有了这个文章类,我想给你加多少装饰就给你加多少装饰(将文章这个类封装进去 ...

  5. 大型Java进阶专题(八)设计模式之适配器模式、装饰者模式和观察者模式

    前言 ​ 今天开始我们专题的第八课了.本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式. ...

  6. 设计模式(九)——装饰者模式(io源码分析)

    1 星巴克咖啡订单项目(咖啡馆): 1) 咖啡种类/单品咖啡:Espresso(意大利浓咖啡).ShortBlack.LongBlack(美式咖啡).Decaf(无因咖啡) 2) 调料:Milk.So ...

  7. 装饰(Decorator)模式

    1.装饰(Decorator)模式    动态给一个对象添加一些额外的职责.就增加功能来说,装饰模式比生成子类更为灵活.Component是定义一个对象接口.可以给这些对象动态地添加职责.Concre ...

  8. 设计模式之第10章-桥接模式(Java实现)

    设计模式之第10章-桥接模式(Java实现) “一入软件深似海,从此早睡是路人.黑夜给了我黑色的眼睛,我却用他去寻找八阿哥.”“怎么了,又来那么多的感慨啊.”“还能有什么啊,老板是说让换个APP做,这 ...

  9. 设计模式的征途—10.装饰(Decorator)模式

    虽然目前房价依旧很高,就连我所在的成都郊区(非中心城区)的房价均价都早已破万,但却还是阻挡不了大家对新房的渴望和买房的热情.如果大家买的是清水房,那么无疑还有一项艰巨的任务在等着大家,那就是装修.对新 ...

随机推荐

  1. centos快速安装lamp

    搭建MySQL数据库 使用 yum 安装 MySQL: yum install mysql-server -y 安装完成后,启动 MySQL 服务: service mysqld restart 设置 ...

  2. Hibernate(五)

    注解高级(原文再续书接上一回) 7.继承映射 第一种:InheritanceType.JOINED 查询时会出现很多join语句. package com.rong.entity.joined; im ...

  3. virtio是啥子

    这个山头今天好像要攻占下来了 guest os中的一些特权操作会被hypervhisor给接收,这里一个很重要的认识是:hypervisor是os的os,既然要访问资源,那么就需要经过整机资源的管理者 ...

  4. el表达式作用域查找顺序 注意:当属性名字相同时候 先找到是小的作用域 因为是从小到大开始找的

  5. bzoj2788-Festival

    题意 有 \(n\) 个变量,有两种限制,分别有 \(m_1,m_2\) 种.限制如下: \(a_x+1=a_y\) \(a_x\le a_y\) 求 \(\{x_i\}\) 集合的大小.\(n\le ...

  6. java 调试

    作为一名java开发程序员,或者有时候需要利用工具调试的时候,但是却感觉不会使用,其实只要记住四个键即可. 一般java开发工具使用的都是Eclipse或者MyEclipse,下面都有这几个键F5(进 ...

  7. vue中axios复用封装

    ajax2: function() { let that = this; return that .$http({ method: "get", url: "/Home/ ...

  8. P4169 [Violet]天使玩偶/SJY摆棋子

    题目背景 感谢@浮尘ii 提供的一组hack数据 题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅 ...

  9. JAVA里面"=="和euqals的区别

    (1)基本数据类型,用双等号“==”比较,比较的是他们的值,值类型是存储在内存中的栈中 (2)复合数据类型中, 当他们用“==”进行比较的时候,比较的是他们在内存中的存放地址,其变量在栈中仅仅是存储引 ...

  10. 前端跨域问题相关知识详解(原生js和jquery两种方法实现jsonp跨域)

    1.同源策略 同源策略(Same origin policy),它是由Netscape提出的一个著名的安全策略.同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正 ...