链接地址: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