一、什么是装饰器模式
简介:
- 也叫包装设计模式,属于结构型模式,它是作为现有的类的一个包装,允许向一个现有的对象添加新的功能,同时又不改变其结构。
- 给对象增加功能,一般两种方式继承或关联组合,将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为来增强功能,这个就是装饰器模式,比继承模式更加灵活。
应用:
小滴课堂-老王,本来计划买跑车撩妹的,结果口袋没钱,改买自行车,为了显得突出,店家提供多种改装方案,加个大的喇叭、加个防爆胎等,经过装饰之后成为目的更明确的自行车,更能解决问题。像这种不断为对象添加装饰的模式就叫Decorator模式,Decorator指的是装饰物。
二、装饰器模式的实现方式
模式结构分析:
● 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
● 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
● 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
● 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
类关系图:
统一模型:
代码实现:
查看代码
/*
* 被装饰者的统一抽象
* */
public interface Bike {
String getDescription();
BigDecimal getPrice();
}
/*
*装饰器
* */
public class BikeDecorator implements Bike {
private String description="我只是一个装饰器,啥都不表示,子类帮我传递";
private Bike bike;
public BikeDecorator(Bike bike){
this.bike=bike;
}
@Override
public String getDescription() {
return bike.getDescription();
}
@Override
public BigDecimal getPrice() {
return bike.getPrice();
}
}
/*
* 具体的装饰器(大自行车)
* */
public class BigBike implements Bike {
@Override
public String getDescription() {
return "大自行车";
}
@Override
public BigDecimal getPrice() {
return new BigDecimal("200");
}
}
/*
* 具体的装饰器(小自行车)
* */
public class SmallBike implements Bike{
@Override
public String getDescription() {
return "小自行车";
}
@Override
public BigDecimal getPrice() {
return new BigDecimal("100");
}
}
/*
* 具体的装饰者(防爆胎)
* */
public class RSCBikeDecorator extends BikeDecorator {
private String description="防爆胎";
public RSCBikeDecorator(Bike bike){
super(bike);
}
@Override
public String getDescription() {
return super.getDescription()+"__"+this.description;
}
@Override
public BigDecimal getPrice() {
return super.getPrice().add(new BigDecimal("100"));
}
}
/*
* 具体的装饰者(大喇叭)
* */
public class SuonaBikeDecorator extends BikeDecorator {
private String description="大喇叭";
public SuonaBikeDecorator(Bike bike){
super(bike);
}
@Override
public String getDescription() {
return super.getDescription()+"__"+this.description;
}
@Override
public BigDecimal getPrice() {
return super.getPrice().add(new BigDecimal("50"));
}
}
测试用例:
/*水
*大自行车200
* *小自行车100
* *防爆胎100
* *喇叭50*/
@Test
public void decoratorDesign() {
Bike bike = new BigBike();
//搭配了个RSC防爆胎
bike = new RSCBikeDecorator(bike);
bike = new RSCBikeDecorator(bike);
//搭配了一个喇叭
bike = new SuonaBikeDecorator(bike);
bike = new SuonaBikeDecorator(bike);
System.out.println(bike.getDescription() + ",价格: " + bike.getPrice());
}
测试结果:
大自行车__防爆胎__防爆胎__大喇叭__大喇叭,价格: 500
方法评估:
装饰器模式和桥接模式对比:
- 相同点都是通过封装其他对象达到设计的目的,和对象适配器也类似,有时也叫半装饰设计模式
- 没有装饰者和被装饰者的主次区别,桥接和被桥接者是平等的,桥接可以互换,不用继承自同一个父类
比如例子里面的,可以是Phone持有Color,也可以是Colnr去右Phone. - 桥接模式不用使用同一个接口;装饰模式用同一个接口装饰,接口在父类中定义
优点:
- 装饰模式与继承关系的目的都是要扩展对象的功能,但装饰模式可以提供比继承更多的灵活性。
- 使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,原有代码无须改变,符合"开闭原则”
缺点:
- 装饰模式增加了许多子类,如果过度使用会使程序变得很复杂(多层包装)
- 增加系统的复杂度,加大学习与理解的难度