设计模式装饰者模式_装饰者模式如何拯救了我的一天
设计模式装饰者模式
在工作中,我正在处理庞大的Java代码库,该代码库是由许多不同的开发人员在15年的时间里开发的。 并不是所有的事情都由书来完成,但是同时我通常无法重构遇到的每一个奇怪的事物。
尽管如此,仍可以每天采取提高代码质量的措施。 今天就像那样……
总览
由于已 存在 大量 教程 ,因此本文的目的不是教授装饰器模式。 相反,它提供了一个现实生活中的示例,说明它如何派上用场并节省了一天的时间。
情况
我们的UI包含Swing的JEditorPanes ,用于显示HTML。 与各种链接(如悬停和单击)的交互会触发以下一个或多个响应:
- 记录事件
- 更改光标(JEditorPane已经自行完成;似乎从2000年5月开始-…?!)
- 使用链接的内容更新窗格
- 打开外部浏览器
- 打开外部应用程序
- 处理内部服务请求
对于所有窗格,这些响应都不相同。 其中有一些需求部分不同。 (如果您知道装饰器模式,那么您会看到它的去向。)
所以问题是:您如何实施这些响应?
一种可配置类的解决方案
您可以将所有这些都放在一个类中,该类实现HyperlinkListener
并使用标记来(取消)激活不同的响应。
这个课真是地狱! 是的,地狱 就这么简单。
首先,它将是巨大的。 而且,其本质上不相关的职责之间可能以某种方式有些奇怪的依赖。这种规模和这些关系将使编写和测试变得更加困难,甚至使理解和修改变得更加困难。
(顺便说一句,造成混乱的根本原因是AllInOneHyperlinkListener
违反了单一责任原则 。由于这篇文章已经足够长了,因此我将不作详细介绍。)
继承的解决方案
无论如何,我很幸运没有发现自己正在面对一个庞然大物的听众。 取而代之的是,我发现了一个小的类层次结构,这些类将这些职责划分为它们( HL是HyperlinkListener的缩写):
CursorSettingHL implements HL
:记录事件并设置光标UrlProcessingHL extends CursorSettingHL
:
通过更新窗格的内容或打开外部浏览器/应用程序来处理URLServiceRequestHandlingHL extends UrlProcessingHL
:如果是服务请求,则处理URL; 否则委托给它的超类
这看起来更好,不是吗? 好…
首先,某些班级仍然要承担几项责任。 没有真正的理由解释为什么日志和更改游标应该由同一类完成。 (我只能猜测,这种结构会随着时间的推移而有机地增长,而没有任何更深层次的设计。)因此,问题较小,但尚未消失。
它也显示在班级名称中。 上面的内容已经过改进,以提高可读性。 原始文档中充满了Default , Simple和其他非信息。 这个名字甚至是误导性的名字都不是简单的疏忽。 它们是缺乏凝聚力的自然结果。
但是通过更深层次的管理,这些问题本来可以得到缓解。 六个类可以各自实现一件事。 但这也不会帮助我。
不,此解决方案的真正问题是模拟的灵活性。 看起来您可以选择,但实际上您不能。 看看当事情改变时会发生什么。
改变
我们慢慢地从摇摆移动到JavaFX的,我想以取代FX JEditorPane中” 的WebView 。 (实际上,将HyperlinkListeners放入WebView有点麻烦,但我将在另一篇文章中再讨论。)WebView已经完成了上面的某些操作,因此这是新侦听器具有的更新响应列表。触发:
- 记录事件
改变光标用新内容更新窗格- 打开外部浏览器
- 打开外部应用程序
- 处理内部服务请求
在这里,整个类系统变得毫无用处。 (至少因为我不愿意让监听者对隐身控件进行2.和3.。)在这一点上,很明显,职责混在一起了。 我仍然需要其中一些,但不是全部,而且由于它们之间没有阶级界限,所以我处于全有或全无的情况。
救援人员的装饰模式
因此,当我在考虑要混合和匹配现有功能的程度时,它最终使我感到痛苦(并且比预期的要晚得多):这正是装饰器模式的目的!
装饰图案
就像我说的,我不会详细介绍这种模式,但是基本思想是:
当存在一个接口,不同的实现可以提供不同的功能时,请让每个实现独立运行。 但是要实现它们,以便在工作中的某个时刻,他们将控制权移交给同一接口的另一个实例。
如果一个这样的实现调用另一个,并使用该结果来计算自己的实现,那么两者都会做自己的事情,但是效果会重叠。 第二个实例的结果仍然存在,但第一个实例有些改变。 因此,据说第一个装饰第二个。
这可以在更多实例中进行,每个实例都装饰前者。 应该将其视为分层系统,其中每个装饰器向整体添加另一层行为。
行动中
现在方法很清楚:我将上述功能重构为不同的装饰器,例如LoggingHyperlinkListenerDecorator
和ServiceRequestHandlingHyperlinkListenerDecorator
。
然后,我删除了原始类,并用正确的装饰器组合替换了它们的用途。 最终,我了解了新功能并选择了正确的装饰器。 用Java 8可以做到这一点,但是为了简单起见,让我们在这里使用构造函数:
将装饰器放在一起
// use a lambda expression to create the initial listener
// which does nothing
HyperlinkListener listener = event -> {};
// these decorators first do their own thing and then call the
// decorated listener (the one handed over during construction);
// in the end, the last added decorator will act first
listener = new ExternalApplicationOpeningHyperlinkListenerDecorator(listener);
listener =new BrowserOpeningHyperlinkListenerDecorator(listener);
listener =new ServiceRequestHandlingHyperlinkListenerDecorator(listener);
listener =new LoggingHyperlinkListenerDecorator(listener);
除了样板之外,很明显这里发生了什么。 首先,在我们确定服务请求并处理它们之前,将进行日志记录。 如果可能,将在浏览器中打开其他任何内容; 否则,我们会将其交给一些外部应用程序。
效果
您马上就可以看到对代码的积极影响。 首先,每个班级都有一个非常简单的责任。 这导致了简短易懂的课程。 他们的名字通常是当场就正确地告诉您他们在做什么。 另外,由于每个单元中发生的事情较少,因此可测试性也提高了。
此外,将装饰器放在一起的地方更能揭示其意图。 您不必检查实例化的ServiceRequestHandlingHyperlinkListener
及其超类即可了解侦听器的确切功能。 取而代之的是,您仅查看装饰列表,看看会发生什么。
最后但并非最不重要的一点,它使代码为将来的更改做好了准备。 现在很明显如何实现新的侦听器功能。 对于继承的类,您必须想知道在何处放置新功能,以及新功能如何影响该类的现有用法。 现在,您只需实现第updecth装饰器,并在需要的地方添加它即可。
反射
这个真实的例子展示了装饰器模式的应用如何使代码更易于阅读,测试和更改。
当然这不是自动的。 该模式只能在确实使代码更清洁的地方使用。 但是要决定这一点,您必须了解它并且必须能够推理其影响。 我希望这篇文章对此有所帮助。
非常感谢Wikipedia的Benjah ,他创造了 Vaska复杂建筑 的美丽形象并将其发布到公共领域。
翻译自: https://www.javacodegeeks.com/2015/01/how-the-decorator-pattern-saved-my-day.html
设计模式装饰者模式
设计模式装饰者模式_装饰者模式如何拯救了我的一天相关推荐
- 工厂设计模式解决什么问题_使用工厂模式解决设计问题
工厂设计模式解决什么问题 工厂设计模式是面向对象环境中最常用的模式之一. 再次来自"创意设计"模式类别,即有关对象创建的所有信息. 在某些情况下,对象的创建很复杂,可能需要某种程度 ...
- 工厂方法模式_工厂方法模式
工厂方法模式是简单工厂模式的升级版,简单工厂模式不符合设计模式的原则(即:单一职责,开闭原则) 优点: 职责明确,扩展方便 缺点:需要创建多个工厂 实现步骤: 1.将工厂通用方法抽取接口 (例如:IF ...
- 工程模式和抽象工厂模式_功能工厂模式
工程模式和抽象工厂模式 您是否需要一种非常快速的方法来制作Factory对象? 然后,您需要lambda或其他函数传递! 它不仅快速,而且非常简单. 我敢打赌,如果您对Lambdas相当满意,那么您只 ...
- 哈斯机床进去debug模式_责任链模式
原文链接: 责任链模式 | 菜鸟教程www.runoob.com 顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请 ...
- python的盈利模式_八大盈利模式是什么?一篇文教会你盈利模式分析!
当今如果说到创业,永远绕不开一个话题:"模式". 非创业者往往最关注的是"产品"或"服务": 初级创业者往往最关注的的是"行业&q ...
- shell开启飞行模式_手机飞行模式有什么用 手机飞行模式介绍【详解】
手机飞行模式功能一直被大家吐槽为最没有用的手机功能,随着智能手机的快速发展,手机很多功能都已经逐渐消失被替代,唯独飞行模式依旧占据着手机设置里的主要地位. 那么问题来了,手机飞行模式到底有什么用? 1 ...
- Hadoop 的三种运行模式_本地模式_伪分布式模式
演示的版本是:2.7.2 官方文档 Hadoop运行模式 Hadoop运行模式包括:本地模式.伪分布式模式以及完全分布式模式. Hadoop官方网站:http://hadoop.apache.org/ ...
- java mediator模式_中介者模式(Mediator)
中介者模式 一. 中介者模式 1.1 定义 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示的相互作用,从而使耦合松散,而且可以独立的改变他们之间的交互. 1.2 角色 抽象中介者类(A ...
- 设计模式 -结构型模式_ 装饰者模式Decorator Pattern 在开源软件中的应用
文章目录 定义 结构图 需求 装饰者模式 装饰者模式在MyBatis中的应用 小结 定义 装饰模式 Decorator : 在不改变原有功能的基础上, 动态的给一个对象添加一些额外的职责 ,非常符合开 ...
最新文章
- android:layout_gravity 和 android:gravity 的区别
- Lancet:支持奋战在疫情一线的中国科研技术工作者
- Markdown中常用的转义字符
- ERP实施过程中的误区 你知道吗?
- YOLOv4重磅发布,五大改进,二十多项技巧实验,堪称最强目标检测万花筒
- 1024“代码急救室”活动来袭!机械键盘、背包等程序员装备等你来!
- pmtk3怎样离线安装
- android 自定义控件的宽高_巧用Handler获取View控件信息
- pyqt5 python2.7_python2.7 安装pyqt5
- debian软raid
- Atitit 人工智能目前的进展与未来 包含的技术 v2 r99.docx
- python抽签代码,python:选房抽签小工具
- Cameralink光端机
- 【数据挖掘】关联规则和Apriori算法
- python数据分析师面试题选
- wordpress 更改excerpt的长度,设置excerpt后面'[...]'的字样和链接
- P3373(线段树)
- PC操作系统使用技巧
- 阿里云二级域名解析教程
- 会写Python代码的人工智能Kite宣布支持Linux,“程序猿”要失业了?
热门文章
- P3911-最小公倍数之和【莫比乌斯反演】
- nssl1519-背包签到题【数论】
- Codeforces Round #684 (Div. 2)
- GDKOI2021总结
- 12、oracle数据库下的存储过程和函数
- Java自动化邮件中发送图表(四)之javafx Chart
- ssm使用全注解实现增删改查案例——EmpServiceImpl
- System.err: java.net.UnknownServiceException: CLEARTEXT communication to 192.168.43.172 not permitte
- 最新版Intellij IDEA视频教程 20170814
- 计算机视觉论文doc,嘉炬-计算机视觉论文资料.doc