二十三种设计模式之装饰器模式
装饰器模式的定义与特点
装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
装饰器模式的主要优点有:
- 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
- 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
- 装饰器模式完全遵守开闭原则
装饰器模式的结构与实现
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰器模式的目标。下面来分析其基本结构和实现方法。
1. 模式的结构
装饰器模式主要包含以下角色。
- 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
- 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
- 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
装饰器模式的结构图如图 1 所示。
2. 模式的实现
装饰器模式的实现代码如下:
1 package decorator; 2 3 public class DecoratorPattern { 4 public static void main(String[] args) { 5 Component p = new ConcreteComponent(); 6 p.operation(); 7 System.out.println("---------------------------------"); 8 Component d = new ConcreteDecorator(p); 9 d.operation(); 10 } 11 } 12 13 //抽象构件角色 14 interface Component { 15 public void operation(); 16 } 17 18 //具体构件角色 19 class ConcreteComponent implements Component { 20 public ConcreteComponent() { 21 System.out.println("创建具体构件角色"); 22 } 23 24 public void operation() { 25 System.out.println("调用具体构件角色的方法operation()"); 26 } 27 } 28 29 //抽象装饰角色 30 class Decorator implements Component { 31 private Component component; 32 33 public Decorator(Component component) { 34 this.component = component; 35 } 36 37 public void operation() { 38 component.operation(); 39 } 40 } 41 42 //具体装饰角色 43 class ConcreteDecorator extends Decorator { 44 public ConcreteDecorator(Component component) { 45 super(component); 46 } 47 48 public void operation() { 49 super.operation(); 50 addedFunction(); 51 } 52 53 public void addedFunction() { 54 System.out.println("为具体构件角色增加额外的功能addedFunction()"); 55 } 56 }
程序运行结果如下:
创建具体构件角色 调用具体构件角色的方法operation() --------------------------------- 调用具体构件角色的方法operation() 为具体构件角色增加额外的功能addedFunction()
装饰器模式的应用实例
【示例】用装饰器模式模拟咖啡店点咖啡
类图如下:
2. 模式的实现
装饰器模式的实现代码如下:
抽象基类Food.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:35 6 * @Version 1.0 7 * 8 * 食物抽象基类 9 */ 10 public abstract class Food { 11 12 private String desc; 13 14 private float price; 15 16 public String getDesc() { 17 return desc; 18 } 19 20 public void setDesc(String desc) { 21 this.desc = desc; 22 } 23 24 public float getPrice() { 25 return price; 26 } 27 28 public void setPrice(float price) { 29 this.price = price; 30 } 31 32 public abstract float cost(); 33 }
Coffee.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:36 6 * @Version 1.0 7 * 8 * 咖啡基类 9 */ 10 public abstract class Coffee extends Food{ 11 12 @Override 13 public float cost() { 14 return super.getPrice(); 15 } 16 }
Americano.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:38 6 * @Version 1.0 7 * 8 * 美式咖啡 9 */ 10 public class Americano extends Coffee{ 11 12 public Americano() { 13 setDesc("美式咖啡"); 14 setPrice(4.5f); 15 } 16 17 }
Cappuccino.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:41 6 * @Version 1.0 7 * 8 * 卡布奇诺 9 */ 10 public class Cappuccino extends Coffee{ 11 12 public Cappuccino() { 13 setDesc("卡布奇诺"); 14 setPrice(6.5f); 15 } 16 17 }
Espresso.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:40 6 * @Version 1.0 7 * 8 * 玛奇朵 9 */ 10 public class Espresso extends Coffee{ 11 12 public Espresso() { 13 setDesc("玛奇朵"); 14 setPrice(3.5f); 15 } 16 17 }
咖啡装饰器基类Decorator.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:42 6 * @Version 1.0 7 * 8 * 装饰器基类 9 */ 10 public class Decorator extends Food{ 11 12 // 目标对象 13 private Food target; 14 15 public Decorator(Food target) { 16 this.target = target; 17 } 18 19 @Override 20 public float cost() { 21 return super.getPrice() + target.cost(); 22 } 23 24 @Override 25 public String getDesc() { 26 return super.getDesc() + " " + super.getPrice() + " " + target.getDesc(); 27 } 28 }
Chocolate.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:48 6 * @Version 1.0 7 * 8 * 巧克力 9 */ 10 public class Chocolate extends Decorator{ 11 12 public Chocolate(Food target) { 13 super(target); 14 setDesc("巧克力"); 15 setPrice(3.5f); 16 } 17 18 }
Yogurt.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:47 6 * @Version 1.0 7 * 8 * 酸奶 9 */ 10 public class Yogurt extends Decorator{ 11 12 public Yogurt(Food target) { 13 super(target); 14 setDesc("酸奶"); 15 setPrice(1.5f); 16 } 17 18 }
测试Main.java
1 package com.lzp.decorator; 2 3 /** 4 * @Author LZP 5 * @Date 2021/6/18 20:50 6 * @Version 1.0 7 */ 8 public class Main { 9 10 public static void main(String[] args) { 11 // 需求:点一份卡布奇诺咖啡,再加一个巧克力和两盒酸奶 12 Food order = new Cappuccino(); 13 System.out.println(order.getDesc() + "单价:" + order.getPrice() + "元"); 14 order = new Chocolate(order); 15 order = new Yogurt(order); 16 order = new Yogurt(order); 17 System.out.println("点一份卡布奇诺咖啡,再加一个巧克力和两盒酸奶共计:" + order.cost() + "元"); 18 System.out.println("点一份卡布奇诺咖啡,再加一个巧克力和两盒酸奶的详细订单:" + order.getDesc()); 19 } 20 21 }
程序测试结果如下:
到此,我们的装饰器模式就讲解完毕了,下次再见啦,小伙伴们!!!