Java设计模式之装饰者模式
摘要:装饰者模式相对来说是一种比较容易理解的模式。主要有组件(components)和装饰器(Decorator)组成。要求components和Decorator实现相同的接口或者抽象类(具体类的局限性太大)。
一:简介
装饰者模式(DecoratorPattern)、顾名思义。是用Decorator去装饰Component、因为实现了同一接口或者抽象类、Decorator同样可以装饰Decorator!通过这种模式我们也可以看出一个设计模式的设计原则:Classes should be open for extension, but closed for modification!下面同样通过对实际问题的分析来了解这种模式、最后对Java类库中的IO体系的设计模式进行一下简单了解。
Decorator Pattern: Attaches additional responsibility to anobject dynamically. Decorators provide a flexible alternative to subclassingfor extending functionality.
二:问题的引出
参照Head First Design Patterns。
对与星巴克咖啡我们都不会陌生、当然这里不会介绍他的编年史什么什么的、只是对其出售的咖啡的一种销售策略的价格做一下统计、这样当顾客点了他们想要的搭配的时候我们就可以知道最后的价格是多少。
假设有四种咖啡:HouseBlend、DarkRoaat、Decaf、Espresso。
同样有四种可以搭配的选择:Milk、Mocha、Soy、Whip。
这四种咖啡有不同的价格、同样四种搭配也有不同的价格。当我们把这个单子拿给顾客的时候、顾客可以任意点一种咖啡、可以任意搭配。我们的目的是要统计每种搭配的价格、那我们要写多少个类?最后的结果就是类爆炸!
当我们要添加一个新的品种的时候、如果按照上面的方法、那我们就要新添加N多类来实现目的。如何有效的解决这两个问题?也许你有别的很多方法与思想、这里只是说明装饰者模式的使用。
三:Decorator Pattern
使用装饰者模式可以很好的解决上面的两个问题、这里不再绕弯子、直接实现。具体的思想内涵可以自己慢慢揣摩。有时间补上类结构图(也可以看Head First Design Pattern这本书的Decorating Object这一章)。
1、装饰者模式要求装饰器和组件是同一类型、那么我们先给所有咖啡一个抽象类——Beverage(当然也可以使用接口、原则就是尽量减少对源代码的改动、如果源代码是抽象类并且没有什么问题、何必还要fix它呢)——Beverage代码:
package com.chy.dp.decorator; public abstract class Beverage { String description = "no description"; public String getDescription (){ return description; } public abstract double cost(); }
2、创建四种咖啡模型、也就是组件、并实现Beverage抽象类、这里列举一个——HouseHand代码:
package com.chy.dp.decorator; public class HouseHand extends Beverage { public HouseHand() { super(); description = "HouseHand"; } /** * the price of HouseHand is 8.9$ . */ @Override public double cost() { return 8.9; } }
3、定义一个所有装饰器的抽象类、继承与Beverage、这样以后如果有新添加的调料我们就可以扩展一个调料装饰器来与当前的几种咖啡组合、而不用动原来的任何代码!open for extension, but closed for modification!——CondimentDecorator代码:
package com.chy.dp.decorator; public abstract class CondimentDecorator extends Beverage { /** * 提供一个必须要实现的获取当前组合的描述信息的方法。 * 方便观察结果。 */ public abstract String getDescription(); }
4、定义具体的装饰类:MochaDecorator、MilkDecorator、WhipDecorator、SoyDecorator、以MochaDecorator为例——MochaDecorator代码:
package com.chy.dp.decorator; public class MochaDecorator extends CondimentDecorator { Beverage beverage; public MochaDecorator(Beverage beverage) { super(); this.beverage = beverage; } /** * 返回被包装的组合或者组件的描述加上当前包装信息。 */ @Override public String getDescription() { return beverage.getDescription() + ", Mocha"; } @Override public double cost() { return beverage.cost() + 10.3; } }
5、在Client端我们就可以任意的指定组合了——Client代码:
package com.chy.dp.decorator; @SuppressWarnings("unused") public class Client { public static void main(String[] args) { Beverage darkRoast = new DarkRoast(); Beverage espresso = new Espresso(); Beverage decaf = new Decaf(); Beverage houseHand = new HouseHand(); // Dark Roast with double Mocha Beverage decoratorMocha = new MochaDecorator(darkRoast); Beverage decoratorMocha2 = new MochaDecorator(decoratorMocha); // Espresso + Soy Beverage espresso_Soy = new SoyDecorator(espresso); System.out.println("discription : " + espresso_Soy.getDescription() + "===price : " + espresso_Soy.cost() + "$"); System.out.println("description : " + decoratorMocha2.getDescription() + "===price : " + decoratorMocha2.cost() + "$"); } }
四:总结补充
1、总结:
装饰者模式挺像一种组合、而且是可以任意搭配、制定的。当我们有新的需求的时候、添加一个装饰器就ok。必要的时候可以添加组件、这样就实现了不用修改现有代码就可以扩展和修改新的功能的一个目的。还是那个设计原则——open for extension, close for modification.
2、补充:
只对Java中IO的结构使用Decorator Pattern的形式简单说明、不再从头模拟。如下图: