一、装饰者模式简介
1.基本原理
通过使用装饰者模式,可以在运行时扩充一个类的功能。原理是:增加一个装饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。装饰类必须和原来的类有相同的接口。
装饰者模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰者模式是在运行时增加行为。
当有几个相互独立的功能需要扩充时,这个区别就变得很重要。在有些面向对象的编程语言中,类不能在运行时被创建,通常在设计的时候也不能预测到有哪几种功能组合。这就意味着要为每一种组合创建一个新类。相反,装饰者模式是面向运行时候的对象实例的,这样就可以在运行时根据需要进行组合。一个装饰者模式的示例是JAVA里的Java I/O Streams的实现。
装饰者模式的UML类图:
2.示例代码
以*** 砂锅羊肉面 ***为实例,别问为什么,(╯°□°)╯︵┻━┻
Component 相当于Marmite(砂锅)类:
public abstract class Marmite {
String description = "砂锅";
public String getDescription() {
return description;
}
public abstract Integer cost();
@ Override
public String toString() {
return "这是一碗:" + getDescription() + ",价格:" + cost() + "元";
}
}
ConcreteComponent是NoddlesMarmite(砂锅面条)类:
public class NoddlesMarmite extends Marmite { public NoddlesMarmite() { description = "砂锅面条"; } public Integer cost() { return 8; } }
Decorator是MaterialDecorator
public abstract class MaterialDecorator extends Marmite { public abstract String getDescription(); }
ConcreteDecorator是MuttonMarmite:
public class MuttonMarmite extends MaterialDecorator { Marmite marmite; public MuttonMarmite(Marmite marmite) { this.marmite = marmite; } @Override public String getDescription() { return "羊肉、" + marmite.getDescription(); } @Override public Integer cost() { return 5 + marmite.cost(); } }
这是测试代码:
public class MarmiteTest {
public static void main(String[] args) {
Marmite marmiteNoddle = new NoddlesMarmite();
System.out.println(marmiteNoddle. toString ());
Marmite muttonMarmiteNoddle = new MuttonMarmite(marmiteNoddle);
System.out.println(muttonMarmiteNoddle.toString());
}
}
二、Java API中装饰者的运用
先看一段demo
public class JavaDemo { public static void main(String[] args) { System.out.println("请输入一句话:"); BufferedInputStream bufferedInputStream = new BufferedInputStream(System.in); String msg = "wocao"; try { BufferedReader bufferedReader=new BufferedReader(new InputStream Reader(bufferedInputStream)); msg = bufferedReader.readLine(); } catch (Exception e){ e.printStackTrace(); } System.out.println("输入的是:" + msg); } }
这段代码的功能是将控制台中输入的内容打印出来。
查看java api得知 BufferedInputStream继承的是FilterInputStream,如下图:
FilterInputStream继承的是InputStream,并且有InputStream对象的一个引用
由此可以得出
InputStream相当于Component,FileterInputStream相当于Decorator,BufferedInputStream相当于ConcreteDecorator,System.in相当于ConcreteComponent。
三、自己实现一个关于InputStream的ConcreteDecorator
talk is cheap, show me the code
public class LowerCaseInputStream extends FilterInputStream { public LowerCaseInputStream(InputStream in){ super(in); } @Override public int read() throws IOException { int c=super.read(); return (c==-1?c: char acter.toLowerCase((char)c)); } @Override public int read( byte [] b, int off, int len) throws IOException { int result=super.read(b,off,len); for(int i=off;i<off+result;i++){ b[i]=(byte)Character.toLowerCase((char)b[i]); } return result; } }
不想解释了,心累 看不懂的,送你一幅图:
—————————————EOF————————————–
参考资料:
- 修饰模式
- Head First设计模式
我的心愿是世界和平!~( ゜▽゜)つロ