生活中门是大家每天都可以见到的东西,我们以木门为例,一个木门主要是由木头组成的,如果有一天为了美观我们想在木门上面添加一些木材饰品,那么我们总不能直接换一个门吧,那多浪费啊。那么我们可以先选定一些木材饰品,然后装饰上去即可,这样门通过木材饰品的修饰更加美观了,而且也不会浪费资源。因此,这个装饰品起到了完善的功能,而且门对于装饰品有选择性,比如主人喜欢哪种饰品,那么门就装饰什么饰品。其实装饰器类就如同之前门装饰一般。门和装饰品都是属于木材,因此普通类与饰品类是统一接口的,这样在装饰的时候比较方便,比如门上安上一个铁饰品就明显显得比较费力。装饰器模式就是动态地给一个对象添加一些额外的职责,就扩展功能来说,装饰者提供了比继承更加有弹性的替代方案。
1.适用性和优缺点
2.示例讲解
Component:组件对象的接口,可以给这些对象动态的添加职责;
ConcreteComponent:具体的组件对象,实现了组件接口。该对象通常就是被装饰器装饰的原始对象,可以给这个对象添加职责;
Decorator:所有装饰器的父类,需要定义一个与组件接口一致的接口(主要是为了实现装饰器功能的复用,即具体的装饰器A可以装饰另外一个具体的装饰器B,因为装饰器类也是一个Component),并持有一个Component对象,该对象其实就是被装饰的对象。如果不继承组件接口类,则只能为某个组件添加单一的功能,即装饰器对象不能在装饰其他的装饰器对象。ConcreteDecorator:具体的装饰器类,实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。
package decoratorpattern;
public interface Wood {
void operation();
}
接下来就是
Decorator,定义一个抽象类实现Wood接口,便于统一装饰品的接口,其实装饰品抽象类相当于小一级的组件接口。里面会传入组件接口对象,便于基本功能的调用。
package decoratorpattern;
public abstract class DecoratorWood implements Wood {
protected Wood wood;
public void setWood(Wood wood) {
this.wood=wood;
}
@Override
public void operation() {
// TODO Auto-generated method stub
wood.operation();
}
}
然后是具体组件的实现,这里的具体组件指的是门,门实现了组件接口的operation()方法。
package decoratorpattern;
public class WoodDoor implements Wood {
@Override
public void operation() {
// TODO Auto-generated method stub
System.out.println("我是一个木门,静静地站在这里看着你");
}
}
接着是具体装饰的实现,可以看出装饰品类继承装饰抽象类,并且在组件接口的基本功能上,增添了新的功能,这也是装饰器的作用,动态地给对象添加职责。
package decoratorpattern;
public class DecoratorA extends DecoratorWood {
public void operation()
{
super.operation();
plusOperation();
}
public void plusOperation()
{
System.out.println("我装饰了DecoratorA之后,可以旋转");
}
}
package decoratorpattern;
public class DecoratorB extends DecoratorWood {
public void operation()
{
super.operation();
plusOperation();
}
public void plusOperation()
{
System.out.println("有了DecoratorB之后,我可以跳跃!");
}
}
最后是客户端的类
package decoratorpattern;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Wood wood=new WoodDoor();
DecoratorA d1=new DecoratorA();
DecoratorB d2=new DecoratorB();
d1.setWood(wood);
d2.setWood(d1);
d2.operation();
}
}
运行客户端程序,得到如下结果:
我是一个木门,静静地站在这里看着你
我装饰了DecoratorA之后,可以旋转
有了DecoratorB之后,我可以跳跃!
根据结果,可以看出,门组件在自己的功能基础上,增加了A和B装饰器的功能,而且是动态添加的,这也是为什么装饰器抽象类实现组件接口,因为统一了接口,便于对象的操作。因此装饰器抽象类的setter函数很重要,便于将对象传入,其实这里用构造函数也是同样的道理,就是将组件传入装饰器类中进行包装,得到新组件,仍然可以将新组件传入另一个装饰器,完成新的装饰。
InputStream in=new FileInputStreanm("xxx.txt");
in=new BufferedInputStream(in);
in=new LowerCaseInputStream(in);
上面那段代码就是使用了装饰器,首先设置好组件FileInputStream,读取相应文件,这是基本功能,然后用装饰器BufferedInputStream装饰它,并需要将FileInputStream对象传入BufferedInputStream中,添加了新功能之后,想对文件进行内容进行过滤,这时可以通过过滤器进行装饰,即用LowerCaseInputStream()装饰。这也是装饰器模式的具体实现。