请相信自己,请再次相信自己,请一定要相信自己
上一章简单介绍了桥接模式(十), 如果没有看过, 请观看上一章
引用 菜鸟教程里面的装饰者模式介绍: https://www.runoob.com/design-pattern/decorator-pattern.html
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。
这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
意图: 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决: 一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用: 在不想增加很多子类的情况下扩展类。
如何解决: 将具体功能职责划分,同时继承装饰者模式。
关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。
应用实例:
1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。
2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。
在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
优点: 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点: 多层装饰比较复杂。
使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。
注意事项: 可代替继承。
组成角色 | 具体 | 关系 | 作用 |
---|---|---|---|
Component | Drink | 被装饰对象的基类 | 给这些对象动态地添加职责 |
ConcreteComponent | Coffee 和及子类 EluosiCoffee, SingleCoffee | 具体被装饰对象 | 具体被装饰对象 |
Decorator | Decorator | 装饰者抽象类 | 装饰者抽象类 |
ConcreteDecorator | BingDecorator, QiaoKeLiDecorator | 具体装饰者 | 具体装饰者 |
由 两部分组成,
一部分是基础种类, 另外一部分是配带信息,可用可无,也可以多次进行的。
这两部分,都需要继承一个总的抽象类。
有两部分拆分的, 一部分是主体的, 另外一部分是配带的。
定义一个 总的 抽象类
然后 主体均实现 这个抽象类
配带的部分 实现抽象类, 并依赖主体信息
@Data
public abstract class Drink {
private BigDecimal price;
private String desc;
// 子类进行实现
public abstract BigDecimal cost();
}
public class Coffee extends Drink{
@Override
public BigDecimal cost() {
// 计算价格
return super.getPrice();
}
}
有单纯的 俄罗斯咖啡,拿铁咖啡,原咖啡,杨枝咖啡
public class EluosiCoffee extends Coffee {
public EluosiCoffee() {
setDesc("俄罗斯咖啡");
setPrice(new BigDecimal(15));
}
}
public class NaTieCoffee extends Coffee {
public NaTieCoffee() {
setDesc("拿铁咖啡");
setPrice(new BigDecimal(12));
}
}
public class SingleCoffee extends Coffee {
public SingleCoffee() {
setDesc("原咖啡");
setPrice(new BigDecimal(10));
}
}
public class YangZhiCoffee extends Coffee {
public YangZhiCoffee() {
setDesc("杨枝咖啡");
setPrice(new BigDecimal(15));
}
}
public class Decorator extends Drink{
private Drink drink ;
public Decorator (Drink drink) {
this.drink = drink;
}
@Override
public BigDecimal cost() {
// 之前的,加上现在的。
return drink.cost().add(getPrice());
}
@Override
public String getDesc() {
return super.getDesc()+""+getPrice() +"&&" +drink.getDesc();
}
}
可以加 冰, 牛奶, 巧克力, 糖
public class BingDecorator extends Decorator{
public BingDecorator(Drink drink) {
super(drink);
setPrice(new BigDecimal(0));
setDesc("冰");
}
}
public class MilkDecorator extends Decorator{
public MilkDecorator(Drink drink) {
super(drink);
setPrice(new BigDecimal(2));
setDesc("牛奶");
}
}
public class QiaoKeLiDecorator extends Decorator{
public QiaoKeLiDecorator(Drink drink) {
super(drink);
setPrice(new BigDecimal(3));
setDesc("巧克力");
}
}
public class TangDecorator extends Decorator{
public TangDecorator(Drink drink) {
super(drink);
setPrice(new BigDecimal(0));
setDesc("糖");
}
}
@Test
public void oneTest() {
Drink drink = new SingleCoffee();
log.info("单咖啡:{}",drink.cost());
drink = new MilkDecorator(drink);
drink = new TangDecorator(drink);
log.info("加了牛奶和糖:{}", drink.cost());
drink = new NaTieCoffee();
log.info("拿铁:{}", drink.cost());
}
装饰者和被装饰者之间必须是一样的类型,也就是要有共同的超类。
在这里应用继承并不是实现方法的复制,而是实现类型的匹配。
因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。
根据装饰者模式的理念,我们可以在任何时候,实现新的装饰者增加新的行为。如果是用继承,每当需要增加新的行为时,就要修改原程序了
本章节的代码放置在 github 上:
https://github.com/yuejianli/DesignPattern/tree/develop/Decorator
谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!