三分钟带您搞懂装饰模式

Posted nedulee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三分钟带您搞懂装饰模式相关的知识,希望对你有一定的参考价值。

全文:959字,预计阅读时间:8分钟

定义:

  装饰模式(Decorator)动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更加灵活。
  这里可以举一个生活中的例子,一个蛋糕,在蛋糕上摆上水果,这个蛋糕就变成了水果蛋糕,给这个水果蛋糕插上蜡烛,它就变成了一个生日蛋糕。(这是Head First中的一个例子,个人觉得非常的形象,记忆犹新)。

分析:

  如果我们需要扩展一个类的功能,你会怎么做呢?如果直接修改这个类,我们就违反了开闭原则(对修改关闭,对扩展开放)。
  我们可以继承这个类,写一个这个类的子类,用于实现扩展功能,也可以使用组合(将这个类作为成员变量),达到相同的效果。
  我们将继承这种关系称为is-a,组合这种关系称为use-a。is-a的耦合程度要高于use-a,所以我们经常可以听到这样的说法:组合优于继承,原因就是这两种关系的耦合程度不同。
装饰模式的核心思想,其实就是用组合代替继承。

图解:

技术图片

实例:

  这里举一个咖啡店的例子,咖啡的原料是咖啡豆,我们可以使用咖啡豆和牛奶、蜂蜜、摩卡组合出不同价格、不同口味的咖啡。
  这里咖啡豆就是被装饰的对象,也就是图示中的ConcreteComponent,饮品类就是我们抽象出的Component,定义了展示价格和材料两个方法。牛奶、蜂蜜、摩卡是装饰对象,也就是图中的ConcreteDecoratorA、ConcreteDecoratorB。他们抽象出的Decorator,同样定义了展示价格和材料两个方法,具体类图与实现如下:

技术图片

 

 

代码:

/**
 * 饮品.
 *
 * @author jialin.li
 * @date 2019-12-26 22:58
 */
public interface Beverage {
    /** 获取描述 */
    String getDescription();
    /** 获取金额 */
    double getPrice();
}
/**
 * 咖啡豆1
 *
 * @author jialin.li
 * @date 2019-12-26 22:59
 */
public class CoffeeBean1 implements Beverage {

    @Override
    public String getDescription() {
        return "第一种咖啡豆";
    }

    @Override
    public double getPrice() {
        return 10d;
    }
}
/**
 * 咖啡豆2
 *
 * @author jialin.li
 * @date 2019-12-26 23:00
 */
public class CoffeeBean2 implements Beverage{
    @Override
    public String getDescription() {
        return "第一种咖啡豆";
    }

    @Override
    public double getPrice() {
        return 12.5d;
    }
}
/**
 * 装饰器.
 *
 * @author jialin.li
 * @date 2019-12-26 23:02
 */
public class Decorator implements Beverage{

    protected Beverage coffee;

    @Override
    public String getDescription() {
        return "装饰器,由子类重写方法";
    }

    @Override
    public double getPrice() {
        return 0;
    }
}
/**
 * 蜂蜜.
 *
 * @author jialin.li
 * @date 2019-12-26 23:07
 */
public class Honey extends Decorator {
    public Honey(Beverage coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + "加蜂蜜";
    }

    @Override
    public double getPrice() {
        return coffee.getPrice() + 4.5d;
    }
}
/**
 * 牛奶.
 *
 * @author jialin.li
 * @date 2019-12-26 23:03
 */
public class Milk extends Decorator {
    public Milk(Beverage coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + "加牛奶";
    }

    @Override
    public double getPrice() {
        return coffee.getPrice() + 1.5d;
    }
}
/**
 * 摩卡.
 *
 * @author jialin.li
 * @date 2019-12-26 23:05
 */
public class Mocha extends Decorator {
    public Mocha(Beverage coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + "加摩卡";
    }

    @Override
    public double getPrice() {
        return coffee.getPrice() + 2.5d;
    }
}
/**
 * 测试类.
 *
 * @author jialin.li
 * @date 2019-12-26 23:09
 */
public class Main {
    public static void main(String[] args) {
        CoffeeBean1 coffee1 = new CoffeeBean1();
        CoffeeBean2 coffee2 = new CoffeeBean2();

        // 加蜂蜜
        Beverage honey = new Honey(coffee1);
        // 加摩卡
        Beverage mocha = new Mocha(honey);
        System.out.println(mocha.getDescription());
        System.out.println(mocha.getPrice());

        // 加牛奶
        Milk milk = new Milk(coffee2);
        System.out.println(milk.getDescription());
        System.out.println(milk.getPrice());
    }
}

结果:

  第一种咖啡豆加蜂蜜加摩卡
  17.0
  第一种咖啡豆加牛奶
  14.0

以上是关于三分钟带您搞懂装饰模式的主要内容,如果未能解决你的问题,请参考以下文章

一篇带您搞懂MQ延迟队列实战操作

三分钟!彻底搞懂PostgreSQL 和 MySQL 区别之分

【编程】三分钟搞懂PCA主成分分析!

五分钟搞懂POM设计模式

一文彻底搞懂 Python中的装饰器偏函数

一文彻底搞懂 Python中的装饰器偏函数