二十三种设计模式之装饰器模式

装饰器模式的定义与特点

装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

装饰器模式的主要优点有:

  • 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
  • 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
  • 装饰器模式完全遵守开闭原则

装饰器模式的结构与实现

通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰器模式的目标。下面来分析其基本结构和实现方法。

1. 模式的结构

装饰器模式主要包含以下角色。

  1. 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
  2. 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  3. 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  4. 具体装饰(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 }

程序测试结果如下:

二十三种设计模式之装饰器模式

 到此,我们的装饰器模式就讲解完毕了,下次再见啦,小伙伴们!!!

二十三种设计模式之装饰器模式

上一篇:fixture的多种用法


下一篇:LeetCode617 合并二叉树