1、简介
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式比生成子类更为灵活。——《设计模式:可复用面向对象软件的基础》
装饰者模式需要动态给某个对象添加职责,是一种对象结构型模式。
使用场景:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
- 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类).
角色:
抽象构件角色(Component):定义一个对象接口或抽象类,可以给这些对象动态地添加职责。
具体构件角色(ConcreteComponent):实际被动态地添加职责的对象。
抽象装饰者角色(Decorator):实现了Component接口,用来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。
具体装饰者角色(ConcreteDecorator):动态地添加职责的对象。
话不多说,上代码。
2、具体实现
//基类
interface Man{
public void get();
}
//具体被装饰角色
class NormalMan implements Man{
@Override
public void get() {
System.out.println("我是一个男人");
}
}
//抽象装饰类
abstract class DecorateMan implements Man{
private Man man;
public DecorateMan(Man man){
this.man = man;
}
@Override
public void get() {
man.get();
}
}
//具体装饰类
class HouseMan extends DecorateMan{
public HouseMan(Man man) {
super(man);
}
public void house(){
System.out.print("我有房");
}
@Override
public void get(){
super.get();
house();
}
}
//具体装饰类
class CarMan extends DecorateMan{
public CarMan(Man man) {
super(man);
}
public void car(){
System.out.print("我有车");
}
@Override
public void get(){
super.get();
car();
}
}
//装饰者模式
public class Decorate {
public static void main(String[] args) {
Man man = new NormalMan();
//new CarMan(man).get(); 我是一个男人 我有车
//new HouseMan(man).get(); 我是一个男人 我有房
new HouseMan(new CarMan(man)).get(); ///我是一个男人我有车我有房
}
}
3、总结
优点:
1、装饰者模式和继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活型。
2、通过使用不同的具体装饰者类及它们不同的组合顺序,可以得到不同装饰后具有不同行为或者状态的对象。例如上面的CarDecoratorImpl可以多次修饰一个男人,证明他有很多车。
3、符合开闭原则。
缺点:
1、增加了抽象装饰者类和具体装饰者类,一定程度增加了系统的复杂度,加大了系统的学习和理解成本。
2、灵活性也意味着更容易出错,对于多次被多次修饰的对象,调试时寻找错误可能需要找到多个地方。