1、装饰模式的概念
装饰模式就是动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
对于人来说,衣服、鞋子、领带、袜子等都是装饰,装饰模式就是给光着身子的人穿上各种衣服裤子。
对于程序对象来说,每一个功能都是装饰,给一个类增加功能,就是给这个类进行装饰。
2、装饰模式的UML图及对应代码
Compoent是一个对象接口,可以给这些对象动态地添加职责:
class interface Component{
void Operation();
}
ConcreteComponent类,定义了一个具体的对象,也可以给这个对象添加一些职责:
class ConcreteComponent implement Component{
@Override
public void Operation(){
//做一些具体的操作
}
}
Decorator 是装饰抽象类,继承了Component接口,从外类来扩展Component类的功能,但是对于Component来说,是无需要知道Decorator的存在的。
public class Decorator implements Component{
protected Component component;
//设置Component
public SetComponent(Component component){
this.component = component;
}
//重写Operation(),实际执行的是Component的Operation()
@Override
public void Operation() {
if(component != null){
component.Operation();
}
}
}
ConcreteDecorator 是具体的装饰对象,起到给Component添加职责的功能
我们来实现一下A和B
public class ConcreteDecoratorA extends Decorator {
//本类特有的功能,以区别B
private String addedState;
@Override
public void Operation() {
// 首先运行原Component的Operation()
super.sampleOperation();
// 再执行本类的功能,如addState相当于对原Component进行了装饰
addState = "New State";
//具体装饰对象A的操作。
}
}
public class ConcreteDecoratorB extends Decorator {
//本类特有的方法,以区别A
public AddBehavior() {
}
@Override
public void Operation() {
// 首先运行原Component的Operation()
super.sampleOperation();
// 再运行自己的功能
AddBehavior();
....
}
}
最后客户端代码点睛之笔:
main(){
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA d1 = new ConcreteDecoratorA();
ConcreteDecoratorB d2 = new ConcreteDecoratorB();
//装饰的方法是:
//首先用 ConcreteComponent实例化c
//然后用 ConcreteDecoratorA的实例化对象d1来包装c
//再用ConcreteDecoratorB的对象d2来包装d1
//最后执行d2的Operation
d1.setComponent(c);
d2.setComponent(d1);
d2.Operation();
...
}
-
装饰模式就是利用SetComponent来对对象进行包装的。
这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象值关心自己的功能,不需要关心如何被添加到对象链当中。
注:不一定要去构造Component类,要善于变通,假如只有一个ConcreteComponent(我们只修饰一个“人”),那么久没有必要些Component类,同时,Decorator就是ConcreteComponent类的子类,如果ConcreteDecorator只有一个(“衣服”只有一件),那么也没有必要构造Decorator,直接让唯一的ConcreteDecorator来继承ConcreteComponent就行啦。
3、经典场景—穿衣服
在这个场景下,我们给一个人穿各种衣服,包括裤子、袜子、鞋子、衣服。
在之前的UML来说,ConcreteComponent可以说是代表着具体的一类人,而这个问题让我们针对这个人,所以我们可以不用构造Component类,或者说 “人”这个类就是Component类。而Decorator很自然就是“服装类”,其子类就是各种衣服,那么我们可以画出下面的UML图:
接着按图来写代码:
首先是Person类
class Person{
public Person(){
}
private String name;
public Person(String name){
this.name = name;
}
public abstract void show(){
System.out.plintln("穿衣服的rikka");
}
}
接着是服饰类Finery:
class Finery extends Person{
protected Person component;
//打扮
public void Decorate(Person component){
this.component = component;
}
@Override
public void show(){
if(component != null){
component.show();
}
}
}
接下来就是具体服饰类ConcreteDecorator
class GoldLianzi extends Finery{
@Override
public void show(){
System.out.prinlin("大金链子");
super.show();
}
}
class Sunglasses extends Finery{
@Override
public void show(){
System.out.prinlin("墨镜");
super.show();
}
}
最后的客户端代码:
main(){
Person rikka = new Person("Rikka");
System.out.println("装扮\n");
Sunglasses sunglasses = new Sunglasses();
GoldLianzi gold = new GoldLianzi();
Cigarette cigarette = new Cigarette();
ThugLife thuglife = new ThugLife();
sunglasses.Decorate(rikka);
gold.Decorate(sunglasses);
cigarette.Decorate(gold);
thuglife.Decorate(cigarette);
thuglife.show();
}
结果显示:
装扮
ThugLife帽子 香烟 大金链子 墨镜 穿衣服的rikka
这样,我们就为一个什么都没有穿的人,穿上了各种衣服啦!
同理就是给类加功能。
总结
学了这么多,其实装饰模式是为已有功能动态地添加更多功能的一种设计模式。
问题:在以往,在系统功能需要更新的时候,是向旧类添加新的代码,这些新的代码通常装饰了原有类的核心职责或主要行为,但这种做法的问题就在于:它们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度。