概述
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
如何解决:将具体功能职责划分,同时继承装饰者模式。
关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。
应用实例:在某物件基础上加以修饰,装点,使得原本的朴素变得华丽,达到化腐朽为神奇的效果。比如我们从开发商买来的毛坯房,必然要进行室内装潢这么一项工程,什么简约风啊,北欧风啊,地中海,美式中式等等,当然萝卜青菜各有所爱,每个人装出的房子都各有差异,但不管何种风格,这都是对原本毛坯房的装饰,留给业主按照自己的喜好进行二次加工,这也是为什么有时候毛坯二手房比装修过的要好卖,有成品就一定得有半成品,这样才能把更多的选择留给用户,使得装饰成为可能。
优点:
1、装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:
多层装饰比较复杂。
装饰器模式的结构
抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator)角色:继承\实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
装饰器模式的使用
这里以装饰女人化妆为例子:
//抽象构建角色
public interface Showable {
public void show();//定义展示的行为
}
此时女人展现她的素颜
//具体构建角色
public class Girl implements Showable{
@Override
public void show() {
System.out.print("女人的素颜");
}
}
下一步给女人的素颜加上对应的粉饰,使其好看一点。
public class Decorator implements Showable {
private Showable showable;
public Decorator(Showable showable) {
this.showable = showable;
}
@Override
public void show() {
System.out.print("粉饰(");
showable.show();
System.out.println(")");
}
}
然后是我们的main方法:
public class Main {
public static void main(String[] args) {
Girl girl = new Girl();
girl.show();
System.out.println();
new Decorator(girl).show();
}
}
运行结果如下:
我们可以看到,只需要新建装饰器的时候把女孩给包装进去就得到了粉饰过的美颜,是不是非常简单?然而此时有女朋友会嫌弃了,“只是打粉底这么简单吗?眼霜呢?口红呢……”。那么我们这个代码该如何扩展呢?
此时就需要划分我们的抽象装饰角色以及具体装饰角色了。
//抽象装饰者
public abstract class Decorator implements Showable {
//采用protected保证在当前包下调用扩展我们的装饰类
protected Showable showable;
public Decorator(Showable showable) {
this.showable = showable;
}
@Override
public void show()
{
showable.show();
}
}
女人的粉底:
//具体装饰角色装饰女人的粉底
public class FoundationMakeUp extends Decorator{
public FoundationMakeUp(Showable showable) {
super(showable);
}
@Override
public void show() {
System.out.print("打粉底(");
showable.show();
System.out.print(")");
}
}
女人的口红:
//具体装饰角色女人的口红
public class LipStick extends Decorator{
public LipStick(Showable showable) {
super(showable);
}
@Override
public void show() {
System.out.print("涂口红(");
showable.show();
System.out.print(")");
}
}
main方法调用如下所示
public static void main(String[] args) {
//通过向上转型showable逐步去嵌套一个化妆了的女人
Showable beautifulGirl = new LipStick(new FoundationMakeUp(new Girl()));
beautifulGirl.show();
}
运行结果如下:
如果对这种淡妆效果还是不满意,我们可以继续添加化妆品类,睫毛膏、眼线、眉笔、腮红等等等等,只需要层层包裹各司其职,最终实现浓妆艳抹的梦想。
总结
其实装饰器模式在JDK里就有很多应用,比如JavaIO包里的众多流处理类
newBufferedReader(newInputStreamReader(newFileInputStream(filePath)));
当然,流处理类当然要比我们的例子复杂的多,但其基本思想和我们去繁就简的例子异途同归,这些对象就好像是俄罗斯套娃一样层层包裹,层层装饰,每套一层就会多出一些功能出来,我们更可以自由搭配,实现不同的组合功能。
所以,不管是女生化妆还是程序员写代码,我们都不可能弄出一个巨大的类然后去搞定所有事情,如此代码会越堆积越多,难于维护,功能扩展更是举步维艰。我们都需要有这种设计思想,每个化妆品部件各司其职,不做和自己不相关的事,然后把部件层层叠加,并根据需求组装成型,以达最终的装饰目的。