模式定义
动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
通过使用装饰器模式(Decorator),可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。
修饰模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰模式是在运行时增加行为。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。
当有几个相互独立的功能需要扩充时,这个区别就变得很重要。在有些面向对象的编程语言中,类不能在运行时被创建,通常在设计的时候也不能预测到有哪几种功能组合。这就意味着要为每一种组合创建一个新类。相反,修饰模式是面向运行时候的对象实例的,这样就可以在运行时根据需要进行组合。
模式结构
UML类图如下:
- Component:定义一个对象接口,可以给这些对象动态的添加职责。
- ConcreteComponent:定义一个对象可以给这个对象动态的添加职责。
- Decorator:维护一个指向Component接口的指针,并定义一个与Component接口一致的接口或者直接实现Component接口。
代码示例
标准模式
将上述标准的装饰器模式,用Java代码给诠释一下。
首先是待装饰的接口Component:
package com.bytebeats.decorator.ch1;
public interface Component {
void operation();
}
接下来便是一个具体的接口实现类,也就是待装饰对象,如下:
package com.bytebeats.decorator.ch1;
/**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2017-04-26 21:43
*/
public class ConcreteComponent implements Component {
@Override
public void operation() {
}
}
接下来是抽象装饰器父类,它主要是为装饰器定义了我们需要装饰的目标是什么,并对Component进行了基础的装饰。代码如下:
package com.bytebeats.decorator.ch1;
/**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2017-04-26 21:44
*/
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
}
最后是具体的装饰器A和装饰器B。代码如下:
package com.bytebeats.decorator.ch1;
/**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2017-04-26 21:48
*/
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
System.out.println("装饰器A包装前");
this.component.operation();
System.out.println("装饰器A包装后");
}
public void featureA() {
System.out.println("装饰器A扩展的功能");
}
}
package com.bytebeats.decorator.ch1;
/**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2017-04-26 21:48
*/
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
System.out.println("装饰器B包装前");
this.component.operation();
System.out.println("装饰器B包装后");
}
public void featureB() {
System.out.println("装饰器B扩展的功能");
}
}
应用
Java中的**Java I/O Streams ** 为典型的装饰器模式。
字节流包装:
File file = new File("F:\\backup\\abc.dat");
InputStream in = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(in);
DataInputStream dis = new DataInputStream(bis);
int value = dis.readInt();//读出来一个int
字符流包装:
LineNumberReader lnr = null;
try {
File file = new File("F:\\backup\\abc.txt");
InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");
BufferedReader br = new BufferedReader(isr);
lnr = new LineNumberReader(br);
String line = null;
while((line=lnr.readLine())!=null){
System.out.println(lnr.getLineNumber()+"\t"+line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
lnr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
源码
https://github.com/TiFG/design-patterns/tree/master/decorator