装饰模式是结构型模式之一,定义为:动态地给一个对象添加一些额外的方法,就增加功能来说,装饰模式相比增加子类更加灵活。所以,装饰模式是为基础类添加功能的!
如果不用装饰模式,当然可以通过继承原有的类完成功能的添加,在子类上添加一些方法,但是却变得耦合性大,灵活性变低和可维护性变大,中间类一旦有方法添加,子类也要跟着添加。如果使继承体系变为2个分支,分为功能类,和装饰类,就可以动态的添加功能而不影响原有的类。
装饰模式的结构如下:
抽象组件Component,具体组件ConcreteComponent,抽象装饰器Decorator继承自Component并组合入一个Component,暴露了与组件相同的方法operate(),两个具体的装饰类ConcreteDecorator1和ConcreteDecorator1,在基础的operate()方法上面增加了一些功能。
具体代码如下:
abstract class Component{
public abstract void operate();
}
class ConcreteComponent extends Component{
@Override
public void operate() {
System.out.println("执行操作");
}
}
abstract class Decorator extends Component{
private Component component;
Decorator(Component component){
this.component = component;
}
public void operate(){
component.operate();
}
}
class ConcreteDecorator1 extends Decorator{
ConcreteDecorator1(Component component) {
super(component);
}
private void decorate1(){
System.out.println("decorate1");
}
public void operate(){
super.operate();
decorate1();
}
}
class ConcreteDecorator2 extends Decorator{
ConcreteDecorator2(Component component) {
super(component);
}
private void decorate2(){
System.out.println("decorate2");
}
public void operate(){
super.operate();
decorate2();
}
}
测试类:
public class DecoratorTest {
public static void main(String[] args) {
Component c = new ConcreteComponent();
Decorator d1 = new ConcreteDecorator1(c);
d1.operate();
Decorator d2 = new ConcreteDecorator2(c);
d2.operate();
}
}
测试结果:
执行操作
decorate1
执行操作
decorate2
以上,说明了装饰模式的具体用法。
在java中,最典型的装饰模式的运用当属javaIO体系结构,再次笔者简单的用eclipse的继承分析工具看一下继承关系:
InputStream为一个输入流,它是个抽象类,提供了read(byte b[])、read(byte b[], int off, int len)等方法;FilterInputStream就是个抽象装饰器,它是一个抽象类,继承了InputStream并且组合入一个InputStream,BufferedInputStream是具体的装饰类,看一下它的read方法:
private int read1(byte[] b, int off, int len) throws IOException {
int avail = count - pos;
if (avail <= 0) {
/* If the requested length is at least as large as the buffer, and
if there is no mark/reset activity, do not bother to copy the
bytes into the local buffer. In this way buffered streams will
cascade harmlessly. */
if (len >= getBufIfOpen().length && markpos < 0) {
return getInIfOpen().read(b, off, len);
}
fill();
avail = count - pos;
if (avail <= 0) return -1;
}
int cnt = (avail < len) ? avail : len;
System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
pos += cnt;
return cnt;
}
在基本的读操作上提供了缓冲的功能。
笔者水平有限,如有错误欢迎指正与探讨。