《Java设计模式》之装饰模式

装饰模式(Decorator)

1.    装饰模式(Decorator)的定义:又名包装(Wrapper)模式。装饰模式以对client透明的方式扩展对象的功能,是继承关系的一个替代方案。

2.    装饰模式以对client透明的方式动态的给一个对象附加上很多其它的责任。换言之client并不会觉的对象在装饰前和装饰后有什么差别。

3.    装饰模式能够在不创造很多其它的子类的模式下,将对象的功能加以扩展

4.    装饰模式与类继承的差别:

1)    装饰模式是一种动态行为,对已经存在类进行任意组合,而类的继承是一种静态的行为。一个类定义成什么样的,该类的对象便具有什么样的功能。无法动态的改变。

2)    装饰模式扩展的是对象的功能。不须要添加类的数量。而类继承扩展是类的功能。在继承的关系中,假设我们想添加一个对象的功能。我们仅仅能通过继承关系,在子类中添加两个方法。

3)    装饰与继承比較图:

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

5.    装饰模式把对client的调用委派给被装饰的类,装饰模式的关键在于这样的扩展全然透明的。

6.    装饰模式的构成:

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

相当于i/o流里面InputStream/OutputStream和Reader/Writer。

2)    详细的构建角色(ConcreteComponent):定义一个将要接受附加责任的类。

相当于i/o里面的FileOutputStream和FileInputStream。

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

相当于i/o里面的FilerOutputStream和FilterInputStream。

4)    详细的装饰角色(ConcreteDecorator):负责给构建对象“贴上”附加的责任。

相当于i/o流里面的BufferedOutputStream和BufferedInputStream以及DataOutputStream和DataInputSrtream。

7.    装饰模式的特点:

1)    装饰对象和真实对象具有同样的接口。这样client对象就能够以真实对象的同样的方式和装饰对象交互。

2)    装饰对象包括一个真实对象的引用(reference).

3)    装饰对象接受全部来自client的请求,它把这些请求转发给真实的对象。

4)    装饰对象能够在转发这些请求曾经或者以后添加一些附加的功能。这样就能确保在执行时,不用改动给定对象结构就能够在外部添加附加的功能。在面向对象的程序设计中,一般是使用继承的关系来扩展给定类的功能。

装饰模式的结构

  装饰模式以对客户透明的方式动态地给一个对象附加上很多其它的责任。换言之。client并不会认为对象在装饰前和装饰后有什么不同。装饰模式能够在不使用创造很多其它子类的情况下,将对象的功能加以扩展。

  装饰模式的类图例如以下:

  在装饰模式中的角色有:

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

  ●  详细构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。

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

  ●  详细装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。

源码

  抽象构件角色

  1. package com.bankht.Decorator;
  2. /**
  3. * @author: 特种兵—AK47
  4. * @创建时间:2012-6-26 上午09:21:22
  5. *
  6. * @类说明 :抽象构件角色
  7. */
  8. public interface Component {
  9. public void sampleOperation();
  10. }
package com.bankht.Decorator;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:21:22
 *
 * @类说明 :抽象构件角色
 */
public interface Component {

	public void sampleOperation();

}

 详细构件角色

  1. package com.bankht.Decorator;
  2. /**
  3. * @author: 特种兵—AK47
  4. * @创建时间:2012-6-26 上午09:22:05
  5. *
  6. * @类说明 :详细构件角色
  7. */
  8. public class ConcreteComponent implements Component {
  9. @Override
  10. public void sampleOperation() {
  11. // TODO Auto-generated method stub
  12. // 写相关的业务代码
  13. }
  14. }
package com.bankht.Decorator;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:22:05
 *
 * @类说明 :详细构件角色
 */
public class ConcreteComponent implements Component {

	@Override
	public void sampleOperation() {
		// TODO Auto-generated method stub
		// 写相关的业务代码
	}

}

  装饰角色

package com.bankht.Decorator;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:23:03
  4. *
  5. * @类说明 :装饰角色
  6. */
  7. public class Decorator implements Component {
  8. private Component component;
  9. public Decorator(Component component) {
  10. this.component = component;
  11. }
  12. @Override
  13. public void sampleOperation() {
  14. // 委派给构件
  15. component.sampleOperation();
  16. }
  17. }
package com.bankht.Decorator;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:23:03
 *
 * @类说明 :装饰角色
 */
public class Decorator implements Component {
	private Component component;

	public Decorator(Component component) {
		this.component = component;
	}

	@Override
	public void sampleOperation() {
		// 委派给构件
		component.sampleOperation();
	}

}

  详细装饰角色

package com.bankht.Decorator;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:23:34
  4. *
  5. * @类说明 :详细装饰角色
  6. */
  7. public class ConcreteDecoratorA extends Decorator {
  8. public ConcreteDecoratorA(Component component) {
  9. super(component);
  10. }
  11. @Override
  12. public void sampleOperation() {
  13. super.sampleOperation();
  14. // 写相关的业务代码
  15. }
  16. }
package com.bankht.Decorator;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:23:34
 *
 * @类说明 :详细装饰角色
 */
public class ConcreteDecoratorA extends Decorator {

	public ConcreteDecoratorA(Component component) {
		super(component);
	}

	@Override
	public void sampleOperation() {
		super.sampleOperation();
		// 写相关的业务代码
	}
}

package com.bankht.Decorator;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:23:34
  4. *
  5. * @类说明 :详细装饰角色
  6. */
  7. public class ConcreteDecoratorB extends Decorator {
  8. public ConcreteDecoratorB(Component component) {
  9. super(component);
  10. }
  11. @Override
  12. public void sampleOperation() {
  13. super.sampleOperation();
  14. // 写相关的业务代码
  15. }
  16. }
package com.bankht.Decorator;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:23:34
 *
 * @类说明 :详细装饰角色
 */
public class ConcreteDecoratorB extends Decorator {

	public ConcreteDecoratorB(Component component) {
		super(component);
	}

	@Override
	public void sampleOperation() {
		super.sampleOperation();
		// 写相关的业务代码
	}
}

齐天大圣的样例

  孙悟空有七十二般变化,他的每一种变化都给他带来一种附加的本领。他变成鱼儿时。就能够到水里游泳;他变成鸟儿时,就能够在天上飞行。

  本例中,Component的角色便由鼎鼎大名的齐天大圣扮演;ConcreteComponent的角色属于大圣的本尊。就是猢狲本人;Decorator的角色由大圣的七十二变扮演。而ConcreteDecorator的角色便是鱼儿、鸟儿等七十二般变化。

源码

  抽象构件角色“齐天大圣”接口定义了一个move()方法,这是全部的详细构件类和装饰类必须实现的。

package com.bankht.Decorator.wukong;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:28:23
  4. *
  5. * @类说明 :抽象构件角色“齐天大圣”接口定义了一个move()方法,这是全部的详细构件类和装饰类必须实现的。
  6. */
  7. // 大圣的尊号
  8. public interface TheGreatestSage {
  9. public void move();
  10. }
package com.bankht.Decorator.wukong;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:28:23
 *
 * @类说明 :抽象构件角色“齐天大圣”接口定义了一个move()方法,这是全部的详细构件类和装饰类必须实现的。

*/
// 大圣的尊号
public interface TheGreatestSage {

	public void move();
}

  详细构件角色“大圣本尊”猢狲类

package com.bankht.Decorator.wukong;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:28:50
  4. *
  5. * @类说明 :详细构件角色“大圣本尊”猢狲类
  6. */
  7. public class Monkey implements TheGreatestSage {
  8. @Override
  9. public void move() {
  10. // 代码
  11. System.out.println("Monkey Move");
  12. }
  13. }
package com.bankht.Decorator.wukong;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:28:50
 *
 * @类说明 :详细构件角色“大圣本尊”猢狲类
 */
public class Monkey implements TheGreatestSage {

	@Override
	public void move() {
		// 代码
		System.out.println("Monkey Move");
	}

}

  抽象装饰角色“七十二变”

package com.bankht.Decorator.wukong;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:29:24
  4. *
  5. * @类说明 :抽象装饰角色“七十二变”
  6. */
  7. public class Change implements TheGreatestSage {
  8. private TheGreatestSage sage;
  9. public Change(TheGreatestSage sage) {
  10. this.sage = sage;
  11. }
  12. @Override
  13. public void move() {
  14. // 代码
  15. sage.move();
  16. }
  17. }
package com.bankht.Decorator.wukong;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:29:24
 *
 * @类说明 :抽象装饰角色“七十二变”
 */
public class Change implements TheGreatestSage {
	private TheGreatestSage sage;

	public Change(TheGreatestSage sage) {
		this.sage = sage;
	}

	@Override
	public void move() {
		// 代码
		sage.move();
	}

}

  详细装饰角色“鱼儿”

package com.bankht.Decorator.wukong;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:29:47
  4. *
  5. * @类说明 :详细装饰角色“鱼儿”
  6. */
  7. public class Fish extends Change {
  8. public Fish(TheGreatestSage sage) {
  9. super(sage);
  10. }
  11. @Override
  12. public void move() {
  13. // 代码
  14. System.out.println("Fish Move");
  15. }
  16. }
package com.bankht.Decorator.wukong;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:29:47
 *
 * @类说明 :详细装饰角色“鱼儿”
 */
public class Fish extends Change {

	public Fish(TheGreatestSage sage) {
		super(sage);
	}

	@Override
	public void move() {
		// 代码
		System.out.println("Fish Move");
	}
}

  详细装饰角色“鸟儿”

package com.bankht.Decorator.wukong;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:30:11
  4. *
  5. * @类说明 :详细装饰角色“鸟儿”
  6. */
  7. public class Bird extends Change {
  8. public Bird(TheGreatestSage sage) {
  9. super(sage);
  10. }
  11. @Override
  12. public void move() {
  13. // 代码
  14. System.out.println("Bird Move");
  15. }
  16. }
package com.bankht.Decorator.wukong;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:30:11
 *
 * @类说明 :详细装饰角色“鸟儿”
 */
public class Bird extends Change {

	public Bird(TheGreatestSage sage) {
		super(sage);
	}

	@Override
	public void move() {
		// 代码
		System.out.println("Bird Move");
	}
}

 client类

package com.bankht.Decorator.wukong;

  1. /**
  2. * @author: 特种兵—AK47
  3. * @创建时间:2012-6-26 上午09:30:32
  4. *
  5. * @类说明 :client类
  6. */
  7. public class Client {
  8. public static void main(String[] args) {
  9. TheGreatestSage sage = new Monkey();
  10. // 第一种写法
  11. TheGreatestSage bird = new Bird(sage);
  12. TheGreatestSage fish = new Fish(bird);
  13. // 另外一种写法
  14. // TheGreatestSage fish = new Fish(new Bird(sage));
  15. fish.move();
  16. bird.move();
  17. }
  18. }
package com.bankht.Decorator.wukong;

/**
 * @author: 特种兵—AK47
 * @创建时间:2012-6-26 上午09:30:32
 *
 * @类说明 :client类
 */
public class Client {

	public static void main(String[] args) {
		TheGreatestSage sage = new Monkey();
		// 第一种写法
		TheGreatestSage bird = new Bird(sage);
		TheGreatestSage fish = new Fish(bird);
		// 另外一种写法
		// TheGreatestSage fish = new Fish(new Bird(sage));
		fish.move();
		bird.move();
	}

}

  “大圣本尊”是ConcreteComponent类,而“鸟儿”、“鱼儿”是装饰类。

要装饰的是“大圣本尊”,也即“猢狲”实例。

  上面的样例中,系统把大圣从一仅仅猢狲装饰成了一仅仅鸟儿(把鸟儿的功能加到了猢狲身上),然后又把鸟儿装饰成了一条鱼儿(把鱼儿的功能加到了猢狲+鸟儿身上,得到了猢狲+鸟儿+鱼儿)。

  如上图所看到的,大圣的变化首先将鸟儿的功能附加到了猢狲身上。然后又将鱼儿的功能附加到猢狲+鸟儿身上。

  

装饰模式的简化

  大多数情况下。装饰模式的实现都要比上面给出的示意性样例要简单。

  假设仅仅有一个ConcreteComponent类,那么能够考虑去掉抽象的Component类(接口),把Decorator作为一个ConcreteComponent子类。例如以下图所看到的:

  假设仅仅有一个ConcreteDecorator类。那么就没有必要建立一个单独的Decorator类,而能够把Decorator和ConcreteDecorator的责任合并成一个类。甚至在仅仅有两个ConcreteDecorator类的情况下,都能够这样做。例如以下图所看到的:

透明性的要求

  装饰模式对client的透明性要求程序不要声明一个ConcreteComponent类型的变量,而应当声明一个Component类型的变量。

  用孙悟空的样例来说,必须永远把孙悟空的全部变化都当成孙悟空来对待。而假设把老孙变成的鱼儿当成鱼儿,而不是老孙。那就被老孙骗了,而这时不应当发生的。

以下的做法是对的:

TheGreatestSage sage = new Monkey();

  1. TheGreatestSage bird = new Bird(sage);
TheGreatestSage sage = new Monkey();
TheGreatestSage bird = new Bird(sage);

  而以下的做法是不正确的:

Monkey sage = new Monkey();

  1. Bird bird = new Bird(sage);
Monkey sage = new Monkey();
Bird bird = new Bird(sage);

半透明的装饰模式

  然而。纯粹的装饰模式非常难找到。装饰模式的用意是在不改变接口的前提下,增强所考虑的类的性能。在增强性能的时候。往往须要建立新的公开的方法。即便是在孙大圣的系统里,也须要新的方法。比方齐天大圣类并没有飞行的能力。而鸟儿有。这就意味着鸟儿应当有一个新的fly()方法。

再比方,齐天大圣类并没有游泳的能力。而鱼儿有,这就意味着在鱼儿类里应当有一个新的swim()方法。

  这就导致了大多数的装饰模式的实现都是“半透明”的,而不是全然透明的。换言之,同意装饰模式改变接口,添加新的方法。这意味着client能够声明ConcreteDecorator类型的变量,从而能够调用ConcreteDecorator类中才有的方法:

TheGreatestSage sage = new Monkey();

  1. Bird bird = new Bird(sage);
  2. bird.fly();
TheGreatestSage sage = new Monkey();
Bird bird = new Bird(sage);
bird.fly();

  半透明的装饰模式是介于装饰模式和适配器模式之间的。适配器模式的用意是改变所考虑的类的接口,也能够通过改写一个或几个方法,或添加新的方法来增强或改变所考虑的类的功能。大多数的装饰模式实际上是半透明的装饰模式,这种装饰模式也称做半装饰、半适配器模式。

装饰模式的长处

  (1)装饰模式与继承关系的目的都是要扩展对象的功能,可是装饰模式能够提供比继承很多其它的灵活性。装饰模式同意系统动态决定“贴上”一个须要的“装饰”,或者除掉一个不须要的“装饰”。

继承关系则不同,继承关系是静态的,它在系统执行前就决定了。

  (2)通过使用不同的详细装饰类以及这些装饰类的排列组合。设计师能够创造出非常多不同行为的组合。

装饰模式的缺点

  因为使用装饰模式。能够比使用继承关系须要较少数目的类。

使用较少的类,当然使设计比較易于进行。可是,在还有一方面,使用装饰模式会产生比使用继承关系很多其它的对象。很多其它的对象会使得查错变得困难,特别是这些对象看上去都非常相像。


设计模式在JAVA I/O库中的应用

  装饰模式在Java语言中的最著名的应用莫过于Java I/O标准库的设计了。

  因为Java I/O库须要非常多性能的各种组合。假设这些性能都是用继承的方法实现的,那么每一种组合都须要一个类。这样就会造成大量性能反复的类出现。而假设採用装饰模式。那么类的数目就会大大降低。性能的反复也能够减至最少。因此装饰模式是Java I/O库的基本模式。

  Java I/O库的对象结构图例如以下。因为Java I/O的对象众多,因此仅仅画出InputStream的部分。

 依据上图能够看出:

  ●  抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。

  ●  详细构件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。

  ●  抽象装饰(Decorator)角色:由FilterInputStream扮演。

它实现了InputStream所规定的接口。

  ●  详细装饰(ConcreteDecorator)角色:由几个类扮演,各自是BufferedInputStream、DataInputStream以及两个不经常使用到的类LineNumberInputStream、PushbackInputStream。

半透明的装饰模式

  装饰模式和适配器模式都是“包装模式(Wrapper Pattern)”,它们都是通过封装其它对象达到设计的目的的,可是它们的形态有非常大差别。

  理想的装饰模式在对被装饰对象进行功能增强的同一时候。要求详细构件角色、装饰角色的接口与抽象构件角色的接口全然一致。而适配器模式则不然,一般而言,适配器模式并不要求对源对象的功能进行增强,可是会改变源对象的接口,以便和目标接口相符合。

  装饰模式有透明和半透明两种。这两种的差别就在于装饰角色的接口与抽象构件角色的接口是否全然一致。透明的装饰模式也就是理想的装饰模式。要求详细构件角色、装饰角色的接口与抽象构件角色的接口全然一致。相反,假设装饰角色的接口与抽象构件角色接口不一致,也就是说装饰角色的接口比抽象构件角色的接口宽的话,装饰角色实际上已经成了一个适配器角色,这样的装饰模式也是能够接受的,称为“半透明”的装饰模式。例如以下图所看到的。

  在适配器模式里面,适配器类的接口一般会与目标类的接口重叠,但往往并不全然同样。

换言之。适配器类的接口会比被装饰的目标类接口宽。

  显然,半透明的装饰模式实际上就是处于适配器模式与装饰模式之间的灰色地带。假设将装饰模式与适配器模式合并成为一个“包装模式”的话。那么半透明的装饰模式倒能够成为这样的合并后的“包装模式”的代表。

InputStream类型中的装饰模式

  InputStream类型中的装饰模式是半透明的。为了说明这一点,最好还是看一看作装饰模式的抽象构件角色的InputStream的源码。这个抽象类声明了九个方法,并给出了当中八个的实现,另外一个是抽象方法。须要由子类实现。

public abstract class InputStream implements Closeable {

  1. public abstract int read() throws IOException;
  2. public int read(byte b[]) throws IOException {}
  3. public int read(byte b[], int off, int len) throws IOException {}
  4. public long skip(long n) throws IOException {}
  5. public int available() throws IOException {}
  6. public void close() throws IOException {}
  7. public synchronized void mark(int readlimit) {}
  8. public synchronized void reset() throws IOException {}
  9. public boolean markSupported() {}
  10. }
public abstract class InputStream implements Closeable {

    public abstract int read() throws IOException;

    public int read(byte b[]) throws IOException {}

    public int read(byte b[], int off, int len) throws IOException {}

    public long skip(long n) throws IOException {}

    public int available() throws IOException {}

    public void close() throws IOException {}

    public synchronized void mark(int readlimit) {}

    public synchronized void reset() throws IOException {}

    public boolean markSupported() {}

}

  

  以下是作为装饰模式的抽象装饰角色FilterInputStream类的源码。能够看出,FilterInputStream的接口与InputStream的接口是全然一致的。也就是说,直到这一步。还是与装饰模式相符合的。

public class FilterInputStream extends InputStream {

  1. protected FilterInputStream(InputStream in) {}
  2. public int read() throws IOException {}
  3. public int read(byte b[]) throws IOException {}
  4. public int read(byte b[], int off, int len) throws IOException {}
  5. public long skip(long n) throws IOException {}
  6. public int available() throws IOException {}
  7. public void close() throws IOException {}
  8. public synchronized void mark(int readlimit) {}
  9. public synchronized void reset() throws IOException {}
  10. public boolean markSupported() {}
  11. }
public class FilterInputStream extends InputStream {
    protected FilterInputStream(InputStream in) {}

    public int read() throws IOException {}

    public int read(byte b[]) throws IOException {}

    public int read(byte b[], int off, int len) throws IOException {}

    public long skip(long n) throws IOException {}

    public int available() throws IOException {}

    public void close() throws IOException {}

    public synchronized void mark(int readlimit) {}

    public synchronized void reset() throws IOException {}

    public boolean markSupported() {}
}

 以下是详细装饰角色PushbackInputStream的源码。

public class PushbackInputStream extends FilterInputStream {

  1. private void ensureOpen() throws IOException {}
  2. public PushbackInputStream(InputStream in, int size) {}
  3. public PushbackInputStream(InputStream in) {}
  4. public int read() throws IOException {}
  5. public int read(byte[] b, int off, int len) throws IOException {}
  6. public void unread(int b) throws IOException {}
  7. public void unread(byte[] b, int off, int len) throws IOException {}
  8. public void unread(byte[] b) throws IOException {}
  9. public int available() throws IOException {}
  10. public long skip(long n) throws IOException {}
  11. public boolean markSupported() {}
  12. public synchronized void mark(int readlimit) {}
  13. public synchronized void reset() throws IOException {}
  14. public synchronized void close() throws IOException {}
  15. }
public class PushbackInputStream extends FilterInputStream {
    private void ensureOpen() throws IOException {}

    public PushbackInputStream(InputStream in, int size) {}

    public PushbackInputStream(InputStream in) {}

    public int read() throws IOException {}

    public int read(byte[] b, int off, int len) throws IOException {}

    public void unread(int b) throws IOException {}

    public void unread(byte[] b, int off, int len) throws IOException {}

    public void unread(byte[] b) throws IOException {}

    public int available() throws IOException {}

    public long skip(long n) throws IOException {}

    public boolean markSupported() {}

    public synchronized void mark(int readlimit) {}

    public synchronized void reset() throws IOException {}

    public synchronized void close() throws IOException {}
}

  查看源代码,你会发现,这个装饰类提供了额外的方法unread(),这就意味着PushbackInputStream是一个半透明的装饰类。

换言 之。它破坏了理想的装饰模式的要求。假设client持有一个类型为InputStream对象的引用in的话,那么假设in的真实类型是 PushbackInputStream的话,仅仅要client不须要使用unread()方法,那么client一般没有问题。可是假设client必须使用这种方法,就 必须进行向下类型转换。

将in的类型转换成为PushbackInputStream之后才可能调用这种方法。可是,这个类型转换意味着client必须知道它
拿到的引用是指向一个类型为PushbackInputStream的对象。这就破坏了使用装饰模式的原始用意。

  现实世界与理论总归是有一段差距的。纯粹的装饰模式在真实的系统中非常难找到。一般所遇到的,都是这样的半透明的装饰模式。



 

 以下是使用I/O流读取文件内容的简单操作演示样例。

public class IOTest {

  1. public static void main(String[] args) throws IOException {
  2. // 流式读取文件
  3. DataInputStream dis = null;
  4. try{
  5. dis = new DataInputStream(
  6. new BufferedInputStream(
  7. new FileInputStream("test.txt")
  8. )
  9. );
  10. //读取文件内容
  11. byte[] bs = new byte[dis.available()];
  12. dis.read(bs);
  13. String content = new String(bs);
  14. System.out.println(content);
  15. }finally{
  16. dis.close();
  17. }
  18. }
  19. }
public class IOTest {

    public static void main(String[] args) throws IOException {
        // 流式读取文件
        DataInputStream dis = null;
        try{
            dis = new DataInputStream(
                    new BufferedInputStream(
                            new FileInputStream("test.txt")
                    )
            );
            //读取文件内容
            byte[] bs = new byte[dis.available()];
            dis.read(bs);
            String content = new String(bs);
            System.out.println(content);
        }finally{
            dis.close();
        }
    }

}

  观察上面的代码。会发现最里层是一个FileInputStream对象,然后把它传递给一个BufferedInputStream对象,经过BufferedInputStream处理,再把处理后的对象传递给了DataInputStream对象进行处理,这个过程事实上就是装饰器的组装过程,FileInputStream对象相当于原始的被装饰的对象,而BufferedInputStream对象和DataInputStream对象则相当于装饰器。

本文借鉴:

http://blog.csdn.net/m13666368773/article/details/7691871

http://www.cnblogs.com/hnrainll/archive/2012/03/23/2414180.html

http://www.cnblogs.com/java-my-life/archive/2012/04/20/2455726.html

时间: 2024-10-01 04:09:55

《Java设计模式》之装饰模式的相关文章

JAVA设计模式之 装饰模式【Decorator Pattern】

一.概述 动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活.装饰模式是一种对象结构型模式.装饰模式是一种用于替代继承的技术,使用对象之间的关联关系取代类之间的继承关系.在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩充原有类的功能. 二.适用场景 装饰原有对象.在不改变原有对象的情况下扩展增强新功能/新特征..当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式. 三.UML类图 四

JAVA设计模式:装饰模式

前面我们学习了代理模式: 代理模式主要使用了java的多态,干活的是被代理类,代理类主要是接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,大家知根知底,你能做啥,我能做啥都清楚得很,同样一个接口. 本次我们学习下装饰模式: 装饰模式又称为包装模式,装饰模式以对客户端透明的方式扩展对象功能,相对于代理而言,代理是不让客户端知道真实对象的信息,装饰模式是基层关系的一个替代方案. 装饰模式是采用对客户端透明的方式动态的给一个对象添加了更多职责,对于原来被装

JAVA设计模式之装饰模式

装饰模式:动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. 例子:你要替一家咖啡店设计beverage类.beverage有很多种,并且可以添加许多的调料,比如蒸奶.豆浆.摩卡等. 1 public abstract class Beverage 2 { 3 String description = "Unknown Beverage"; 4 5 public String getDescription() 6 { 7 return description

Java——设计模式(装饰模式_IO)

 /* * 装饰设计模式: *  对一组对象的功能进行增强时,就能够使用该模式进行问题的解决; * 装饰和继承都能实现一样的特点:  就是进行功能的扩转增强. * */ public class TestIO4 { public static void main(String[] args) { Person p = new Person(); NewPerson np = new NewPerson(p); np.chifan();//使用增强后的功能. } } //原有的类 class 

浅谈JAVA设计模式之——装饰模式(Decorator)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/45464445 一.概述 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 二.适用性 1.在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职责. 2.处理那些可以撤消的职责. 3.当不能采用生成子类的方法进行扩充时. 三.参与者 1.Component 定义一个对象接口,可以给这些对象动态地添加职责. 2.Concrete

java设计模式(1)-------单例,工厂,值对象,装饰模式

      java设计模式(1) 先简单的介绍下设计模式吧:是一种解决问题的一种行之有效的思想:用于解决特定环境下.重复出现的特定问题的解决方案. 那为什么我们需要学习设计模式呢? 1.设计模式都是一些相对优秀的解决方案,很多问题都是典型的.有代表性的问题,学习设计模式,我们就不用自己从头来解决这些问题,相当于在巨人的肩膀上,复用这些方案即可,站的高看到远,就是要站在巨人的肩膀上把他们踩下去,嘿嘿. 2.设计模式已经成为专业人士的常用词汇,不懂不利于交流,能让你变得很牛逼哦. 3.能让你设计的

菜鸟版JAVA设计模式—适配器模式,装饰模式,代理模式异同

节前把3个设计模式的学习心得分享了一下,分别是适配器模式,装饰模式,代理模式. 但是似乎越写越有些迷糊,这三种模式都有着一些大同小异的地方,总是有些搞不清. 今天再重新学习下,把学习心得分享给大家一下.这次是结合的我工作中的实际项目. 设计模式,其实是一种解决方法,JAVA作为一种面向对象的语言,对于所有的设计模式在实现上,总是少不了对接口的实现,对抽象类的继承,有时候似乎是为了去实现接口而去写接口,所以在这三种模式的说明代码中,我们都定义了接口这些东西,所以才有了现在的混淆. 先不厌其烦的介绍

Java设计模式学习记录-装饰模式

前言 装饰模式也是一种结构型模式,主要是目的是相对于类与类之间的继承关系来说,使用装饰模式可以降低耦合度.JDK中有不少地方都使用到了装饰模式,例如Java的各种I/O流,javax.swing包中一些图形界面构件功能的增强等地方都运用了装饰模式. 装饰模式 定义 装饰模式的定义是:在不改变原类文件以及不使用继承的情况下,动态的扩展一个对象的功能.装饰模式是通过创建一个包装对象来实现的,也就是用装饰来包裹真实的对象. 举例 还是老规矩,举例说明,在给亲朋好友过生日时会买生日蛋糕,然后生日蛋糕又有

Java设计模式之认识阶段

设计模式是什么? 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结. 其本质就是继承与接口的组合应用. 为什么要用设计模? 使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.提高工作效率. 设计模式的分类: 设计模式按目的可分为三种类型,共23种. 创建型模式:单例模式.抽象工厂模式.建造者模式.工厂模式.原型模式. 结构型模式:适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式. 行为型模式:模版

java设计模式演示样例

创建模式 1.工厂方法模式(Factory Method)  将程序中创建对象的操作,单独出来处理,创建一个产品的工厂接口,把实际的工作转移到详细的子类.大大提高了系统扩展的柔性,接口的抽象化处理给相互依赖的对象创建提供了最好的抽象模式. public class TestFactoryMethod { public static void main(String[] args) { AnimalFactory af=new DogFactory(); Animal1 a=af.getAnima