装饰模式,动态的给一个对象添加一些额外的职责。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
一、装饰模式
装饰模式通过组合的方式扩展对象的特性,这种方式允许我们在任何时候对对象的功能进行扩展,甚至是运行时扩展。
与继承相比,组合关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。其UML图如下:
装饰模式由以下部分组成:
抽象构件(Component):给出一个抽象接口,是一组某种类的基类。
具体构件(ConcreteComponent):这个类就是我们要装饰的对象。
装饰类(Decorator):继承自Component,保证装饰者和被装饰者有共同的超类,持有一个构件(Component)对象的实例。
具体装饰角色(ConcreteDecorator):负责给构件对象装饰附加的责任。
二、案列分析:
在西游记第二十七回《尸魔三戏唐三藏 圣僧恨逐美猴王》中,孙悟空三打白骨精可是一番精彩,书中讲道:
好妖精,停下阴风,在那山凹里,摇身一变,变做个月貌花容的女儿,说不尽那眉清目秀,齿白唇红。
……
好妖精,按落阴云,在那前山坡下,摇身一变,变作个老妇人,年满八旬,手拄着一根弯头竹杖,一步一声的哭着走来。
……
好妖怪,按耸阴风,在山坡下摇身一变,变成一个老公公,真个是:白发如彭祖,苍髯赛寿星….”
白骨精也是很聪明的妖怪,三次分别装饰成女子、老妪、老头来迷惑师徒四人。但最终也是被大圣给打死了。
白骨精(Decorator)属于妖怪(Moonster),妖怪想要吃唐僧肉,分别装饰成女子、老妇、老汉(这些都是ConcreteDecorator)要吃唐僧。这就是一个装饰模式的体现,其UML图如下:
具体代码:
Component:妖怪接口
interface Monster {
public void eatTS();
}
ConcreteComponent :被装饰的类–白骨精
class WhiteBoneMonster implements Monster {
public void eatTS(){
System.out.println("其实我是白骨精,我要吃唐僧肉");
}
}
Decorator:女子、老妪、老头等都是装饰白骨精的装饰类。
class Daughter implements Monster {
private WhiteBoneMonster monster ;
public Daughter(WhiteBoneMonster monster){
this.monster = monster ;
}
@Override
public void eatTS() {
System.out.println("我是一个翠袖轻摇笼玉笋,湘裙斜拽显金莲的女子");
monster.eatTS();
System.out.println("我被孙悟空打死了...");
}
}
class Grandma implements Monster {
private WhiteBoneMonster monster ;
public Grandma (WhiteBoneMonster monster){
this.monster = monster ;
}
@Override
public void eatTS() {
System.out.println("我是年满八旬的老妪,我来找我女儿");
monster.eatTS();
System.out.println("我也被孙悟空打死了...");
}
}
class Grandfa implements Monster {
private WhiteBoneMonster monster ;
public Grandfa (WhiteBoneMonster monster){
this.monster = monster ;
}
@Override
public void eatTS() {
System.out.println("我是一生好善斋僧,看经念佛的老头");
monster.eatTS();
System.out.println("我也被孙悟空打死了...");
}
}
故事上演:
public class Test {
public static void main(String[] args) {
WhiteBoneMonster monster = new WhiteBoneMonster();
Daughter daughter = new Daughter(monster);
Grandma grandma = new Grandma(monster);
Grandfa grandfa = new Grandfa(monster);
daughter.eatTS();
grandma.eatTS();
grandfa.eatTS();
}
}
运行结果:
代码地址:Decorator
三、模式结语
装饰模式的优点:
装饰者模式可以提供比继承更好的灵活性
可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
装饰模式的使用场景:
在不影响其他对象的情况下,以动态、透明的方式给对象添加职责。
需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时,考虑使用装饰者模式。
欢迎大家留言评论,点击查看其它设计模式。