装饰器模式可以动态地向一个已经存在的对象实例添加额外其他的功能。下面,用一个简单的小例子——打扮你的女友,来讲解装饰器模式。
1、装饰器小故事
假设你正在找一个妹子,这些妹子可能来自不同的国际,例如,America, China, Japan, France, 等等。她们也有不同的个性和习惯。在一个(像百合网)相亲的网站上,如果每一种类型的妹子都是各不相同的Java类的话,这可就有成千上万个类了。这是一个非常严重的问题叫做类爆炸(class explosion)。而且,当有新的妹子类型,新的类需要创建时,这种设计是不可扩展的。
我们改变下原来的设计,让每一种个性或者习惯变成一种装饰,可以动态的应用到每一个妹子上。
2、类图
Girl是一个最顶端的抽象类,Girls来自不同的国家。基于这个GirlDecorate类,我们可以通过添加新的装饰器来装饰任何一种特征到每一个Girl上。
3、实例代码
Girl抽象类
public abstract class Girl { String description = "no particular"; public String getDescription(){ return description; } }
AmericanGirl.java
public class AmericanGirl extends Girl { public AmericanGirl(){ description = "+American"; } }
EuropeanGirl.java
public class EuropeanGirl extends Girl { public EuropeanGirl() { description = "+European"; } }
GirlDecorator.java
public abstract class GirlDecorator extends Girl { public abstract String getDescription(); }
Science.java
public class Science extends GirlDecorator { private Girl girl; public Science(Girl g) { girl = g; } @Override public String getDescription() { return girl.getDescription() + "+Like Science"; } public void caltulateStuff() { System.out.println("scientific calculation!"); } }
我们可以毫无限制的给每一个装饰器添加更多的方法如“Dance()”。
Art.java
public class Art extends GirlDecorator { private Girl girl; public Art(Girl g) { girl = g; } @Override public String getDescription() { return girl.getDescription() + "+Like Art"; } public void draw() { System.out.println("draw pictures!"); } }
Main.java
package designpatterns.decorator; public class Main { public static void main(String[] args) { Girl g1 = new AmericanGirl(); System.out.println(g1.getDescription()); Science g2 = new Science(g1); System.out.println(g2.getDescription()); Art g3 = new Art(g2); System.out.println(g3.getDescription()); } }
输出:
+American
+American+Like Science
+American+Like Science+Like Art
我们也可以这样写:
Girl g = new Science(new Art(new AmericanGirl()));
4、实际应用
典型的用到装饰器模式的就是Java IO classes。
一个简单的例子 – BufferedReader decorates InputStreamReader。
BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); //System.in is an InputStream object
InputStreamReader(InputStream in) – bridge from byte streams to character streams. InputSteamReader reads bytes and translates them into characters using the specified character encoding.
BufferedReader(Reader in) – read text from a character stream and buffer characters in order to provide efficient reading methods(e.g., readLine())
BufferedReader(Reader in) – read text from a character stream and buffer characters in order to provide efficient reading methods(e.g., readLine())