定义:动态的给对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
每个装饰对象只关心自己的功能,不需要关心自己如何被添加到对象中。
装饰模式就是为已有功能动态添加更多功能的一种方式。
什么时候用?
当系统需要新功能的时候,是向旧类中添加新的代码,这些新代码通常装饰了旧类的核心职责或主要行为。但问题在于这些新代码仅仅是为了满足一些在特定情况下才会执行的特殊行为的需要。
装饰模式提供了一个很好的解决方案。它把每个要装饰的新功能放在单独的类中,并让这个类,包装它所需要装饰的对象【比如:j.Decorate(t);】。
因此,当需要执行特殊行为时,客户端代码就可以在运行时根据需要有选择的、按顺序的使用装饰功能包装对象。
优点:
把类中的装饰功能从类中搬移去除,这样就可以简化原有的类。
有效的把类的核心职责和装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑。
注意:
装饰模式的顺序很重要。
比如加密数据和过滤词汇都可以是数据持久化前的装饰功能,但若先加密再过滤就会出现问题。
所以要尽量保证装饰类之间彼此独立,这样就可以随意的按顺序来进行组合了。
代码举例:
package o3Decorator;
/**
* ConcreteComponent
* 只需要有一个ConcreteComponent而不需要没有抽象的Component类
* 如果需要给【小猫妮妮】装饰,就有2个ConcreteComponent并且需要抽象的Component类
*/
public class Person {
private String name;
public Person() {
}
public Person(String name){
this.name = name;
}
/**
* show()
*/
public void show(){
System.out.println("装扮的"+name);
}
}
package o3Decorator;
/**
* Decorator
* 服饰类
*/
public class Finery extends Person {
protected Person component;
public void Decorate(Person component) {
this.component = component;
}
@Override
public void show() {
if(component != null){
component.show();
// component.show(); = super.show();
}
}
}
package o3Decorator;
/**
* ConcreateDecorator
* 具体服饰类
*/
public class TShirt extends Finery {
@Override
public void show() {
System.out.print("T恤");
super.show();
}
}
package o3Decorator;
/**
* ConcreateDecorator
* 具体服饰类
*/
public class Jeans extends Finery {
@Override
public void show() {
System.out.print("牛仔裤");
super.show();
}
}
package o3Decorator;
/**
* ConcreateDecorator
* 具体服饰类
*/
public class LeatherShoes extends Finery {
@Override
public void show() {
System.out.print("小皮鞋");
super.show();
}
}
package o3Decorator;
/**
* 客户端代码
*/
public class test {
public static void main(String[] args) {
Person jack = new Person("杰克");
System.out.println("第一种装扮");
TShirt t = new TShirt();
Jeans j = new Jeans();
LeatherShoes l = new LeatherShoes();
t.Decorate(jack);
j.Decorate(t);
l.Decorate(j);
l.show();
System.out.println("第二种装扮");
TShirt ts = new TShirt();
Jeans je = new Jeans();
LeatherShoes ls = new LeatherShoes();
ls.Decorate(jack);
je.Decorate(ls);
ts.Decorate(je);
ts.show();
/**
* 装扮可以有许多【具体服饰类】,想加什么加什么。
* 装扮顺序也是可以控制的。
*/
}
}
控制台打印结果:
第一种装扮
小皮鞋牛仔裤T恤装扮的杰克
第二种装扮
T恤牛仔裤小皮鞋装扮的杰克