装饰者模式(十一)

请相信自己,请再次相信自己,请一定要相信自己

上一章简单介绍了桥接模式(十), 如果没有看过, 请观看上一章

一. 装饰者模式

引用 菜鸟教程里面的装饰者模式介绍: 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 具体装饰者 具体装饰者

装饰者模式(十一)_第1张图片

二. 装饰者模式

由 两部分组成,
一部分是基础种类, 另外一部分是配带信息,可用可无,也可以多次进行的。

这两部分,都需要继承一个总的抽象类。

有两部分拆分的, 一部分是主体的, 另外一部分是配带的。

定义一个 总的 抽象类

然后 主体均实现 这个抽象类

配带的部分 实现抽象类, 并依赖主体信息

二.一 基类 Drink

@Data
public abstract class Drink {
    private BigDecimal price;
    private String desc;

    // 子类进行实现
    public abstract BigDecimal cost();

}

二.二 被装饰的对象 Coffee

public class Coffee extends Drink{

    @Override
    public BigDecimal cost() {
        // 计算价格
      return super.getPrice();
    }
}

二.三 装饰对象 Coffee 的子类

有单纯的 俄罗斯咖啡,拿铁咖啡,原咖啡,杨枝咖啡

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));
    }

}

二.四 装饰者抽象类 Decorator

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());

    }

装饰者模式(十一)_第2张图片

装饰者和被装饰者之间必须是一样的类型,也就是要有共同的超类。

在这里应用继承并不是实现方法的复制,而是实现类型的匹配。

因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。

根据装饰者模式的理念,我们可以在任何时候,实现新的装饰者增加新的行为。如果是用继承,每当需要增加新的行为时,就要修改原程序了


本章节的代码放置在 github 上:


https://github.com/yuejianli/DesignPattern/tree/develop/Decorator


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

你可能感兴趣的:(设计模式,装饰者模式,设计模式)