装饰者模式

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

具体被装饰者和抽象装饰类都继承于抽象被装饰者类,继承的是类型,而不是行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。

装饰模式的角色

  抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。

  具体构件角色(Concrete Component):定义将要接收附加责任的类。

  装饰角色(Decorator):持有一个构件(Component)对象的引用,并定义一个与抽象构件接口一致的接口。

  具体装饰角色(Concrete Decorator):负责给构件对象“贴上”附加的责任。

装饰模式的特点

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

  装饰对象包含一个真实对象的引用(reference)。

  装饰对象接收所有来自客户端的请求,它把这些请求转发给真实的对象。

  装饰对象可以在转发这些请求之前或之后附加一些功能。

  这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。

代码

 public class Zhuangxiuzhe {
public static void main(String[] args) {
Zhuangxiuzhe zhuangxiuzhe=new Zhuangxiuzhe();
Component component=zhuangxiuzhe.new ConcreteComponent();
Component decorator=zhuangxiuzhe.new ConcreteDecorator1(component);
decorator.doMethod();
Component decorator2=zhuangxiuzhe.new ConcreteDecorator2(decorator);
decorator2.doMethod(); } interface Component { public void doMethod(); } class ConcreteComponent implements Component { public void doMethod() {
System.out.println("一般操作"); } }
abstract class Decorator implements Component{ protected Component component;
public Decorator(Component component){
this.component=component;
} }
class ConcreteDecorator1 extends Decorator{ public ConcreteDecorator1(Component component) {
super(component); }
public void test1(){
System.out.println("ConcreteDecorator1 额外操作");
} public void doMethod() {
super.component.doMethod();
test1();
}
}
class ConcreteDecorator2 extends Decorator{ public ConcreteDecorator2(Component component) {
super(component); } public void doMethod() {
super.component.doMethod();
test2();
} public void test2(){
System.out.println("ConcreteDecorator2 额外操作");
}
} }

执行结果

一般操作
ConcreteDecorator1 额外操作
一般操作
ConcreteDecorator1 额外操作
ConcreteDecorator2 额外操作


突然发现装修者模式跟责任链模式有点相同,自身都引用了抽象类,这样可以调用传入的包装类

区别在于功能上:责任链强调的是请求由谁来处理,而装修者模式则是对引入的对象的现有功能进行包装,增强改变

Java IO中的装饰模式

  在IO中,具体构件角色是节点流,装饰角色是过滤流

  FilterInputStream和FilterOutputStream是装饰角色,而其他派生自它们的类则是具体装饰角色。

我们来看看代码

抽象角色类InputStream

 public abstract class InputStream implements Closeable {

 //实现了read等方法
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
} }

具体角色类FileInputStream

 public
class FileInputStream extends InputStream{ }

抽象包装类FilterInputStream

 public
class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in; protected FilterInputStream(InputStream in) {
this.in = in;
} public int read() throws IOException {
return in.read();
} }

具体包装类BufferedInputStream

 public
class BufferedInputStream extends FilterInputStream { public BufferedInputStream(InputStream in) {
this(in, defaultBufferSize);
} //完成了设置抽象角色类的映射
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
} //read方法中调用fill()
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
else if (pos >= buffer.length) /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
} else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
} else { /* grow buffer */
int nsz = pos * 2;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
// Can't replace buf if there was an async close.
// Note: This would need to be changed if fill()
// is ever made accessible to multiple threads.
// But for now, the only way CAS can fail is via close.
// assert buf == null;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
} }

fill()方法中除了自身操作外,我们看到了 int n = getInIfOpen().read(buffer, pos, buffer.length - pos);

  private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}

在看看getInIfOpen()方法,我们就明白了 整个的过程

参考地址:

http://www.cnblogs.com/mengdd/archive/2013/02/12/2910302.html

http://blog.csdn.net/cai1213/article/details/8003445

http://xubindehao.iteye.com/blog/474636

《JAVA与模式》之装修者模式的更多相关文章

  1. JAVA设计模式之【装饰者模式】

    JAVA设计模式之[装饰者模式] 装饰模式 对新房进行装修并没有改变房屋的本质,但它可以让房子变得更漂亮.更温馨.更实用. 在软件设计中,对已有对象(新房)的功能进行扩展(装修). 把通用功能封装在装 ...

  2. 重学 Java 设计模式:实战工厂方法模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  3. 重学 Java 设计模式:实战抽象工厂模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  4. 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...

  5. 重学 Java 设计模式:实战享元模式「基于Redis秒杀,提供活动与库存信息查询场景」

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 程序员‍‍的上下文是什么? 很多时候一大部分编程开发的人员都只是关注于功能的实现,只 ...

  6. Java 的设计模式之一装饰者模式

    刚开始接触装饰者的设计模式,感觉挺难理解的,不够后来花了一个晚上的时间,终于有头绪了 装饰者设计模式:如果想对已经存在的对象进行装饰,那么就定义一个类,在类中对已经有的对象进行功能的增强或添加另外的行 ...

  7. Java设计模式12:装饰器模式

    装饰器模式 装饰器模式又称为包装(Wrapper)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...

  8. Java设计模式3:工厂方法模式

    工厂方法模式 工厂方法模式是类的创建模式.工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工厂推迟到子类中. 工厂方法模式 工厂方法模式是对简单工厂模式进一步抽象的结果. 假如是不使用反 ...

  9. Java设计模式2:简单工厂模式

    简单工厂模式 简单工厂模式是类的创建模式,又叫做静态工厂方法模式.简单工厂模式由一个工厂对象决定生产出哪一种产品类的实例. 为什么要使用简单工厂模式 原因很简单:解耦. A对象如果要调用B对象,最简单 ...

随机推荐

  1. Android开发——Android M(6.0) 权限解决方案

    Android开发--Android M(6.0) 权限解决方案 自从Android M(6.0)发布以来,权限管理相比以前有了很大的改变,很多程序员发现之前运行的好好的Android应用在Andro ...

  2. Discuz常见小问题-如何人为地添加用户并分配小组

    进入后台,在用户-添加用户中可以人为添加用户并分配权限

  3. 解决Android Studio无法下载sdk的问题

    因为google被墙了,android sdk无法下载.然后各种百度,都是说让设置代理,给的代理地址一般都是用的下面这个代理服务器: 大连东软信息学院镜像服务器地址: mirrors.neusoft. ...

  4. Android开发点滴 - 实现层级式导航(API 16+)

    在Jelly Bean(API 16)以前,为了实现顶部的导航菜单,程序员们不得不手工写代码, 神马在OnCreate啊,神马onOptionsItemSelected啊,但是,现在一切都是浮云了. ...

  5. Binary Search二分法搜索C++程序

    二分法基本上学计算机的都听过,但是有人不知道的就是其实二分法是减治法的思想. 所谓减治法和分治法有一个主要差别就是减治法是减去一般,就是分治之后只需要解决原问题的一半就可以了得到全局问题的解了.所以速 ...

  6. centos下安装配置mongodb

    1:安装mkdir -p /app/mongodb tar zxvf mongodb-linux-x86_64-rhel62-3.4.6.tgz vi .bash_profile PATH=$PATH ...

  7. h5画图表

    折线: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&q ...

  8. MAVEN创建JAVA的Web工程

    maven命令:http://blog.csdn.net/edward0830ly/article/details/8748986 1.创建MAVEN的Web工程 mvn archetype:gene ...

  9. logback debug 日志没有信息

    可能是项目绑定的日志不是logback的jar包,而是其他包,具体可查看tomcat启动日志 log4j:WARN No appenders could be found for logger (or ...

  10. Codeforces Round #234 (Div. 2) :A. Inna and Choose Options

    A. Inna and Choose Options time limit per test 1 second memory limit per test 256 megabytes input st ...