装饰者模式
Decorator模式(别名Wrapper):动态将职责附加到对象上,若要扩展功能,装饰者提供了比继承更具弹性的代替方案。
意图:
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
设计原则:
利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
要点:
1. 装饰者和被装饰对象有相同的超类型。 2. 可以用一个或多个装饰者包装一个对象。 3. 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。 4. 对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的用你喜欢的装饰者来装饰对象。 5. 装饰模式中使用继承的关键是想达到装饰者和被装饰对象的类型匹配,而不是获得其行为。 6. 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。在实际项目中可以根据需要为装饰者添加新的行为,做到“半透明”装饰者。 7. 适配器模式的用意是改变对象的接口而不一定改变对象的性能,而装饰模式的用意是保持接口并增加对象的职责。
实现:
Component:
定义一个对象接口,可以给这些对象动态地添加职责。
public interface Component { void operation(); }
Concrete Component:
定义一个对象,可以给这个对象添加一些职责。
public class ConcreteComponent implements Component { public void operation() { // Write your code here } }
Decorator:
维持一个指向Component对象的引用,并定义一个与 Component接口一致的接口。
public class Decorator implements Component { public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); } private Component component; }
Concrete Decorator:
在Concrete Component的行为之前或之后,加上自己的行为,以“贴上”附加的职责。
public class ConcreteDecorator extends Decorator { public void operation() { //addBehavior也可以在前面 super.operation(); addBehavior(); } private void addBehavior() { //your code } }
模式的简化:
适用性:
以下情况使用Decorator模式
优点:
缺点:
装饰模式在Java I/O库中的应用:
编写一个装饰者把所有的输入流内的大写字符转化成小写字符:
import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; public class LowerCaseInputStream extends FilterInputStream { protected LowerCaseInputStream(InputStream in) { super(in); } @Override public int read() throws IOException { int c = super.read(); return (c == -1 ? c : Character.toLowerCase((char) c)); } @Override 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; } }
测试我们的装饰者类:
import java.io.*; public class InputTest { public static void main(String[] args) throws IOException { int c; try { InputStream in = new LowerCaseInputStream(new BufferedInputStream( new FileInputStream("D:\\test.txt"))); while ((c = in.read()) >= 0) { System.out.print((char) c); } in.close(); } catch (IOException e) { e.printStackTrace(); } } }