职责

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

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

  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. Maya脚本——重命名物体的名称

    该脚本用于将图1中的命名变更为图2中的,把maya中使用相同名称的物体都重命名为不同的名称. 重命名的规则是:组名_原名称_序号 查阅了maya的官方手册:http://download.autode ...

  2. nodejs 中on 和 emit

    首先测试用例: var EventEmitter = require('events').EventEmitter var life = new EventEmitter(); // life.on( ...

  3. Winform程序在XP系统上双击运行无反应解决方法

    右键程序,打开属性栏,在兼容性选项里以兼容模式运行该程序即可解决.

  4. 【bzoj4027】[HEOI2015]兔子与樱花 树形dp+贪心

    题目描述 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它 ...

  5. Java导出数据行写入到Excel表格:基于Apache POI

    Java导出数据行写入到Excel表格:基于Apache POI import java.io.File; import java.io.FileOutputStream; import org.ap ...

  6. Unity3D实现3D立体游戏原理及过程

    Unity3D实现3D立体游戏原理及过程 183 0 0     下面的教程是我今天整理的资料,教大家一步步完成自己的3D立体游戏,并向大家介绍一些3D成像的原理.     理论上,每个普通的非立体3 ...

  7. Splitter Control for Dialog

    原文链接地址:https://www.codeproject.com/Articles/595602/Splitter-Control-for-Dialog Introduction Yes, tha ...

  8. 解题:AHOI 2005 航线规划

    题面 这种不断删边的首先肯定想到时光倒流啊=.= 在最后剩下的连通图上跑出一棵搜索树,先将边权都赋为$1$,那么两点间的关键航线就是链上边权和,而每加入一条非树边$u,v$都会使得$u,v$链上的边的 ...

  9. jquery、css3动态显示百分比圆

    动态显示百分圆 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <m ...

  10. 洛谷P2345 奶牛集会

    题目背景 MooFest, 2004 Open 题目描述 约翰的N 头奶牛每年都会参加“哞哞大会”.哞哞大会是奶牛界的盛事.集会上的活动很 多,比如堆干草,跨栅栏,摸牛仔的屁股等等.它们参加活动时会聚 ...