全文: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