专业编程基础技术教程

网站首页 > 基础教程 正文

架构轻松学--JAVA装饰器模式

ccvgpt 2024-08-04 12:17:14 基础教程 21 ℃

什么是装饰器模式?

关于这一种设计模式比较官方的解释是:装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

架构轻松学--JAVA装饰器模式

装饰器模式应用场景:

举个例子,如果想调一杯焦糖奶茶,这杯奶茶可以根据我们自己的喜欢添加加布丁、青稞等等。现在我们要计算调制这样一杯网红奶茶花了多少钱,那么通过代码的方式思考应该如何去做?

首先在不考虑设计模式的情况下,如果按照传统的编码思路,我们会先写一个抽象的焦糖奶茶基类、接着焦糖奶茶基类若不能满足我的需要,比如要在奶茶的基础上加青稞,我们就会写一个焦糖青稞奶茶类去继承焦糖奶茶基类,返回新的价格;比如我现在又不想要青稞,想要加布丁,那么我们就会又写一个焦糖布丁奶茶去继承奶茶基类、后面的以此类推。虽然这种方法可以解决问题,但是这样不断继承,子类会比较膨胀,耦合性太强。

那么,我们换一种思路,既然这杯焦糖奶茶有多种可添加材料,但是它的本质依旧是一杯奶茶,添加的材料只是它附加的一种属性。按照面向对象的思想,既然附加的材料属性有很多,那么我们就可以将材料属性单独抽取成一个父类材料对象(也就是先不管奶茶,只针对附加的材料,这样做的好处是低耦合,解决子类过于膨胀的问题),让各种各样的材料分别继承材料基类即可;因此我们也就可以这样定义,焦糖奶茶就是我们的核心组件、布丁和青稞以及别的材料是我们的装饰者。

综上,我们可以首先定义一个顶层的接口,这个接口(主要是针对奶茶进行操作)定义的行为规范如:这杯奶茶花了多少钱,使用了什么材料,于是乎就有了以下代码


刚才也说了,附加的多种材料,我们可以单独把它抽象出来,将其设计成一个抽象类,让子类去设计定义具体的材料(使用的是青稞还是布丁)。但是,这个材料基类单独定义没有任何意义,需要将材料 放进奶茶中才能完成代码的需求。因此,这个基类需要实现最顶层的奶茶接口,然后通过构造函数,将顶层接口进行赋值操作。可能你会问,为什么要将顶层接口通过构造函数进行赋值操作,因为只有赋值操作以后,才可以再次调用顶层接口里面的方法:


接口和基类已经简单介绍和封装完了。那么接下来我们就来定义上面提到的角色。

首先是焦糖奶茶,刚才说了,焦糖奶茶是这个功能的核心组件,而且我们也定义了最顶层的奶茶接口,所以,焦糖奶茶只需要实现顶层接口,在里面进行赋值返回操作即可,假设这杯不含任何材料的纯粹焦糖奶茶价值12元,那么就有以下代码:


定义完了奶茶,我们在定义客户可能想要在里面添加的青稞,布丁等等。因为在上面我们已经定义了添加材料的基类,现在只需要继承材料基类然后在子类设置附加材料的价格就可以满足计算价格以及统计材料的任务:



焦糖奶茶附加材料青稞和布丁都已经准备好了,下面就等着添加测试使用了。

下面就开始测试这杯奶茶的价格(老板我现在要布丁以及双份的青稞)


下面是仅单独添加一种材料的结果测试:


为了加深对装饰器模式的印象,这里在举一个网上的例子:

在英雄联盟中,有个叫提莫的英雄。他是负责瓦罗兰大陆的班德尔城安全的侦察兵首领,我们知道英雄升级以后系统会赋予新的技能点供英雄去学习,那么这种英雄学技能的现象我们用装饰器模式又该如何去设计操作?

跟上面的奶茶一样,我们把 “提莫学技能” 分成两部分,第一部分就是我们的核心组件,也就是我们的提莫英雄;第二部分我们把提莫的技能抽取共性,成为核心组件的装饰。

首先,我们定义顶层英雄学习技能的接口:


接着,我们抽象技能的属性,让子类自己实现:


我们先实例化提莫对象:


接着,轮到提莫开始学技能啦:


为了方便测试,我把提莫的技能名称放在了构造函数这里,下面就是测试:

综上所述,装饰器模式是为了从基类开始不断给对象做功能的新增或原有功能的优化补充。在类的不断传递的过程中包装类原有方法或新增方法。

最近发表
标签列表