设计模式学习笔记--装饰(Decorator)模式


写在模式学习之前


       什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式;每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案;当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式。

       设计模式就是抽象出来的东西,它不是学出来的,是用出来的;或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以“模式专家”的角度来看,都是最佳的设计,不得不说是“最佳的模式实践”,这是因为你积累了很多的实践经验,知道“在什么场合代码应该怎么写”,这本身就是设计模式。

       有人说:“水平没到,学也白学,水平到了,无师自通”。诚然,模式背熟,依然可能写不出好代码,更别说设计出好框架;OOP理解及实践经验到达一定水平,同时也意味着总结了很多好的设计经验,但"无师自通",却也未必尽然,或者可以说,恰恰是在水平和经验的基础上,到了该系统的学习一下“模式”的时候了,学习一下专家总结的结果,印证一下自己的不足,对于提高水平还是很有帮助的。

       本系列的设计模式学习笔记,实际是对于《Java与模式》这本书的学习记录。


装饰(Decorator)定义


装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。

装饰模式使用原来被装饰的类的一个子类的实例,把客户端的调用委派到被装饰类。装饰模式的关键在于这种扩展是完全透明的。


结构图




所涉及的角色


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

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

(3)装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。虽然Decorator类不是一个抽象类,在实际应用中也不一定是抽象类,但是由于它的功能是一个抽象角色,因此也常常称它为抽象装饰。

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


代码实现

interface Component
{
	//商业方法
	void sampleOp();
}
class ConcreteComponent implements Component
{
	public ConcreteComponent()
	{
		//Write your code
	}
	//商业方法
	public void sampleOp()
	{
		//Write your code
	}
}
class Decorator implements Component
{
	private Component component;
	public Decorator(Component component)
	{
		this.component = component;
	}
	public Decorator()
	{
		//Write your code
	}
	//商业方法
	public void sampleOp()
	{
		component.sampleOp();
	}
}
class ConcreteDecorator extends Decorator
{
	//商业方法
	public void sampleOp()
	{
		super.sampleOp();
	}
}

装饰模式使用场景


(1)需要扩展一个类的功能,或给一个类增加附加责任。

(2)需要动态地给一个对象增加功能,这些功能可以再动态的撤销。

(3)需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使基础关系变得不现实。

个人感觉,除了JDK中IO类的设计,工作场景中几乎碰不到装饰模式的使用,完全不像适配器模式,随处可见。


使用装饰模式的优点和缺点


(1)装饰模式与继承的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态地决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。

(2)通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出更多不同行为的组合。而继承关系则没有这个优势,每一种不同的排列组合均需要事先通过子类的继承方式设计好。

(3)这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错。

(4)使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。


模式的简化


大多数情况下,装饰模式的实现都比本节的定义中给出的示意性实现要简单。对模式进行简化时,需要注意以下的情况:

(1)一个装饰类的接口必须与被装饰类的接口相容。ConcreteDecorator类和ConcreteComponent必须继承自一个共同的父类,这个在装饰模式结构图中就有说明,但是在实际使用时,如果在模式的实现上有所简化,就必须特别注意这一点。

(2)尽量保持Component作为一个“轻”类。抽象构件的职责是接口而不是存储数据吗,注意不要把太多的逻辑和状态放在Component类里。Component可以是接口、抽象类或者具体类。

(3)如果只有一个ComcreteComponent类而没有抽象的Component类(接口),那么Decorator类经常可以是ConcreteComponent的一个子类,如下图:


由上图可知,没有抽象的接口Component也是可以的,但ConcreteComponent就要扮演双重的角色。

(4)如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以吧Decorator和ConcreteDecorator的责任合并成一个类。甚至只有两个ConcreteDecorator类的情况下,也可以这样做;但是具体装饰类大于三个的话,使用一个单独的抽象装饰类就有必要了,如下图:


由上图可知,没有抽象的Decorator也是可以的,只是ConcreteDecorator需要扮演双重的角色。


透明性的要求


(1)最后,本节指出一个重要的实现问题,通常叫做针对抽象编程。装饰模式对客户端的透明性要求程序不要声明一个ConcreteDecorator类型的变量,而应当声明一个Component类型的变量。

(2)然而,纯碎的装饰模式很难找到。装饰模式的用意是在不改变接口的前提下,增强所考虑的类的性能。在增强性能的时候,往往需要建立新的公开的方法。这就导致了大多数的装饰模式的实现都是“半透明”(semi-transparent)的,而不是完全“透明”的。换言之,允许装饰模式改变接口,增加新的方法。这意味着客户端可以声明ConcreteDecorator类型的变量,从而可以调用ConcreteDecorator类才有的方法。

(3)半透明的装饰模式介于装饰模式和适配器模式之间的。适配器模式的用意是改变所考虑的类的接口,也可以通过改写一个或几个方法,或增加新的方法来增强或改变所考虑的类的功能。大多数的装饰模式实际上是半透明的装饰模式,这样的装饰模式也称做“半装饰、半适配器模式”。
(4)在模式研究圈子里,所谓半透明的装饰模式又叫做退化的(degenerate)装饰模式。


结构模式(Structural Pattern)小结


结构模式(Structural Pattern)一共有七种,分别是:适配器模式、装饰模式、合成模式、代理模式、享元模式、门面模式、桥梁模式。

大致总结如下:

 最大特点典型应用
适配器模式利用对象的功能,并转换其接口日常工作,入目尽是适配器,DAO适配,Cache功能适配,等等
装饰模式对象层面的功能增强,接口不变Java I/O类库的设计
合成模式树枝、叶子同样对待分类树、权限树等
代理模式代表人WebService 的本地代理,权限访问代理,引用计数代理等
享元模式共享对象,减小内存占用编译器系统,Java String
门面模式统一对外接口,方便调用基于SOA框架编程中,不同系统之间的接口
桥梁模式解耦大多数的驱动器,包括JDBC Driver

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值