一,定义
装饰模式,动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
或者说:在不必改变原类文件和原类使用的继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是用装饰来包裹真实的对象来实现。
二,角色
抽象构件角色(Component):给出一个接口,以规范准备接收附加责任的对象。
具体构件角色(ConcreteComponent):定义一个将要接收附加责任的类。
装饰角色(Decorator):持有一个构件对象的实例,并定义一个与抽象构件接口一致的接口。
具体装饰角色(ConCreteDecoratorA,ConcreteDecoratorB):负责给构件对象“贴上”附加的责任。
三,实例
下面我要是实现一个给一个人进行装饰的例子,即给人穿上外套,裤子,鞋子等装饰。并且可以控制装饰顺序。
这里的人就是抽象构建角色,当然也可以不抽象没有具体构建角色。服饰就是装饰角色,其子类就是具体装饰角色。下面贴一下代码:
public abstract class Person {
//这里要实现的是给人装扮的功能。类似于QQ秀 换衣服然后展示这种的。
public abstract void show();
}
public class ConcretePersonA extends Person {
@Override
public void show() {
System.out.println("嘻哈装扮");
}
}
上面是一个抽象的人,和一个喜欢嘻哈风格装扮的人。
public abstract class Finery extends Person {
protected Person component;
public void decorate(Person component){
this.component = component;
}
@Override
public void show() {
if (null != component){
component.show();
}
}
}
public class BigTrouser extends Finery {
@Override
public void show() {
super.show();
System.out.println("大垮裤");
}
}
public class TShirts extends Finery {
@Override
public void show() {
super.show();
System.out.println("大T恤");
}
}
上面是一个抽象的装饰类,绑定一下装饰对象,和他的具体装饰类。
public static void main(String[] args) {
//装饰模式
ConcretePersonA a = new ConcretePersonA();
Sneakers sneakers = new Sneakers();
BigTrouser bigTrouser = new BigTrouser();
TShirts tShirts = new TShirts();
sneakers.decorate(a);
bigTrouser.decorate(sneakers);
tShirts.decorate(bigTrouser);//装饰过程
tShirts.show();
ConcretePersonB b = new ConcretePersonB();
LeatherShoes leatherShoes = new LeatherShoes();
Tie tie = new Tie();
Suit suit = new Suit();
leatherShoes.decorate(b);
tie.decorate(leatherShoes);
suit.decorate(tie); //装饰过程
suit.show();
}
输出结果:
嘻哈装扮
运动鞋
大垮裤
大T恤
庄重装扮
皮鞋
领带
西装
以上就是装饰模式的实现,从代码我们能看到,装饰模式是为已有功能动态的添加更多功能的一种方式。那到底什么时候用它呢,当系统中需要新功能的时候,是向旧的类中添加新代码,这些新代码通常装饰了原有类的核心职责或者主要行为。我们看到,它把每个要装饰的功能放在一个单独的类中,并让这类包装它所要装饰的对象,因此,当需要执行特殊行为的时候,客户代码就可以在运行时根据需要选择地,按顺序地使用装饰功能包装对象。
这样更大的好处是,有效的把类的核心职责和装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑。
四,优缺点
优点:
- 1,使用装饰者模式比使用继承更加灵活,因为它选择通过一种动态的方式来扩展一个对象的功能,在运行时可以选择不同的装饰器,从而实现不同的行为。
- 2,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
- 3,具体构件类与具体装饰类可以独立变化,他能是低耦合的。用户可以根据需要来增加新的具体构件类和具体装饰类,在使用时再对其进行各种组合,原有代码无须改变,符合“开闭原则”。
缺点:
- 1,会产生很多的小对象,增加了系统的复杂性
- 2,这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
装饰者和继承的区别:
继承:
- 优点:代码结构清晰,而且实现简单
- 缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致继承体系过于庞大。
装饰者:
- 优点:内部可以通过多态技术对多个需要增强的类进行增强
- 缺点:需要内部通过多态技术维护需要增强的类的实例。进而使得代码稍微复杂。
五,使用场景
1,需要扩展一个类的功能,或给一个类添加附加职责。
2,需要动态的给一个对象添加功能,这些功能可能不明确或者暂时的,可以随时很方便的动态撤销掉。
3,需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
参考:《大话设计模式》 阿木虾 Java知音