一.什么是装饰器模式
装饰器(Decorator)模式又称为包装(Wrapper)模式。装饰器模式动态来扩展对象的功能,是继承关系的一个替代方案。
二.为什么需要装饰器模式
通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类的方式并不可取,在面向对象的设计中,我们应该尽量使用组合对象而不是继承对象来扩展和复用功能,装饰器模式就是基于对象组合的方式的。
三.一个简单的例子带你了解装饰器模式的使用
这里我就用仿大话设计模式中的例子来说一下了,假设小明要去参加约会,他要选择衣服,如果让我们去设计,我们会可能会撸出下面一段代码:
public class NormalPerson {
private String name; //姓名
// 目前只公布了这几种造型
public NormalPerson() {
}
public NormalPerson(String name) {
super();
this.name = name;
}
public void wearSneankers() {
System.out.println("穿球鞋");
}
public void wearLeatherShoes() {
System.out.println("穿皮鞋");
}
public void wearSuit() {
System.out.println("穿西装");
}
public void show() {
System.out.println("装扮的大佬:"+name);
}
}
在写个测试代码
NormalPerson person =new NormalPerson("小明");
person.wearLeatherShoes();
person.wearSuit();
person.show();
控制台上的打印:
穿皮鞋
穿西装
装扮的大佬:小明
如果他要去参加参加角色扮演的舞会,他想穿蝙蝠侠的装扮,我们是不是需要改Person这个类,但是我们一般不建议这样做,并且这样违背了开闭原则,于是我们将装扮抽象出来,并且让抽象装饰类继承自Person这个类,并且定义不同的具体装饰器继承自抽象装饰器,抽象装饰器持有Person类对象引用,让具体的装饰器重写抽象类装饰类的方法,并且可以在增加自己的特有方法,于是我们的代码结构就变成了这样。给大家看张UML图。
再来看具体的类,NormalPerson这个类不变,看看其他装饰类:
public abstract class Decorator extends NormalPerson {
//抽象出来的装饰类,持有被装饰者的引用
public NormalPerson person;
public void Decorator(NormalPerson person) {
this.person = person;
}
public void show() {
if (null != person) {
person.show();
}
}
}
public class SuitBatMan extends Decorator{
//具体装扮类,在原来的装扮前增加自己的新的蝙蝠侠装扮
public void show() {
System.out.println("穿蝙蝠侠装");
super.show();
}
}
public class SuitLetherShoes extends Decorator{
//具体装扮类,在原来的装扮前增加自己的新的皮鞋装扮
public void show() {
System.out.println("穿皮鞋");
super.show();
}
}
public class SuitSneakers extends Decorator{
///具体装扮类,在原来的装扮前增加自己的新的球鞋装扮
public void show() {
System.out.println("穿球鞋");
super.show();
}
}
写个测试:
public static void main(String []args){
System.out.println("第一种蝙蝠侠装扮的小明>>>>>>");
NormalPerson normalPerson=new NormalPerson("小明");
Decorator suitBatMandecorator=new SuitBatMan(); //先对小明进行蝙蝠侠装扮
suitBatMandecorator.Decorator(normalPerson);
suitBatMandecorator.show();
System.out.println("装扮结束>>>>>");
System.out.println("第二种开始蝙蝠侠和皮鞋的小明");
Decorator suitLeatherDecorator=new SuitLetherShoes();//皮鞋装扮,包装蝙蝠装扮
suitLeatherDecorator.Decorator(suitBatMandecorator);
suitLeatherDecorator.show();System.out.println("装扮结束>>>>>");
System.out.println("第三种开始蝙蝠侠和球鞋的装扮的小明");
Decorator sneakersSuit=new SuitSneakers();
suitBatMandecorator.Decorator(sneakersSuit);//球鞋装扮,包装蝙蝠装扮
suitBatMandecorator.show();
System.out.println("装扮结束>>>>>");
}
我们可以看到控制台打印为:
第一种蝙蝠侠装扮的小明>>>>>>
穿蝙蝠侠装
装扮的大佬:小明
装扮结束>>>>>
第二种开始蝙蝠侠和皮鞋的小明
穿皮鞋
穿蝙蝠侠装
装扮的大佬:小明
装扮结束>>>>>
第三种开始蝙蝠侠和球鞋的装扮的小明
穿蝙蝠侠装
穿球鞋
装扮结束>>>>>
通过上面的例子,我们可以了解到,装饰器模式并没有修改NormalPerson,通过组合一个NormalPerson这个对象,对Normal进行包装,这样就动态的扩展了一个对象功能。下面在给大家看张一般情况下的装饰器模式的UML图:
我们可以看到,与我们举的例子相比,少了抽象对象的接口,在我们的例子中,由于只有一个具体被装饰对象,所以我们省略了抽象接口类,让装饰器抽象类直接继承了具体装饰类了,同样的如果只有一个装饰器,也不用抽象装饰类了,直接让具体装饰类继承自抽象接口进行动态添加功能。
以上就是装饰器的模式。我们来总结下装饰器模式:
使用场景:一般是在动态扩展类的功能,动态添加或撤销功能,或者是组合一些基本功能产生大量的功能时。
优缺点:优点已经很明显了,这样动态添加使得程序扩展性很强,对修改是关闭的,缺点也是很明显装饰器模式会使得程序多了很多类,如果过度使用,会让程序变得复杂。
本文如果不正之处。欢迎大家批评指正。