定义:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
个人理解
1、装饰者存在两个重要的组成部分,需要被装饰的组件(被装饰者)和装饰者抽象。每个装饰者需要持有一个组件,也就是说,装饰者需要持有Component抽象的引用。
2、装饰者和被装饰者必须是一样的类型也就是要有共同的超类,这是装饰者模式的关键。(因为装饰者必须要能取代被装饰者)
3、在以上 的类图中,继承Beverage类,是为了有正确的类型,而不是继承它的行为。行为来自于装饰者和基础组件。或者其他装饰者之间的组合关系。(如果依赖继承,那么类的行为只能在编译时静态决定,也就是说,行为不是来自于超类就是子类覆盖后的版本)要点
1、继承属于扩展形式之一,但不见得是达到弹性的最佳方案。
2、在我们的设计中,应该允许行为可以被扩展,而无需修改现有的代码
3、组合和委托可以在运行时动态地加上新的行为。
4、除了继承,装饰者模式也可以让我们扩展行为。
5、装饰者模式以为者一群装饰者类,这些类用来包装具体组件 。
6、装饰者类反应出被装饰者的组件类型(事实上,他们具有相同的类型,都通过接口或继承实现)。
7、装饰者可以在被装饰者的行为前面/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
8、你可以用无数个装饰者包装一个组件。
9、装饰者一般对组件的客户是透明的,除非客户程序依赖于具体的组件。
10、装饰者会导致设计中出现很多小的对象,如果过度使用,会让程序变得复杂。- Java IO 的简单类图UML
使用装饰者模式,建立一个新的装饰者完成实现将字符串的小写变成大写。
- LowerCaseInputStream 类,实现将字符的小写变成大写。
public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in) {
super(in);
}
public int read() throws IOException {
int c = super.read();
return (c == -1 ? c : Character.toLowerCase((char)c));
}
public int read(byte[] b, int offset, int len) throws IOException {
int result = super.read(b, offset, len);
for (int i = offset; i < offset+result; i++) {
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}
- 测试类
public class InputTest {
public static void main(String[] args) throws IOException {
int c;
try {
InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
while ((c = in.read()) >= 0) {
System.out.print((char) c);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
说明:以上代码来自于HeadFirst书籍智慧,请参考原书,获得更多知识。