设计模式——装饰模式

一、装饰模式的动机

装饰模式动机:买了新房(毛胚房)需要装修,对新房进行装修并没有改变房子居住的本质,但它让房子变得更漂亮,更加满足居家的要求。在软件设计中,我们也可以用类似的技术对原有对象的动能进行扩展,以获得更加符合用户需求的对象,这种技术在设计模式中被称为装饰模式。

在软件开发中,一般有两种方式可以实现给一个类或一个对象增加行为
1、继承机制
使用继承机制是给现有的类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法时静止的,用户不能控制增加行为的方式和时机。同时,根据“合成复用原则”,对类的功能进行扩展时,应该多用关联关系,少用继承关系。
2、关联机制
关联机制是一种更加灵活的方法,即将一个类的对象嵌入另一个对象中,由另一个对象来绝对是否调用嵌入对象的行为并扩展自己的行为。在软件开发阶段,关联关系虽然不会比继承关系减少编码量,但是到了软件维护阶段,由于关联关系使系统具有较好的耦合性,因此使得系统更加容易维护。关联关系的主要优势在于不会破坏类的封装性,缺点是相比于继承关系要创建很多的对象。

二、装饰模式定义

装饰模式定义:动态的给一个对象增加一些额外的的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。(其别名也可以成为包装器,与适配器模式的别名相同,但他们适用于不同的场合)。

三、装饰模式结构图

装饰模式结构图

 

1、Component(抽象构件)
抽象构件定义了对象的接口,可以给这些对象动态的增加职责(方法)。抽象构件是具体构件和装饰类的共同父类。它声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户的的透明操作。
2、ConcreteComponent(具体构件)
具体的构件定义了具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
3、Decorator(抽象装饰类)
抽象装饰类是抽象构件类的子类,用于给具体构件增加职责,但是具体的职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以装饰之前构件对象的方法,并通过子类扩展该方法,以达到装饰的目的。
4、ConcreteDecorator(具体的装饰类)
具体装饰类是抽象装饰类的子类,负责向构件中添加新的职责(方法)。每一个具体的装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法以便扩充对象的行为。

四、实现代码:

抽象构件类:

public interface Component {
	public void operation();
}

具体构件类:

public class ConcreteComponent implements Component{

	public void operation() {
		System.out.println("具体的操作");
		
	}
}

抽象装饰类:

public  class Decorator implements Component{
	private Component component;
	public Decorator(Component component) {
		this.component = component;
	}
	public void operation() {
		component.operation();
	}
}

具体装饰类:

public class ConcreteDecoratorB extends Decorator{
	public ConcreteDecoratorB(Component component) {
		super(component);
		addBehavior();
	}
	public void addBehavior() {
		System.out.println("添加的方法");
	}
}

客户端测试类:

public class Client {
	public static void main(String[] args) {
		Component component = new ConcreteComponent();
		//装饰之前
		component.operation();
		Decorator decorator = new ConcreteDecoratorB(component);
		//装饰之后
		decorator.operation();
	}
}

五、装饰模式的优缺点:

装饰模式的优点:
(1)装饰模式与继承关系的目的都是扩展对象的功能,但是装饰模式可以提供相比于继承更多的灵活性。
(2)可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而可以实现不同的行为。
(3)通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
(4)具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件和具体装饰类,在使用时在对其组合,原来代码无须改变,符合“开闭原则”。
装饰模式缺点:
(1)使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式不同,而不是它们的类或者属性不同,同事还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习和理解的难度。
(2)这种比继承更加灵活的特性,也同时意味着装饰模式比继承更加易于出错,排错也更加困难,对于多次装饰的对象,调试寻找错误可能需要逐级排查,较为繁琐。

六、装饰模式适用的环境

(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
(2)需要动态地给一个对象添加功能,这些功能也可以动态地撤销。
(3)当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类)。

七、装饰模式的简化

大多数情况下,装饰模式的实现比标准的结构图要简单,可以对装饰模式进行简化,在简化中注意一下问题:
(1)一个装饰类的接口必须与被装饰类的接口保持相同。对于客户端来说,无论是装饰之前的对象还是装饰之后的对象都可以同等对待。
(2)尽量保持具体构件类ConcreteComponent作为一个“轻”类,也就是说不要把太多的逻辑和状态放在具体的构件类中,可以通过装饰类对其扩展。
(3)如果只有一个具体构件类而没有抽象构件类,那么抽象装饰类可以直接作为具体构件类的子类。如下图所示

装饰类简化结构图

如果有一个具体的装饰类,那么就没有必要设计一个单独的抽象装饰类,可以把抽象装饰类和具体装饰类的职责合并在一起。

八、透明装饰模式和半透明装饰模式

(1)透明装饰模式
在透明装饰模式中,要求客户端完全针对抽象编程,装饰模式的透明性要求客户段程序不应该申明具体构件类型和具体装饰类型,而应该全部声明为抽象构件类型,也就是说可以使用

Component component = new ConcreteComponent();
Decorator decorator = new ConcreteDecoratorB(component);

不应该使用如下代码:

ConcreteDecoratorB decoratorB = new ConcreteDecoratorB(component);

(2)半透明装饰模式
然而,透明装饰模式在实际开发中很难找到。装饰模式的用意是在不改变接口的前提下,增强原有类的功能。在增强功能时,用户往往需要创建新的方法。实际上,大多数装饰模式都是半透明的装饰模式,而不是完全透明的装饰模式,即允许客户端声明具体装饰者类型的对象。半透明装饰模式最大的缺点在于不能实现多重装饰,但其设计相对简单,使用也非常方便。
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值