设计模式——装饰模式(Decorator)

要想正确理解设计模式,首先必须明确它是为了解决什么问题而提出来的。

设计模式学习笔记

——Shulin

转载请注明出处:http://blog.csdn.net/zhshulin

1、概念

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

但是纯粹的装饰模式很难找到,大多数的装饰模式的实现都是“半透明”的,而不是完全透明的。换言之,允许装饰模式改变接口,增加新的方法。半透明的装饰模式是介于装饰模式和适配器模式之间的。适配器模式的用意是改变所考虑的类的接口,也可以通过改写一个或几个方法,或增加新的方法来增强或改变所考虑的类的功能。

大多数的装饰模式实际上是半透明的装饰模式,这样的装饰模式也称做半装饰、半适配器模式。

2、针对的问题

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。不改变接口的前提下,增强所考虑的类的性能。

何时使用:

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

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

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

3、角色组成

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

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

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

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

4、举例说明

咖啡是一种饮料,咖啡的本质是咖啡豆+水磨出来的。咖啡店现在要卖各种口味的咖啡,如果不使用装饰模式,那么在销售系统中,各种不一样的咖啡都要产生一个类,如果有4中咖啡豆,5种口味,那么将要产生至少20个类(不包括混合口味),非常麻烦。使用了装饰模式,只需要11个类即可生产任意口味咖啡(包括混合口味)。

4.1、类图

4.2、源码

Beverage饮料接口

/**
 * 饮料接口
 * @author Administrator
 *
 */
public interface Beverage {
	//返回商品描述
	public String getDescription();
	//返回价格
	public double getPrice();
}

CoffeeBean1——具体被装饰的对象类1

public class CoffeeBean1 implements Beverage {
	private String description = "选了第一种咖啡豆";
	@Override
	public String getDescription() {
		return description;
	}
	@Override
	public double getPrice() {
		return 50;
	}

}

CoffeeBean2——具体被装饰的对象类2

public class CoffeeBean2 implements Beverage {
	private String description = "第二种咖啡豆!";
	@Override
	public String getDescription() {
		return description;
	}

	@Override
	public double getPrice() {
		return 100;
	}

}

Decorator——装饰类

public class Decorator implements Beverage {
	private String description = "我只是装饰器,不知道具体的描述";
	@Override
	public String getDescription() {
		return description;
	}
	@Override
	public double getPrice() {
		return 0;		//价格由子类来决定
	}

}

Milk——具体装饰类,给咖啡加入牛奶

public class Milk extends Decorator{
	private String description = "加了牛奶!";
	private Beverage beverage = null;
	public Milk(Beverage beverage){
		this.beverage = beverage;
	}
	public String getDescription(){
		return beverage.getDescription()+"\n"+description;
	}
	public double getPrice(){
		return beverage.getPrice()+20;	//20表示牛奶的价格
	}
}

Mocha——给咖啡加入摩卡

public class Mocha extends Decorator {
	private String description = "加了摩卡!";
	private Beverage beverage = null;
	public Mocha(Beverage beverage){
		this.beverage = beverage;
	}
	public String getDescription(){
		return beverage.getDescription()+"\n"+description;
	}
	public double getPrice(){
		return beverage.getPrice()+49;	//30表示摩卡的价格
	}
}

Soy——给咖啡加入豆浆

public class Soy extends Decorator {
	private String description = "加了豆浆!";
	private Beverage beverage = null;
	public Soy(Beverage beverage){
		this.beverage = beverage;
	}
	public String getDescription(){
		return beverage.getDescription()+"\n"+description;
	}
	public double getPrice(){
		return beverage.getPrice()+30;	//30表示豆浆的价格
	}
}

测试类:

public class Test {

	public static void main(String[] args) {
		Beverage beverage = new CoffeeBean1();	//选择了第一种咖啡豆磨制的咖啡
		beverage = new Mocha(beverage);		//为咖啡加了摩卡
		beverage = new Milk(beverage);
		System.out.println(beverage.getDescription()+"\n加了摩卡和牛奶的咖啡价格:"+beverage.getPrice());

	}
}

测试结果:

5、装饰模式和适配器模式的关系

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

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

  装饰模式有透明和半透明两种,这两种的区别就在于装饰角色的接口与抽象构件角色的接口是否完全一致。透明的装饰模式也就是理想的装饰模式,要求具体构件角色、装饰角色的接口与抽象构件角色的接口完全一致。相反,如果装饰角色的接口与抽象构件角色接口不一致,也就是说装饰角色的接口比抽象构件角色的接口宽的话,装饰角色实际上已经成了一个适配器角色,这种装饰模式也是可以接受的,称为“半透明”的装饰模式,如下图所示。

在适配器模式里面,适配器类的接口通常会与目标类的接口重叠,但往往并不完全相同。换言之,适配器类的接口会比被装饰的目标类接口宽。

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

6、透明性要求

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

  用上面的例子来说,必须永远把所有的饮料当成饮料来对待,而如果把饮料变成的加摩卡的饮料当成摩卡,而不是饮料,这是不应当发生的。下面的做法是对的:

Beverage beverage = new CoffeeBean1();
Beverage mochaBeverage = new Mocha(beverage);

而下面的做法是不对的:

Beverage beverage = new CoffeeBean1();
Mocha mochaBeverage = new Mocha(beverage);

7、半透明模式

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

这就导致了大多数的装饰模式的实现都是“半透明”的,而不是完全透明的。换言之,允许装饰模式改变接口,增加新的方法。这意味着客户端可以声明ConcreteDecorator类型的变量,从而可以调用ConcreteDecorator类中才有的方法:

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

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

8、优点

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

  (2)通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

9、缺点

使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

设计模式——装饰模式(Decorator)

时间: 2024-10-26 07:24:34

设计模式——装饰模式(Decorator)的相关文章

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

装饰模式(Decorator) : 动态的给一个对象加入一些额外的职能,就添加功能来说,装饰模式比生成子类更为灵活. 实例: ConcreteComponent:让Decorator对象为自己加入功能.有时候使用ConcreteComponent的派生类提供核心功能.在这样的情况就是用ConcreteComponent替代了Component的功能,并且装饰者是继承于ConcreteComponent的子类. Component:定义ConcreteComponent和Decorator类要实现

[工作中的设计模式]装饰模式decorator

一.模式解析 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的要点主要是: 1.需要对已有对象扩展新的功能,又不希望改变原有对象接口: 2.装饰者对象与原有对象需要继承相同接口,初始化装饰对象时将原有对象传入装饰对象: 3.可以对一个对象定义多个装饰着对象,进行分别装饰或者组合装饰 二.模式代码 1.抽象接口 package decorator.patten; public interface Component { pu

设计模式-装饰模式(Decorator Pattern)

Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.(动态地给一个对象添加一些额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活.) 装饰模式有四个角色:1.Component抽象构件Component

c++设计模式----装饰模式

前言 在实际开发时,你有没有碰到过这种问题:开发一个类,封装了一个对象的核心操作,而这些操作就是客户使用该类时都会去调用的操作:而有一些非核心的操作,可能会使用,也可能不会使用:现在该怎么办呢? 将这些非核心的操作全部放到类中,这样,一个类就包含了很多核心的操作和一些看似有关,但是又无关的操作:这就会使核心类发生"爆炸"的现象,从而使核心类失去了一定的价值,也使使用核心类的客户在核心操作和非核心操作中挣扎: 使用继承来扩展核心类,需要使用核心类时,直接建立核心类对象:当需要使用核心类扩

装饰模式Decorator

第三章 装饰模式Decorator  1.1 什么是装饰模式? 装饰模式Decorator,动态的给一些对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活 1.2装饰模式Decorator的结构图 Component是定义一个对象接口,可以给这些对象动态的添加职责. ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责. Decorator装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,

设计模式之三:装饰模式(Decorator)

装饰模式: 动态地给对象添加一些相关的职责.装饰模式相比与添加子类提供了一种更加灵活的方式. UML图如下所示: 感觉上图中关键的有这几点: Decorator与Component的聚合关系(即Decorator中存在一个Component类型的引用),由于这个聚合关系的存在,Decorator可以通过一个Component的引用调用Component的接口 Decorator与Component的继承关系,这个关系不是很容易理解.但是在这里联想到继承的里氏代换原则(父类出现的地方都可以替换成子

24种设计模式--装饰模式【Decorator Pattern】

装饰模式在中国使用的那实在是多,中国的文化是中庸文化,说话或做事情都不能太直接,需要有技巧的,比如说话吧,你要批评一个人,你不能一上来就说你这个做的不对,那个做的不对,你要先肯定他的成绩,表扬一下优点,然后再指出瑕疵,指出错误的地方,最后再来个激励,你修改了这些缺点后有那些好处,比如你能带更多的小兵,当个小头目等等,否则你一上来就是一顿批评,你瞅瞅看,肯定是不服气,顶撞甚至是直接“此处不养爷,自有养爷处”开溜哇.这是说话,那做事情也有很多,在山寨产品流行之前,假货很是比较盛行的,我在 2002

[设计模式]<4>. C++与装饰模式(decorator pattern)

原文地址: http://www.cnblogs.com/hebaichuanyeah/p/5612028.html 装饰模式是指,动态的为一个类增加职责(相对于继承). 截自<设计模式>装饰者的UML图 举个栗子,

设计模式 笔记 装饰模式 Decorator

//---------------------------15/04/17---------------------------- //Decorator 装饰模式----对象结构型模式 /* 1:意图: 动态地给一个对象添加额外的职业,就增加功能来说,Decorator模式相比生成子类更为灵活. 2:别名: 包装器(Wrapper) 3:动机: 4:适用性: 1>在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职责. 2>处理那些可以撤销的职责. 3>当不能采用生成子类的方法