用装饰器改变收藏

装饰图案

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

(如果您不熟悉设计模式,我强烈建议您采用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;
}

如何装饰对象

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

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

这两个选项都显示在这里

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360918.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET WebAPI 自定义ControllerSelector

呃..今天同事要实现客户端调用不同版本Controller的功能, 其实几句代码就搞定了.. 首先定义自己的ControllerSelector,代码如下: public class ShadowControllerSelector : IHttpControllerSelector{private readonly HttpConfiguration _configuration;public ShadowControlle…

MomentJS计算两个时间的差值diff方法

moment(endTime).diff(moment(startTime), years)moment(endTime).diff(moment(startTime), months)moment(endTime).diff(moment(startTime), days) // 开始时间和结束时间的时间差,以“天”为单位;endTime和startTime都是毫秒数moment(endTime).d…

JAX-RS 2.0:服务器端处理管道

这篇文章的灵感来自JAX-RS 2.0规范文档 (附录C)中的Processing Pipeline部分。 我喜欢它是因为它提供了JAX-RS中所有模块的漂亮快照-以准备好吞咽的胶囊形式! 礼貌– JAX-RS 2.0规范文档 因此,我想到了使用此图简要概述不同的JA…

基于TCP/IP的文件服务器编程一例

来源,华清远见嵌入式学院实验手册,代码来源:华清远见曾宏安 实现的功能: 编写TCP文件服务器和客户端。客户端可以上传和下载文件 客户端支持功能如下: 1.支持一下命令 help 显示客户端所有命令和说明 list 显示服务器…

React 向children中传值,layouts

const newChild React.children.map(children,function(childItem){return React.cloneElement(childItem,{key:传递的数据}) })

Apache TomEE + JMS。 这从未如此简单。

我记得J2EE (1.3和1.4)的过去,使用JMS启动项目非常困难。 您需要安装JMS 代理 ,创建主题或队列 ,最后使用服务器配置文件和JNDI开始自己的战斗。 感谢JavaEE 6及其它,使用JMS确实非常简单。 但是使用Apach…

Struts2显示double价格格式0.00

在国际化资源文件中加入&#xff1a; format.money{0,number,0.00} jsp页面用struts标签&#xff1a; <s:text name"format.money">   <s:param name"value" value"priceName" /> </s:text> 输出格式&#xff1a;0.00转载于…

数组方法大全ES5+ES6

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录1. 使用 Array 构造函数2. 使用数组字面量表示法数组原型方法1. join()2.push()和pop()3.shift() 和 unshift()4.sort()5.reverse()6.concat()7.slice()8.splice()9.…

【Linux系统基础】(2)在Linux上部署MySQL、RabbitMQ、ElasticSearch、Zookeeper、Kafka、NoSQL等各类软件

实战章节&#xff1a;在Linux上部署各类软件 前言 为什么学习各类软件在Linux上的部署 在前面&#xff0c;我们学习了许多的Linux命令和高级技巧&#xff0c;这些知识点比较零散&#xff0c;同学们跟随着课程的内容进行练习虽然可以基础掌握这些命令和技巧的使用&#xff0c;…

使用Java 8流进行快速失败的验证

我已经失去了使用类似方法通过失败快速验证代码状态的次数&#xff1a; public class PersonValidator {public boolean validate(Person person) {boolean valid person ! null;if (valid) valid person.givenName ! null;if (valid) valid person.familyName ! null;if (…

找到数组最大值

const maxHight Math.max.apply(null, rowData && rowData.urlImage.map(ele > ele.long) || []);

JDK 7和JDK 8中大行读取速度较慢的原因

我之前发布了博客文章“使用JDK 7和JDK 8读取慢速行”&#xff0c;并且在该问题上有一些有用的评论来描述该问题。 这篇文章提供了更多解释&#xff0c;说明为何该文章中演示的文件读取&#xff08;并由Ant的LineContainsRegExp使用 &#xff09;在Java 7和Java 8中比在Java 6中…

Spring Stateless State Security第3部分:JWT +社会认证

我的Stateless Spring Security系列文章的第三部分也是最后一部分是关于将基于JWT令牌的身份验证与spring-social-security混合在一起的。 这篇文章直接建立在此基础上&#xff0c;并且主要集中在已更改的部分上。 想法是使用基于OAuth 2的“使用Facebook登录”功能来替换基于用…

css React 单行省略和多行省略

单行省略 white-space: nowrap; text-overflow: ellipsis; overflow: hidden; word-break: break-all;多行省略 overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;我们需要在需要超出加省略号的标签…

nyoj239 月老的难题 二分图 匈牙利算法

月老的难题 时间限制&#xff1a;1000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描述月老准备给n个女孩与n个男孩牵红线&#xff0c;成就一对对美好的姻缘。 现在&#xff0c;由于一些原因&#xff0c;部分男孩与女孩可能结成幸福的一家&#xff0c;部分可能不会结…

使用系统规则测试System.in和System.out

编写单元测试是软件开发的组成部分。 当您的被测类与操作系统交互时&#xff0c;您必须解决的一个问题是模拟其行为。 这可以通过使用模拟代替Java Runtime Environment&#xff08;JRE&#xff09;提供的实际对象来完成。 支持Java的模拟的库是例如嘲笑或jMock 。 当您完全控…

循环对象

params为对象&#xff0c;key为对象的k值 Object.keys(params).forEach(key > {formData.append(key, params[key]); });

[转]C#操作XML方法详解

本文转自&#xff1a;http://www.cnblogs.com/minotmin/archive/2012/10/14/2723482.html using System.Xml;//初始化一个xml实例XmlDocument xmlnew XmlDocument(); //导入指定xml文件xml.Load(path);xml.Load(HttpContext.Current.Server.MapPath("~/file/bookstore.xml…

Web应用程序体系结构– Spring MVC – AngularJs堆栈

Spring MVC和AngularJs共同为构建表单密集型Web应用程序提供了一个真正高效且吸引人的前端开发堆栈。在这篇博客文章中&#xff0c;我们将看到如何使用这些技术构建表单密集型Web应用程序&#xff0c;并将这种方法与其他方法进行比较可用选项。 可以在此github 存储库中找到功能…

HTML5基础一:常用布局标签

1、DTD声明&#xff1a; <!doctype html> 2、布局标签 <html> <head></head> <body> //头部标签 <header> <nav>导航栏标签</nav> </header>  <div> //自定义主区间 <section> <ruby>夼<rp>(&…