装饰模式

原创 2012年03月30日 12:34:11

实际案例

1、在我们现实生活中,我们会发现有很多种颜色,其实各种各样的颜色都是由三原色组合起来的,红黄蓝三种颜色,当我们随机搭配这三种颜色根据其程度又会出现各种各样不同的颜色,它里面实际上是一种组合,在这个里面,我们实际上使用了一种设计模式,装饰模式,类比我们的程序,将这三种颜色比作我们程序里面的三种不同的功能,当我们随机搭配的时候,就会完成不同的功能,看实际案例2。

2、我们在java的IO流这个章节中,我们会发现有底层流,比如说字节和字符流,有缓冲流等等,看下面的程序:

FileOutputStream:基本的文件输出流   BufferedOutputStream:缓冲流  DataOutputStream :输出二进制数据的缓冲流,这三种流我们可以随机组合而实现不同功能

new BufferedOutputStream(new FileOutputStream):带有缓冲流的文件输出流

new DataOutputStream(new FileOutputStream):带有输出二进制数据的文件输出流

new DataOutputStream(new BufferedOutputStream(new FileOutputStream)):带有双层缓冲流的可以输出二进制数据的文件输出流

这样组合就实现了各种不同的功能,在IO流中大量使用了我们的装饰模式


装饰模式

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

装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展,是继承关系的一个替代方案。

装饰模式的角色

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

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

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

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


装饰模式特点:

(1) 装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
(2) 装饰对象包含一个真实对象的索引(reference)
(3) 装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。


装饰模式与继承的区别

装饰模式  :用来扩展特定对象的功能    不需要子类  动态地   运行时分配职责  防止由于子类而导致的复杂和混乱 导致很多子类产生,在一些场合,报漏类的层次
更多的灵活性     对于一个给定的对象,同时可能有不同的装饰对象,客户端可以通过它的需要选择合适的装饰对象发送消息。 对于所有可能的联合,客户期望
很容易增加

继承:用来扩展一类对象的功能     需要子类  静态地  编译时分派职  缺乏灵活性  导致很多子类产生

实现一个装饰模式,代码中会发现和代理模式有点类似:

package cn.com.decorator;

//创建一个抽象构件角色
public interface Component {
	public void makeColor();//调色
}
package cn.com.decorator;

//创建具体的构件角色
public class ConcreteComponent implements Component {
	@Override
	public void makeColor() {
		System.out.println("添加红色原料");
	}

}

package cn.com.decorator;

//创建装饰角色
public class Decorator implements Component {
	//持有一个构件对象的引用
	private Component component;
	public Decorator(Component component){
		this.component=component;
	}
	
	public void makeColor() {
		component.makeColor();
	}

}
package cn.com.decorator;
//具体装饰角色一
public class ConcreteDecorator1 extends Decorator{
	private Component component;
	public ConcreteDecorator1(Component component){
		super(component);
	}
	
	@Override
	public void makeColor() {
		super.makeColor();
		this.makeColor2();
	}
	
	//添加附加功能
	public void makeColor2(){
		System.out.println("添加黄色原料");
	}

}

package cn.com.decorator;
//具体装饰角色二
public class ConcreteDecorator2 extends Decorator{
	private Component component;
	public ConcreteDecorator2(Component component){
		super(component);
	}
	
	@Override
	public void makeColor() {
		super.makeColor();
		this.makeColor2();
	}
	
	//添加附加功能
	public void makeColor2(){
		System.out.println("添加蓝色原料");
	}

}
package cn.com.decorator;

//测试类
public class Test {
	public static void main(String[] args) {
		Component component = new ConcreteComponent();
		Component component1 = new ConcreteDecorator1(component);
		Component component2 = new ConcreteDecorator2(component1);
		component2.makeColor();

		// 另一种写法
		Component component4 = new ConcreteDecorator2(new ConcreteDecorator1(
				new ConcreteComponent()));
		component4.makeColor();

	}

}

以上代码会输出:添加红色原料 添加黄色原料 添加蓝色原料

其实,上面的代码跟IO流中:OutputStream  out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream()));一样

在其中ConcreteComponent()和FileOutputStream都是我们的具体构件角色,而ConcreteDecorator1、ConcreteDecorator2和

BufferedOutputStream以及DataOutputStream一样都是具体的装饰角色。


深入装饰模式

(1)模式功能
        装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象增加功能,相当于是改变了对象的外观。当装饰过后,从外部使用系统的角度看,就不再是使用原始的那个对象了,而是使用被一系列的装饰器装饰过后的对象。
        这样就能够灵活的改变一个对象的功能,只要动态组合的装饰器发生了改变,那么最终所得到的对象的功能也就发生了改变。
        变相的还得到了另外一个好处,那就是装饰器功能的复用,可以给一个对象多次增加同一个装饰器,也可以用同一个装饰器装饰不同的对象。

(2)对象组合
        前面已经讲到了,一个类的功能的扩展方式,可以是继承,也可以是功能更强大、更灵活的对象组合的方式。
        其实,现在在面向对象设计中,有一条很基本的规则就是“尽量使用对象组合,而不是对象继承”来扩展和复用功能。装饰模式的思考起点就是这个规则,可能有些朋友还不太熟悉什么是“对象组合”,下面介绍一下“对象组合”。

(3)装饰器
        装饰器实现了对被装饰对象的某些装饰功能,可以在装饰器里面调用被装饰对象的功能,获取相应的值,这其实是一种递归调用。
        在装饰器里不仅仅是可以给被装饰对象增加功能,还可以根据需要选择是否调用被装饰对象的功能,如果不调用被装饰对象的功能,那就变成完全重新实现了,相当于动态修改了被装饰对象的功能。
         另外一点,各个装饰器之间最好是完全独立的功能,不要有依赖,这样在进行装饰组合的时候,才没有先后顺序的限制,也就是先装饰谁和后装饰谁都应该是一样的,否则会大大降低装饰器组合的灵活性。

(4)装饰器和组件类的关系
         装饰器是用来装饰组件的,装饰器一定要实现和组件类一致的接口,保证它们是同一个类型,并具有同一个外观,这样组合完成的装饰才能够递归的调用下去。
        组件类是不知道装饰器的存在的,装饰器给组件添加功能是一种透明的包装,组件类毫不知情。需要改变的是外部使用组件类的地方,现在需要使用包装后的类,接口是一样的,但是具体的实现类发生了改变。

(5)退化形式
        如果仅仅只是想要添加一个功能,就没有必要再设计装饰器的抽象类了,直接在装饰器里面实现跟组件一样的接口,然后实现相应的装饰功能就可以了。但是建议最好还是设计上装饰器的抽象类,这样有利于程序的扩展。



Android设计模式之一个例子让你彻底明白装饰者模式(Decorator Pattern)

导读这篇文章中我不会使用概念性文字来说明装饰者模式,因为通常概念性的问题都很抽象,很难懂,使得读者很难明白到底为什么要使用这种设计模式,我们设计模式的诞生,肯定是前辈们在设计程序的时候遇到了某种困难,...
  • nugongahou110
  • nugongahou110
  • 2015年12月27日 19:40
  • 2970

设计模式-装饰模式(理解)

看了《大话设计模式》pdf版的装饰模式和其他博客上的一些讲解,第一遍很难get到讲解的点在哪。经国深思,记录下深思的结果。 装饰模式,其实就是用递归的方式实现了面向切面(接口)编程。面向切面...
  • Scalaaaaaa
  • Scalaaaaaa
  • 2016年07月12日 15:22
  • 259

Java 装饰模式 io流

Java 装饰模式 io流
  • u013803262
  • u013803262
  • 2017年02月24日 19:42
  • 324

设计模式第六站--桥接模式PK装饰模式

设计模式学到
  • YSC1123
  • YSC1123
  • 2014年05月17日 11:32
  • 1769

设计模式之八 --- 装饰模式(Decorator)

【1】基本概念           装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。 【2】简单分析           我们先来...
  • cjjky
  • cjjky
  • 2012年04月19日 20:12
  • 14361

装饰模式(python版)

装饰模式(python版)目录装饰模式python版 目录 什么是装饰模式 装饰模式UML图 装饰模式的python实现 题目 题目分析 实现代码结构图 代码实现 装饰模式总结什么是装饰模式装饰模式(...
  • u014148798
  • u014148798
  • 2016年08月19日 15:19
  • 285

扩展系统功能——装饰模式(四):透明与半透明装饰模式,装饰模式注意事项,装饰模式总结

12.4 透明装饰模式与半透明装饰模式       装饰模式虽好,但存在一个问题。如果客户端希望单独调用具体装饰类新增的方法,而不想通过抽象构件中声明的方法来调用新增方法时将遇到一些麻烦,我们通过一...
  • Mark_LQ
  • Mark_LQ
  • 2015年09月13日 12:10
  • 1112

简单Java代码实例助你通俗易懂的理解什么是装饰(者)设计模式 (Decorator)

首先抛开到处都有的文字概念。来看下面的例子。 现在以:人吃饭。这个需求为例。来讲解这个设计模式。 1.0:想当年,人们都比较朴实。吃饭就是简简单单的吃饭。 那么PersonBefore类里面一个简单的...
  • qq_27093465
  • qq_27093465
  • 2016年11月24日 15:34
  • 1014

从咖啡谈装饰模式

问题描述     星巴克要订做一个管理系统.他们的咖啡有不同的品牌,有latte(拿铁),卡布奇诺(cappuccino)等等当然以后肯定会改变,同时各种咖啡都可以加上milk(牛奶),soy(豆浆)...
  • dlf123321
  • dlf123321
  • 2013年07月08日 18:25
  • 1346

设计模式--策略模式,装饰模式

坚持着客户端代码是程序的入口,构造函数是类的入口为原则,对策略模式,装饰模式和代理模式理解整理如下:...
  • u012466304
  • u012466304
  • 2014年12月08日 12:57
  • 1950
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:装饰模式
举报原因:
原因补充:

(最多只允许输入30个字)