改变数据类型的装饰器

装饰图案

自从第一次学习编程设计模式以来,装饰器模式一直是我的最爱。 在我看来,这是一个很新颖的想法,比其他想法有趣得多。 不要误会我的意思,其他大多数人也引起了我的注意,但没有什么比装饰器模式更重要。 至今,它仍然是我的最爱之一。

(如果您不熟悉设计模式,我强烈建议您采用Head First Design Patterns 。如果您只是想学习装饰器模式,请参考这本书的装饰器章节摘录 。)

我个人认为装饰器模式通常未得到充分利用。 可能有几个原因。 一方面,我认为这不适用于所有情况。 另外,装饰器模式可以解决的问题通常很难发现。 是什么让该模式如此令我赞叹,这是因为可能很难弄清楚需要在何处,这是因为它是一个不寻常的想法。 就是说,直到您对“继承之上的构成”的原理非常熟悉为止。

太多的地方将继承深深地打入您的脑海,以至于使人难以相信组合通常是比继承更好的主意。

无论如何,装饰器模式不仅是我最喜欢的模式,而且在Java 8我最喜欢的新功能之一中也强烈使用了它:Stream API。 实际上,我要向您展示的大部分内容都在很大程度上模仿了Stream API的某些行为。

问题

假设您有一个字符串列表,但它们可能有也可能没有不需要的前导或尾随空格。 您可能会这样做,以消除不需要的空间。

List untrimmedStrings = aListOfStrings();
List trimmedStrings = new ArrayList();for(String untrimmedString : untrimmedStrings)
{trimmedStrings.add(untrimmedString.trim());
}//use trimmed strings...

在这种情况下,您将创建一个全新的字符串列表,并使用第一个列表中的字符串填充该字符串,但会对其进行修剪。 这有几个问题。 首先,它立即创建了一个完整的新列表。 相反,每个修剪后的String的创建都可以延迟到需要时才进行,甚至在不需要时也永远不会执行。 另外,如果有人想添加更多字符串,则必须将它们添加到两个列表中。 您还必须确保先修剪新的字符串,然后再将它们放入修剪的列表中。 最后,此代码是命令性的,而不是声明性的。

让我们看一下代码的更具声明性的版本,然后看看如何使用它来解决其他问题。

List untrimmedStrings = aListOfStrings();
List trimmedStrings = trimmed(untrimmedStrings);//use trimmed strings...

哎呀,该trimmed()函数可能会发生任何事情! 看看那个; 它返回字符串列表,就像前面的方法一样。 这样做的好处,对吧?

错误。 是的,该函数从技术上讲可以做与之前相同的操作,这意味着我们所做的只是使外部代码具有声明性。 但是在此示例中,它打算是一个静态工厂方法(带有静态导入),该方法创建一个新的Trimmed对象,该对象包装了untrimmedStrings列表。 Trimmed实现了List接口,但它几乎将所有内容都委派给包装的列表,但通常具有修饰的功能。 当添加或删除新的String时,通过对包装列表进行处理,可以对两个列表进行“合并”。 并且当它添加新的String时,可以按原样添加它,但是然后只需确保在输出时将其修剪掉即可。

另外,由于仅在从列表中提取数据时才进行修剪,因此我们不必立即完成修剪每个String的所有工作。 有可能甚至无法处理某些字符串,因此永远不会不必要地修剪那些字符串。

但是,这有一些缺点。 一种,如果修剪过的字符串多次从列表中拉出,则最终每次都会修剪。 这不会占用任何额外的内存,但是会增加一些时间,尤其是如果您遍历整个列表几次。 其次,它会产生修剪后的列表和未修剪的列表为同一列表的副作用。 无论我们是否想要,更改一个都会影响另一个。

在本文中,我不想浪费太多时间和空间来向您展示完全创建的Trimmed的List实现(为List定义了30多种方法),因此,我将对其进行调整,以便仅定义的可迭代方法。 由于在很多时候,您真正要做的只是遍历集合,因此必须相对可以接受。

public class Trimmed implements Iterable
{public static List trimmed(List base) {return base;}public Trimmed(Iterable base){this.base = base;}public Iterator iterator(){return new TrimmedIterator(base.iterator());}private Iterable base;
}class TrimmedIterator implements Iterator
{public TrimmedIterator(Iterator base){this.base = base;}public boolean hasNext(){return base.hasNext();}public String next(){return base.next().trim();}public void remove(){throw new UnsupportedOperationException();}private Iterator base;
}

如何装饰对象

我不记得有人在任何地方提及此事,但这很重要,因此我想告诉您。

关于装饰对象,有2种基本的思想流派。 第一种是当您简单地传入传入经过装饰/包装的对象来创建装饰器的新实例时。第二种方法是在要装饰的对象上调用一个方法。

这两个选项都显示在这里

MyCollection untrimmedStrings = aCollectionOfStrings();//new Decorator Instance
MyCollection trimmedStrings = new TrimmingDecorator(untrimmedStrings);//OR//method call on the to-be-decorated object
MyCollection trimmedStrings2 = untrimmedStrings.trimmed();

而且trimmed()的代码如下所示:

public MyCollection trimmed() {return new TrimmingDecorator(this);
}

每种方法都有其优点和缺点。 由于每个选项的弊端本质上都缺乏另一个选项的优点,因此我只列出每个选项的优点。

新实例专家:

  • 比方法调用选项可扩展,因为方法调用必须尝试涵盖装饰器的所有可能性
  • 用户可以更轻松地看到它是装饰器模式
  • 可修饰界面中所需的方法更少

方法调用的优点:

  • 如果用户不需要知道,则隐藏装饰器实现
  • 用户端没有明确的“新”关键字(通常被认为是不好的)
  • 用户可以轻松找到所有装饰器,因为它们都在可装饰对象的界面上列出了

Java的原始IO库是新实例装饰的一个很好的例子,而Java 8中的Stream API是方法调用装饰的一个很好的例子。 我个人的喜好是使用方法调用选项,因为它使所有可能性对用户显而易见,但是如果要这样做,则用户也可以使用自己的装饰器扩展对象,那么您绝对应该使用新的实例路由。

翻译自: https://www.javacodegeeks.com/2015/01/transforming-collections-with-decorators.html

改变数据类型的装饰器

改变数据类型的装饰器_用装饰器改变收藏相关推荐

  1. OpenGL ES _ 着色器_片断着色器详解

    OpenGL ES _ 入门_01 OpenGL ES _ 入门_02 OpenGL ES _ 入门_03 OpenGL ES _ 入门_04 OpenGL ES _ 入门_05 OpenGL ES ...

  2. axios拦截器_请求拦截器_响应拦截器---axios工作笔记010

    然后我们再去看看axios的,请求拦截器,和响应拦截器. 先说一下这个,拦截器的原理,其实就是 我们发送一个请求,这个请求在发出去之前,我们的请求拦截器,先去拦截一下,拦截的时候可以对请求数据做一些处 ...

  3. python的网页解析器_网页解析器(BeautifulSoup)-- Python

    分享一下关于 Python的网页解析器(BeautifulSoup) BeautifulSoup解析器 为了实现解析器,可以选择使用正则表达式.html.parser.BeautifulSoup.lx ...

  4. 安卓pdf阅读器_电子书阅读器选哪个好?这篇文章告诉你!

    电子书是一种采用电子纸的显示屏幕的新式数字阅读器.它辐射小.耗电低.不伤眼睛.携带方便,而且它的显示效果逼真,看起来和纸质书本的效果一样,备受读书一族的喜爱.那么,电子书哪个牌子好?电子阅读器哪个品牌 ...

  5. python贝叶斯分类器_朴素贝叶斯分类器的简单Python实现

    本文介绍如何使用Python实现一个简易的朴素贝叶斯分类器(Naive Baves classifier). 贝叶斯公式 我们先简单回顾一下贝叶斯公式: 其中,我们称P(A)和P(B)为先验概率,P( ...

  6. android 取色器_音乐剪辑器手机版下载-音乐剪辑器app下载v9.10.15 安卓免费版

    音乐剪辑器app是非常棒的剪辑软件,大家可以使用它对各种彩铃铃声,原版音乐进行剪辑编辑处理,功能强大完全免费,而且操作非常简单,有需要的朋友赶快下载试试吧! 音乐剪辑器手机版介绍 有时候想把多首歌曲合 ...

  7. 包管理器_包管理器的演变

    包管理器 每个计算机化设备都使用某种形式的软件来执行其预期的任务. 在软件的早期,对产品进行了严格的bug和其他缺陷测试. 在过去的十年左右的时间内,该软件已通过Internet发布,目的是通过应用新 ...

  8. 用java写修改器_一些修改器1

    1.增加:$inc db.mycoll.update({}, {"$inc":{"mykey":10}}); 2.设置:$set db.mycoll.updat ...

  9. npm 包管理器_纱包管理器:npm的改进

    npm 包管理器 From bower to npm, package management for the web has come a long way. 从Bower到npm ,Web的软件包管 ...

最新文章

  1. linux搭建markdown服务,Markdown新手快速入门基础教程及Ubuntu下的安装
  2. 基于ip地址的客户识别原理_使用 LVS 实现负载均衡原理及安装配置
  3. 如何利用office绘制施工进度计划横道图?
  4. ntu 课程笔记 :MAS714(7) 最短路径和优先队列
  5. 帮助方老师使用固态硬盘安装win10,赚了150软妹币(但是他赖账了!)
  6. 安装Oracle数据库操作步骤
  7. python 从入门到实践_Python编程从入门到实践日记Day15
  8. erp采购总监个人总结_2018计划工作年终总结和2019目标:助理版、经理版、总监版(二)...
  9. python decorator. decorator_Python 装饰器Decorator(一)
  10. IPC通信:Posix消息队列的属性设置
  11. net安装 0x80096004 无法验证证书的签名_如何购买iOS签名证书
  12. linux大一实验报告,linux实验报告
  13. iTop-4412 SCP 精英版 linux-4.14.12 内核移植(2)
  14. Cloud 团队:让 TiDB 在云上跳舞 | PingCAP 招聘季
  15. python微博相册爬虫
  16. ARM公司发展历程 - 从1985年至今
  17. vue部署nginx无法访问服务端端问题
  18. 微信云开发之小游戏排行榜的实现,云数据库,云函数【白玉无冰】每天进步一点点
  19. 如何查看电脑的SN码?
  20. iphone 控制android手机,如何从Apple手机远程控制Android手机

热门文章

  1. jzoj1267-路障【最短路,SPFA】
  2. 【bfs】廉价最短路径(2013特长生 T4)
  3. Java中关于String类型的10个问题
  4. Hibernate注解(一)之持久化实体
  5. 命令模式的两种不同实现
  6. 漫画算法:判断2的乘方
  7. winform通过ListView绑定数据库数据源
  8. 无缝滚动图片——源码
  9. AntDesignPro一次添加多条数据的表单字数限制,并且把input框变为可变文本框
  10. React中构造函数、reader和函数的调用次数和时机测试