装饰器特点
装饰器的定义:
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变原来类。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
对功能的扩展也可以通过继承扩展所需要功能的类的方法,但是Java中的继承时单继承,如果想要扩展多个功能就需要不断继承,代码相当冗余。
-
Component:为统一接口,也是装饰类和被装饰类的基本类型
-
ConcreteComponent:为具体实现类,实现了Component接口,也是被装饰类,他本身是个具有一些功能的完整的类。
-
Decorator:是装饰类,实现了Component接口的同时还在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。
-
ConcreteDecorator:是具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。可以通过构造器声明装饰哪种类型的ConcreteComponent。
注意:装饰器类可以有很多的变化
1、被装饰器的统一的接口,可以是一个接口,也可以是抽象父类
2、装饰器类Decorator可以不需要
代码示例
首先创建一个统一的接口,接口中声明了一个方法
/**
* 统一接口,也是装饰类和被装饰类的基本类型
*/
public interface Component {
void method();
}
创建一个该接口的具体实现类
/**
* 为具体实现类,也是被装饰类,他本身是一个具有功能的完整类
*/
public class ConcreteComponent implements Component {
// 其余变量和方法
@Override
public void method() {
System.out.println("原来的方法");
}
}
创建一个实现接口的装饰类,这个类中实现的method方法是调用了类中的component.method()方法,为后来继承这个装饰类的装饰器类对component方法的使用和扩展做准备。
/**
* 装饰类
* 实现了Component接口
*/
public abstract class Decorator implements Component {
// 内部维护一个ConcreteComponent实例
protected Component component;
// 通过构造函数实例化ConcreteComponent实例
public Decorator(Component component) {
super();
this.component = component;
}
// Component接口提供的方法的实现是调用component的方法,自己没有实现
@Override
public void method() {
component.method();
}
}
定义两个装饰器类,装饰器类继承了装饰类,并且都有自己的自定义方法,而且对父类的方法进行了扩展。
/**
* 具体装饰器类A
* 继承自装饰器类
*/
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void methodA() {
System.out.println("装饰器类A的扩展功能");
}
@Override
public void method() {
System.out.println("针对该方法进行一层A包装");
super.method();
System.out.println("包装结束");
}
}
/**
* 具体装饰器类B
* 继承自装饰器类
*/
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void methodB() {
System.out.println("装饰器类B的扩展功能");
}
@Override
public void method() {
System.out.println("针对该方法进行一层B包装");
super.method();
System.out.println("包装结束");
}
}
所需要的类和接口都定义完成,下面我们写一个测试用例,来看一下装饰器这种设计模式是如何在不改变原有的类ConcreteComponent的情况下,给实例对象扩展多个所需要的功能的:
public class DecoratorTest {
public static void main(String[] args) {
Component component = new ConcreteComponent();//原来的对象
component.method();//原来的方法
System.out.println("------------------------");
ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(component);//装饰成A
concreteDecoratorA.method();
concreteDecoratorA.methodA();//装饰成A以后新增的方法
System.out.println("-------------------------");
ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB(component);//装饰成B
concreteDecoratorB.method();
concreteDecoratorB.methodB();
System.out.println("-------------------------");
concreteDecoratorB = new ConcreteDecoratorB(concreteDecoratorA);//装饰成A以后再装饰成B
concreteDecoratorB.method();
concreteDecoratorB.methodB();//装饰成B以后新增的方法
System.out.println("----------------------");
}
}
可以看到,每次执行method方法后,不仅有原有的方法实现,还有扩展的部分,并且可以实现原先的类中没有的别的装饰类自定义的方法:
IO流中的使用
public class IODecorator {
public static void main(String[] args) throws IOException, FileNotFoundException {
final String filepath = "C:/Users/Chuuuki/Desktop/test.txt";
/**
* InputStream相当于统一接口,是装饰类和被装饰类的基本类型(Component)
* FileInputStream相当于原始的待装饰的对象,为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类
*
*/
InputStream inputStream = new FileInputStream(filepath);
System.out.println("FileInputStream不支持mark和reset" + inputStream.markSupported());
System.out.println("-----------------------");
/**
* 下面展示一种装饰器的作用BufferedInputStream
*
* BufferedInputStream是一个具体的装饰器类
* 其定义如下:
* BufferedInputStream extends FilterInputStream
*
* FilterInputStream是装饰类,其继承自InputStream
* 内部存在一个inputStream实例
*
* BufferedInputStream提供了特有的方法:
*/
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
System.out.println("bufferedInputStream支持mark和reset:" + bufferedInputStream.markSupported()); // 提供实现自自定义的方法
bufferedInputStream.mark(0); // 标记一下
char c = (char) bufferedInputStream.read();
System.out.println("文件的第一个字符:" + c);
bufferedInputStream.reset(); // 重置
c = (char) bufferedInputStream.read(); // 再读
System.out.println("重置以后再读一个字符,依然会是第一个字符:" + c);
bufferedInputStream.reset();
}
}
- InputStream是一个抽象类,不能被实例化,所以可以将其看作统一接口。(Component)
- FileInputStream相当于需要被扩展功能的原来的类,因为器本身是不支持
mark
和reset
方法的。(ConcreteComponent) - BufferedInputStream是一个具体的装饰器类,他是支持
mark
和reset
方法的,这两个方法相当于其自定义的方法。(ConcreteDecorator) - BufferedInputStream继承了FilterInputStream类,这个类
是继承了InputStream的,并且里面维护了一个InputStream实例,所以在这里
FilterInputStream是一个装饰类。(Decorator)
运行结果如图所示,文件中内容为”Hello“,FileInputStream实例也可以进行mark和reset操作了:
这样就实现了没有改变FileInputStream类,并且扩展了inputstream实例的功能的需求。