设计模式快速入门——结构型模式之装饰者模式(Java)
这篇系列文章将按照以下结构逐一介绍不同种类的设计模式:
1. 创建型模式
- 创建型模式用于回答:“如何更好地创建对象?” 这些模式的主要目标是将对象的创建与使用分开,这部分会探讨以下五种创建型模式:单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式。
2. 结构型模式
- 结构型模式关注如何以某种方式组合类或对象来构建更大的系统结构。这部分将探讨七种结构型模式:代理模式、适配器模式、桥接模式、装饰模式、外观模式、享元模式、组合模式。
3. 行为型模式
- 行为型模式涉及类和对象之间的协作,以完成单个对象无法独立完成的任务,并分配职责。这部分将介绍十一种行为型模式:模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式和解释器模式。
通过这一系列文章,深入了解这些不同类型的设计模式,以及它们如何在软件开发中发挥关键作用。
文章目录
- 前言
- 一、装饰者模式简介
- 1.1 什么是装饰者模式?
- 1.2 为什么需要装饰者模式(优点)
- 1.3 装饰者模式的不足
- 1.4 装饰者模式的结构
- 1.5 装饰者模式的应用场景
- 二、装饰者模式的示例
- 三、装饰者模式和代理模式的对比
- 总结
前言
在软件开发中,设计模式是一种被广泛接受的可复用解决方案,用于解决在软件设计中常见的问题。设计模式为开发人员提供了一种通用的指导,帮助他们设计和实施高质量、易维护、可扩展的软件系统。
本文将快速入门结构型模设计模式中的装饰者模式。
一、装饰者模式简介
1.1 什么是装饰者模式?
装饰者模式是一种结构型设计模式,它允许动态地将新功能附加到对象上,而不改变其结构。这种模式是一种修饰型模式,因为它通过创建装饰类来修饰原始类的行为,以扩展其功能。
1.2 为什么需要装饰者模式(优点)
装饰者模式的优点包括:
- 允许在不修改现有代码的情况下添加新功能。
- 可以使用多个装饰器组合功能。
- 提高了代码的可重用性,因为可以在不同情况下使用不同的装饰器。
- 符合开闭原则,对扩展开放,对修改关闭。
1.3 装饰者模式的不足
装饰者模式的不足包括:
- 可能会导致类的数量增加,增加了复杂性。
- 过度使用装饰者可能会使代码变得难以理解。
1.4 装饰者模式的结构
装饰者模式通常包括以下角色:
- 组件(Component):定义一个对象接口,可以动态地添加职责。
- 具体组件(Concrete Component):实现Component接口的具体对象。
- 装饰者(Decorator):继承Component接口,并保存一个Component对象的引用,以便在运行时动态添加职责。
- 具体装饰者(Concrete Decorator):具体的装饰者类,扩展Decorator类的功能。
1.5 装饰者模式的应用场景
装饰者模式通常用于以下情况:
- 当需要在不影响其他对象的情况下动态添加功能或职责时。
- 当需要扩展对象的功能,但使用继承会导致类爆炸时。
- 当需要在运行时选择不同的装饰器组合时。
以下是一些常见的装饰者模式应用场景的示例:
图形界面组件:在图形用户界面开发中,装饰者模式经常用于创建自定义的UI组件。可以动态地添加或修改组件的外观和行为,例如为按钮添加边框、滚动条等。
输入/输出流:在Java的输入/输出流中,装饰者模式被广泛应用。可以使用不同的装饰器来扩展流的功能,如缓冲、加密、压缩等。例如,
BufferedInputStream
和BufferedOutputStream
就是装饰了输入和输出流的例子。文本处理:文本编辑器中的格式化文本功能可以使用装饰者模式实现。可以动态添加和移除文本格式装饰器,如加粗、斜体、下划线等。
游戏中的角色装备:在游戏中,可以使用装饰者模式来装备角色。不同的装备可以提供不同的属性和技能,可以动态地为角色添加装备,而不需要修改角色类。
动态权限管理:在安全和权限管理领域,装饰者模式可用于实现动态权限管理。可以根据用户的角色和权限动态地为他们添加或移除权限,而不需要修改用户类。
二、装饰者模式的示例
我们以奶茶店点餐的功能为例,其中奶茶可以添加珍珠、椰果、布丁等配料:
首先,定义抽象组件类 MilkTea
,它代表奶茶的基本组件:
public abstract class MilkTea {public abstract String getDescription();public abstract double cost();
}
然后,创建具体组件类 BasicMilkTea
,表示基础奶茶:
public class BasicMilkTea extends MilkTea {@Overridepublic String getDescription() {return "奶茶";}@Overridepublic double cost() {return 6.0;}
}
接下来,创建装饰器抽象类 MilkTeaDecorator
,它继承自 MilkTea
,并包含一个成员变量用于持有被装饰的奶茶对象:
public abstract class MilkTeaDecorator extends MilkTea {protected MilkTea milkTea;public MilkTeaDecorator(MilkTea milkTea) {this.milkTea = milkTea;}
}
现在,创建具体的装饰器类,如 PearlDecorator
、CoconutDecorator
和 PuddingDecorator
,它们都继承自 MilkTeaDecorator
:
public class PearlDecorator extends MilkTeaDecorator {public PearlDecorator(MilkTea milkTea) {super(milkTea);}@Overridepublic String getDescription() {return milkTea.getDescription() + " + 珍珠";}@Overridepublic double cost() {return milkTea.cost() + 1;}
}public class CoconutDecorator extends MilkTeaDecorator {public CoconutDecorator(MilkTea milkTea) {super(milkTea);}@Overridepublic String getDescription() {return milkTea.getDescription() + " + 椰果";}@Overridepublic double cost() {return milkTea.cost() + 2;}
}public class PuddingDecorator extends MilkTeaDecorator {public PuddingDecorator(MilkTea milkTea) {super(milkTea);}@Overridepublic String getDescription() {return milkTea.getDescription() + " + 布丁";}@Overridepublic double cost() {return milkTea.cost() + 3;}
}
现在,顾客可以点餐并创建不同种类的奶茶,例如:
public class Client {public static void main(String[] args) {MilkTea basicMilkTea = new BasicMilkTea();MilkTea milkTeaWithPearl = new PearlDecorator(basicMilkTea);MilkTea milkTeaWithCoconut = new CoconutDecorator(milkTeaWithPearl);MilkTea milkTeaWithPudding = new PuddingDecorator(milkTeaWithCoconut);System.out.println(basicMilkTea.getDescription() + " 总价:" + basicMilkTea.cost());System.out.println(milkTeaWithPearl.getDescription() + " 总价:" + milkTeaWithPearl.cost());System.out.println(milkTeaWithCoconut.getDescription() + " 总价:" + milkTeaWithCoconut.cost());System.out.println(milkTeaWithPudding.getDescription() + " 总价:" + milkTeaWithPudding.cost());}
}
这样,可以根据客户的点餐需求动态地组合不同的配料,而不需要修改奶茶的基本类,实现了装饰者模式的功能。
运行结果:
奶茶 总价:6.0
奶茶 + 珍珠 总价:7.0
奶茶 + 珍珠 + 椰果 总价:9.0
奶茶 + 珍珠 + 椰果 + 布丁 总价:12.0
三、装饰者模式和代理模式的对比
下面表格总结了装饰者模式和代理模式之间的一些主要区别和相似点。
特征 | 装饰者模式 | 代理模式 |
---|---|---|
类型 | 结构型模式 | 结构型模式 |
目的 | 扩展对象的功能,动态添加职责 | 控制对对象的访问,代表对象进行间接访问 |
主要关注点 | 功能扩展 | 控制访问和管理对象 |
结构 | 组合多个装饰器,嵌套调用 | 代理对象包装被代理对象 |
类关系 | 装饰器和组件之间的继承关系,实现接口 | 代理和被代理对象之间的关联,通常也实现接口 |
修改对象行为 | 在运行时动态添加功能 | 控制对对象的访问 |
使用场景 | 需要在不修改现有对象代码的情况下扩展功能 | 需要对对象的访问进行控制,如延迟加载、权限控制等 |
举例 | Java IO 中的 InputStream 和 OutputStream | 远程代理、虚拟代理、安全代理等 |
关注开闭原则 | 对扩展开放,对修改关闭 | 对扩展开放,对修改关闭 |
复杂性 | 可能增加类的数量,增加复杂性 | 相对较简单,通常只包含代理和被代理对象 |
总结
装饰者模式是一种强大的设计模式,它允许动态地扩展对象的功能,而不需要修改其代码。通过创建装饰器类,可以轻松地添加新功能,同时保持代码的可维护性和可重用性。这种模式在需要动态添加职责的情况下非常有用,但需要谨慎使用,以避免过度复杂化代码。希望本文对装饰者模式的理解和应用有所帮助。
设计模式快速入门——结构型模式之装饰者模式(Java)相关推荐
- 图解Java设计模式学习笔记——结构型模式(适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式、代理模式)
一.适配器模式(类适配器.对象适配器.接口适配器) 1.现实生活中的例子 泰国插座用的是两孔的(欧标),可以买个多功能转换插头(适配器),这样就可以使用了国内的电器了. 2.基本介绍 适配器模式(Ad ...
- Java设计模式快速入门之外观模式
3.2Java设计模式快速入门之外观模式 3.2.1概念 外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这种类型的设计模式属于结构型模式,它向 ...
- 设计模式7大结构型模式
2019独角兽企业重金招聘Python工程师标准>>> 结构型模式:结构型模式是描述如何将类对象结合在一起,形成一个更大的结构,结构模式描述两种不同的东西:类与类的实例.故可以分为类 ...
- 设计模式总结之结构型模式
设计模式总结之结构型模式 结构型模式描述如何组织类和对象以组成更大的结构.结构型类模式采用继承机制来组合接口和实现,结构型对象模式则采用组合聚合来组合对象以实现新功能,可以在运行时刻改变对象组合关系, ...
- iOS设计模式四部曲(二) 结构型模式 内附Demo
本篇是四部曲的第二篇,第一篇请点这里iOS设计模式四部曲(一):创建型模式 内附Demo,关于设计模式强烈推荐图书<Head First设计模式>以及<研磨设计模式>.由于个人 ...
- 设计模式(17):结构型-组合模式(Composite)(2)
设计模式(Design pattern) 是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式 ...
- java外观设计修改_Java设计模式之外观模式和装饰器模式的设计(精选)
前言 本篇来学习下结构型模式的外观模式和装饰器模式. 外观模式 简介 外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这种类型的设计模式属于结构型模式,它向现有的系统添加一个接 ...
- 设计模式之门面模式与装饰器模式详解和应用
目录 1 门面模式定义 1.1 门面模式的应用场景 1.2 门面模式的通用写法 1.3 门面模式业务场景实例 1.4 门面模式在源码中的应用 1.5 门面模式的优缺点 2 装饰器模式 2.1 装饰器模 ...
- Java设计模式之五 ----- 外观模式和装饰器模式
前言 在上一篇中我们学习了结构型模式的适配器模式和桥接模式.本篇则来学习下结构型模式的外观模式和装饰器模式. 外观模式 简介 外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这 ...
- 策略模式、工厂模式、装饰者模式总结解析
今天在面试的时候被问到自己策略模式怎么用的时候有被问懵到,以至于明明是自己的代码在脑海里已经混乱了,而且面试官提出的还是没有更好的利用设计模式也让我思考了一下我之前的代码到底是怎么实现的,重新梳理下策 ...
最新文章
- Spring Security 实战干货:实现自定义退出登录
- 敏捷转型历程 - Sprint3 回顾会
- vue Watcher分类 computed watch
- 【渝粤教育】国家开放大学2018年春季 0025-21T数据结构 参考试题
- 中如何移动物体在画面中的位置_组合柜摆在客厅中什么位置最旺运?客厅中,财位是如何确定的?...
- php中::双冒号有什么作用
- (5)剑指Offer之栈变队列和栈的压入、弹出序列
- 解决屏蔽JS代码报错的问题
- 天涯明月刀最新服务器,天涯明月刀最新开服时间表 | 手游网游页游攻略大全
- 【算法基础三】算法如何入门?零基础入门算法应该学些什么?
- 沟通CTBS,远程接入速度不再是困扰
- 医疗人工智能与未来医院信息化建设
- 坚果云 不在计算机显示图标,在Ubuntu18.04系统顶栏不显示坚果云图标的解决办法...
- Sql Server数据库中查询操作时“对象名无效”解决方法
- 同时支持手机号、用户名、邮箱登录
- 20. Linux提权:从入门到放弃
- Linux ssh免密登录
- 关于华为实习的一两点感触
- 解决 XXX cannot be resolved or is not a field 问题
- 计算机不识别lacie硬盘,LaCie移动硬盘