链接地址:http://www.xx566.com/detail/125.html
学习I/O的时候,各种putStream常常会困扰新手,这时候总会说:Java I/O设计的时候使用了装饰(Decorator)模式对各种Stream做了包装,到后来学习Struts2的时候也提到了装饰(Decorator) 模式 ,struts2对ServletRequest做了装饰 ,那么到底什么是装饰(Decorator)模式呢,我们今天就来学习一下。
我们首先来看一下装饰模式的官方定义:Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.大概意思就是:对一个相同的接口动态的添加额外的功能,装饰器提供了一种灵活的子类扩展的功能。
翻阅一些资料,里面的解释是:动态的给一个对象增加一些额外的职责。就增加功能来说,他比生成子类更加灵活。装饰模式以对客户端透明的方式扩展对象的功 能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常 大量的功能。
不太明白哈,我们来研究一下装饰模式的UML设计图:
图中我们可以看到,在装饰模式中有四种角色:Component抽象构件,ConcreateComponent具体组件,Decorator抽象装饰角色,ConcreateDecorator具体抽象角色。
说白了,其实装饰模式的核心就是理清楚Component与Decorator的关系,也就是能够分清主体类与装饰类, wiki上关于装饰模式的讲解很详细,列举的例子也很典型,这里借用一下。
比如说:购买coffee,先忽略coffee添加的成分,简单的原味coffee(里面有water)就是主体类,在装饰模式中,必然有一个最基本、最 核心、最原始的接口或抽象类充当Component抽象构件。不过有的顾客喜欢加糖的、加牛奶的等等,牛奶、糖是coffee里额外添加的成分,起着装饰 coffee的作用,就是装饰类。
下面,我们通过代码,来深入理解装饰模式,首先我们抽象出一个coffee的主体,包含价格、成分,代码如下:
/**
* 抽象主体类
* User: Realfighter
* Date: 2014/8/16
* Time: 10:09
*/
public abstract class Coffee {
abstract double costs(); //coffee价格
abstract String contains();//coffee包含成分
}
当然,我们可以先构建一个基本的coffee实体,包含water,价格1元,代码如下:
/**
* 最基本的成分water
* User: Realfighter
* Date: 2014/8/16
* Time: 10:28
*/
public class CoffeeOnlyWater extends Coffee {
@Override
public double costs() {
return 1;
}
@Override
public String contains() {
return "water";
}
}
coffee主体好了,我们就需要根据客户的不同口味装饰成不同的coffee,首先我们抽象出一个coffee的装饰类,内部拥有coffee的引用,提供获取价格和成分的方法,代码如下:
/**
* coffee装饰类
* User: Realfighter
* Date: 2014/8/16
* Time: 10:30
*/
public abstract class CoffeeDecorator extends Coffee {
protected final Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
public double costs() {
return coffee.costs();
}
public String contains() {
return coffee.contains();
}
}
有了装饰类的抽象,我们就需要实实在在的去装饰coffee了,我们有两种装饰的成分,milk和sugar,添加sugar的coffee要昂贵1元,milk的昂贵2元,并且需要给客户说明真实的价格和成分,代码如下:
/**
* 装饰成分:糖sugar
* User: Realfighter
* Date: 2014/8/16
* Time: 10:43
*/
public class CoffeeAddSugar extends CoffeeDecorator {
public CoffeeAddSugar(Coffee coffee) {
super(coffee);
}
@Override
public double costs() {
//sugar额外加1元
return super.costs() + 1;
}
@Override
public String contains() {
return super.contains() + " sugar";
}
}
/**
* 装饰成分:牛奶milk
* User: Realfighter
* Date: 2014/8/16
* Time: 10:41
*/
public class CoffeeAddMilk extends CoffeeDecorator {
public CoffeeAddMilk(Coffee coffee) {
super(coffee);
}
@Override
public double costs() {
//milk额外加2元
return super.costs() + 2;
}
@Override
public String contains() {
return super.contains() + " milk";
}
}
好了,这样我们的公司就可以开张了,第一天来了三位顾客,在排队购买,第一个要了杯最普通的,第二位顾客在前者基础上加了milk牛奶,第三位顾客说要一杯和第二位顾客一样的,后来尝了尝,有点苦,另外加了点sugar糖,顺利营业了。
/**
* 客户来购买coffee
* User: Realfighter
* Date: 2014/8/16
* Time: 10:45
*/
public class Customer {
/**
* @param costs 价格
* @param contains 成分
*/
private static void print(int index, double costs, String contains) {
System.out.println("customer " + index + " >>> coffee costs:" + costs + ",contains:" + contains);
}
public static void main(String[] args) {
//第一杯coffee只是最基本的coffee
Coffee coffee = new CoffeeOnlyWater();
print(1, coffee.costs(), coffee.contains());
//第二杯coffee在前者基础上加了milk
coffee = new CoffeeAddMilk(coffee);
print(2, coffee.costs(), coffee.contains());
//第三杯coffee在第二杯基础上再加了sugar
coffee = new CoffeeAddSugar(coffee);
print(3, coffee.costs(), coffee.contains());
}
}
打印结果:
customer
1
>>>>> coffee costs:
1.0
,contains:water
customer
2
>>>>> coffee costs:
3.0
,contains:water milk
customer
3
>>>>> coffee costs:
4.0
,contains:water milk sugar