设计模式之装饰器模式(decorator)
装饰器(decorator)模式又名包装器(Wrapper)模式,它的主要用途在于给一个对象动态的添加一些额外的职责。与生成子类相比,它更具有灵活性。
有时候,我们需要为一个对象而不是整个类添加一些新的功能,比如,给一个文本区添加一个滚动条的功能。我们可以使用继承机制来实现这一功能,但是这种方法不够灵活,我们无法控制文本区加滚动条的方式和时机。而且当文本区需要添加更多的功能时,比如边框等,需要创建新的类,而当需要组合使用这些功能时无疑将会引起类的爆炸。
我们可以使用一种更为灵活的方法,就是把文本区嵌入到滚动条中。而这个滚动条的类就相当于对文本区的一个装饰。这个装饰(滚动条)必须与被装饰的组件(文本区)继承自同一个接口,这样,用户就不必关心装饰的实现,因为这对他们来说是透明的。装饰会将用户的请求转发给相应的组件(即调用相关的方法),并可能在转发的前后做一些额外的动作(如添加滚动条)。通过这种方法,我们可以根据组合对文本区嵌套不同的装饰,从而添加任意多的功能。这种动态的对对象添加功能的方法不会引起类的爆炸,也具有了更多的灵活性。
JAVA中IO流的设计就大量运用了装饰模式。看看我们熟悉的代码:
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("..")));
层层包装,增强功能。这就是装饰模式的要旨。(当然红字部分用到了适配器模式).
UML图
抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这些对象动态地添加职责。
具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。可以给这个类的对象添加一些职责
抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口
具体装饰器角色(ConcreteDecorator):向组件添加职责。
java代码实现
package com.ihyperwin.designPattern.decorator;/** * 冰淇淋接口,抽象组件角色,也可设置成抽象类 * 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这些对象动态地添加职责。 * @author ihyperwin * */public interface IceCream { int price();}
package com.ihyperwin.designPattern.decorator;/** * 最基本的冰淇淋类,具体组件角色(ConcreteComponent) ,被装饰者,定义一个将要被装饰增加功能的类 * @author ihyperwin * */public class BaseIceCream implements IceCream{@Overridepublic int price() {return 2;//价格为2元}}
package com.ihyperwin.designPattern.decorator;/** * 抽象装饰器(Decorator):维持一个IceCream对象的实例,并定义一个与抽象组件角色IceCream接口一致的接口 * * @author ihyperwin * */public abstract class IceCreamDecorator implements IceCream{public IceCream iceCream;public abstract int price();}
package com.ihyperwin.designPattern.decorator;/** * 具体装饰器角色(ConcreteDecorator):向组件添加职责。加香草的冰淇淋,价格加2元。 * * @author ihyperwin * */public class VanillaIceCreamDecorator extends IceCreamDecorator {public VanillaIceCreamDecorator(IceCream iceCream) {this.iceCream = iceCream;}@Overridepublic int price() {return this.iceCream.price()+2;}}
package com.ihyperwin.designPattern.decorator;/** * 具体装饰器角色(ConcreteDecorator):向组件添加职责。加葡萄的冰淇淋,价格加3元 * @author ihyperwin * */public class GrapeIceCreamDecorator extends IceCreamDecorator{public GrapeIceCreamDecorator(IceCream iceCream){this.iceCream=iceCream;}@Overridepublic int price() {return this.iceCream.price()+3;}}
package com.ihyperwin.designPattern.decorator;/** * 具体装饰器角色(ConcreteDecorator):向组件添加职责。加草莓的冰淇淋,价格加4元 * @author ihyperwin * */public class StrawBerryIceCreamDecorator extends IceCreamDecorator{public StrawBerryIceCreamDecorator(IceCream iceCream){this.iceCream=iceCream;}@Overridepublic int price() {return this.iceCream.price()+4;}}
package com.ihyperwin.designPattern.decorator;public class Client {/** * @param args */public static void main(String[] args) {IceCream iceCream = new BaseIceCream();System.out.println("原味冰淇淋价格为:"+iceCream.price());IceCream vanillaIceCream = new VanillaIceCreamDecorator(iceCream);System.out.println("香草冰淇淋价格为:"+vanillaIceCream.price());IceCream grapeIceCream = new GrapeIceCreamDecorator(iceCream);System.out.println("葡萄冰淇淋价格为:"+grapeIceCream.price());IceCream strawBerryIceCream = new StrawBerryIceCreamDecorator(iceCream);System.out.println("草莓冰淇淋价格为:"+strawBerryIceCream.price());IceCream strawBerryGrapeIceCream = new GrapeIceCreamDecorator( new StrawBerryIceCreamDecorator(iceCream));System.out.println("加葡萄有加草莓冰淇淋价格为:"+strawBerryGrapeIceCream.price());IceCream vanillaStrawBerryGrapeIceCream =new VanillaIceCreamDecorator( new GrapeIceCreamDecorator( new StrawBerryIceCreamDecorator(iceCream)));System.out.println("加香草加葡萄有加草莓冰淇淋价格为:"+vanillaStrawBerryGrapeIceCream.price());IceCream twoGrapeIceCream = new GrapeIceCreamDecorator( new GrapeIceCreamDecorator(iceCream));System.out.println("加两层葡萄也可以,价格为:"+twoGrapeIceCream.price());}}