定义

装饰者模式动态的将责任附加在对象上. 若要拓展功能, 装饰者提供了比继承更有弹性的替代方案.

特点:

  • 装饰者和被装饰对象有共同的超类型
  • 可以用一个或多个装饰者包装一个对象
  • 既然装饰者与被装饰对象有着相同的超类型, 所以在任何需要原始对象(被包装)的场合, 可以用装饰过的对象代替它
  • 装饰者可以在所委托被装饰者的行为之前与/或之后, 加上自己的行为, 以达到特定的目的
  • 对象可以在任何时候被装饰, 所以可以在运行时动态的, 不限量的用你喜欢的装饰者来装饰对象

设计原则

  • 类应该对拓展开放, 对修改关闭

案例

背景: 酒吧卖酒, 酒Beverage是抽象类, 酒有很多子类,需要计算成本, 子类的调料并不相同
现将计算成本的方法cost()在父类中声明, 子类重写调料的方法

image.png
Beverage

  1. public abstract class Beverage {
  2. protected abstract boolean hasMilk();
  3. protected abstract boolean hasSoy();
  4. private Integer money;
  5. public Integer getMoney() {
  6. return money;
  7. }
  8. public void setMoney(Integer money) {
  9. this.money = money;
  10. }
  11. public Integer cost() {
  12. if (hasMilk()) {
  13. this.money += 1;
  14. }
  15. if (hasSoy()) {
  16. this.money += 2;
  17. }
  18. return this.money;
  19. }
  20. }

HouseBlend

  1. public class HouseBlend extends Beverage {
  2. @Override
  3. protected boolean hasMilk() {
  4. return true;
  5. }
  6. @Override
  7. protected boolean hasSoy() {
  8. return false;
  9. }
  10. }

测试

  1. @Test
  2. public void testDecorator() {
  3. HouseBlend houseBlend = new HouseBlend();
  4. houseBlend.setMoney(0);
  5. System.out.println("houseBlend的成本为: " + houseBlend.cost());
  6. DarkRoust darkRoust = new DarkRoust();
  7. darkRoust.setMoney(0);
  8. System.out.println("darkRoust的成本为: " + darkRoust.cost());
  9. }
  10. 结果:
  11. houseBlend的成本为: 1
  12. darkRoust的成本为: 2

问题:
出现新的调料, 需要在父类中添加新的方法, 并更改cost方法

改用装饰者模式后
image.png
被装饰者顶层抽象类

  1. public abstract class Beverage {
  2. public abstract Integer cost();
  3. }

被装饰者

  1. public class DarkRoust extends Beverage {
  2. @Override
  3. public Integer cost() {
  4. return 10;
  5. }
  6. }
  1. public class HouseBlend extends Beverage {
  2. @Override
  3. public Integer cost() {
  4. return 20;
  5. }
  6. }

装饰者
现有一个抽象类保证 装饰者与被装饰者类型一致

  1. public abstract class CondimentDecorator extends Beverage {
  2. }

装饰者持有被装饰者的属性, 在构造方法中传入,当然也可以动态set
Milk

  1. public class Milk extends CondimentDecorator {
  2. private Beverage beverage;
  3. public Milk(Beverage beverage) {
  4. this.beverage = beverage;
  5. }
  6. @Override
  7. public Integer cost() {
  8. return 2 + beverage.cost();
  9. }
  10. public Beverage getBeverage() {
  11. return beverage;
  12. }
  13. public void setBeverage(Beverage beverage) {
  14. this.beverage = beverage;
  15. }
  16. }
  17. @Override
  18. public Integer cost() {
  19. return 2 + beverage.cost();
  20. }
  21. }

Soy, 注意可以”层层包装”

  1. public class Soy extends CondimentDecorator {
  2. private Beverage beverage;
  3. public Soy(Beverage beverage) {
  4. this.beverage = beverage;
  5. }
  6. @Override
  7. public Integer cost() {
  8. return 1 + beverage.cost();
  9. }
  10. public Beverage getBeverage() {
  11. return beverage;
  12. }
  13. public void setBeverage(Beverage beverage) {
  14. this.beverage = beverage;
  15. }
  16. }

测试

  1. @Test
  2. public void testDecorator() {
  3. //darkRoust成本10,houseBlend成本20
  4. //milk成本1,soy成本2
  5. // darkRoust加milk和soy
  6. DarkRoust darkRoust = new DarkRoust();
  7. Milk milk = new Milk(darkRoust);
  8. Soy soy = new Soy(milk);
  9. System.out.println("darkRoust的成本为: " + milk.cost());
  10. // houseBlend只加soy
  11. HouseBlend houseBlend = new HouseBlend();
  12. Soy soy1 = new Soy(houseBlend);
  13. System.out.println("houseBlend的成本为: " + soy.cost());
  14. }
  15. 结果:
  16. darkRoust的成本为: 12
  17. houseBlend的成本为: 13

java io装饰者模式

image.png