Decorator Pattern(装饰器模式)
GoF定义:为一个对象动态添加额外的功能。代替继承的一种扩展功能的机制
概念
这个设计模式的核心是我们不能修改已有的功能,但是我们能扩展它的功能。即对修改闭合而对扩展开放。这种模式应用于我们想给一些特定对象增加功能,但是不想修改整个类
例子
现实世界:假设现在有一个新房子,需要铺一层地板,但是不希望把现在的地板全部拆掉,那么就要在现有的地板上做一些改动来保证可以在上面铺新地板
代码世界:假设一个GUI程序,我们需要给边框加一些属性,此时可以选择继承组件类,但是这并不是好方法,因为用户/客户端并不能完全控制这个组件。而装饰器和被装饰的对象类型符合同一个接口,将被装饰的对象包在装饰器中,直到请求到达真正的对象之前,装饰器可以被追加无限的责任(做其它操作)
展示
这里装饰器的doJob
方法会增加一些别的操作,但是不影响被包起来的对象的doJob
方法调用
代码
public class DecoratorPatternSample
{
public static void main(String[] args)
{
System.out.println("***Decorator pattern Demo***");
ConcreteComponent cc = new ConcreteComponent();
ConcreteDecoratorEx1 cd_1 = new ConcreteDecoratorEx1();
// Decorating ConcreteComponent Object //cc with ConcreteDecoratorEx_1
cd_1.setCom(cc);
cd_1.doJob();
ConcreteDecoratorEx2 cd_2= new ConcreteDecoratorEx2();
// Decorating ConcreteComponent Object //cc with ConcreteDecoratorEx_1 & //ConcreteDecoratorEX_2
cd_2.setCom(cd_1);//Adding //results from cd_1 now
cd_2.doJob();
}
}
abstract class AbstractComponent
{
abstract public void doJob();
}
class ConcreteComponent extends AbstractComponent
{
@Override
public void doJob()
{
System.out.println("I am from Concrete Component-I am closed for modification.");
}
}
class AbstractDecorator extends AbstractComponent
{
private AbstractComponent com;
public void setCom(AbstractComponent com)
{
this.com = com;
}
@Override
public void doJob()
{
if (this.com != null)
{
com.doJob();
}
}
}
class ConcreteDecoratorEx1 extends AbstractDecorator {
@Override
public void doJob()
{
super.doJob();
System.out.println("I am explicitly from Ex_1");
}
}
class ConcreteDecoratorEx2 extends AbstractDecorator {
@Override
public void doJob()
{
System.out.println("");
System.out.println("***START Ex-2***");
super.doJob();
//Add additional thing if necessary
System.out.println("Explicitly From DecoratorEx_2");
System.out.println("***END. EX-2***");
}
}
这里的代码,每个具体的装饰器都是父类持有被装饰的对象,所以调用super.doJob()
会层层往上调用
Note
使用装饰器的好处:
- 不干扰系统中现存的对象,可以单独为某个对象添加功能
- 渐进式编码。即开始定义一个(功能)简单的对象,后续使用装饰器方式无限叠加功能
和继承的区别?
装饰器可以动态增加或者减少(随功能的需求变化),而继承会创建新的类,这样时间越长,系统中的类越多
使用这个模式的缺点?
如果足够小心,那么没有显著缺点(毕竟作者【滑稽】)。如果装饰器过多,那么会导致debug困难并且难以维护,而且装饰器会引起一些困惑(可读性降低)
PS:Java库中的IO流是经典的装饰器实现,上述代码中的set
方法可以换成构造器实现(装饰器抽象父类定义带参构造器,子类使用super(component)
)