第21条:用函数对象表示策略

第21条:用函数对象表示策略

有些语言支持函数指针(function pointer)、代理(delegate)、lambda表达式(lambda expression),或者支持类似的机制,允许程序把“调用特殊函数的能力”存储起来并传递这种能力。这种机制通常用于允许函数的调用者通过传入第二个函数,来指定自己的行为。

Java中没有提供函数指针,但是可以用对象引用实现同样的功能。调用对象上的方法通常是执行该对象(that object)上的某项操作。然而,我们也可能定义这样一种对象,它的方法执行其它对象(other object)(这些对象被显示传递给这些方法)上的操作。如果一个类仅仅导出这样的一个方法,它的实例实际上就等同于一个指向该方法的指针。这样的实例被称为函数对象(function object)。例如考虑下面的类:

1 public class StringLengthComparator {
2     public int compare(String s1,String s2) {
3         return s1.length() - s2.length();
4     }
5 }

这个类导出一个带两个字符串参数的方法,这个方法是一个比较器,它根据长度来给字符串排序,而不是根据更常用的字典顺序。指向StringLengthComparator对象的引用可以被当做是一个指向该比较器的“函数指针(function pointer)”,可以在任意一对字符串上被调用。换句话说,StringLengthComparator实例就是用于字符串比较操作的具体策略(concrete strategy)。

作为典型的具体策略类,StringLengthComparator类是无状态的(stateless):它没有域,所以这个类的所有实例在功能上都是相互等价的。因此,它作为一个Singleton是非常合适的,可以节省不必要的对象创建开销:

1 public class StringLengthComparator {
2     private StringLengthComparator() {};
3     public static final StringLengthComparator INSTANCE = 
4             new StringLengthComparator();
5     public int compare(String s1,String s2) {
6         return s1.length() - s2.length();
7     }
8 }

为了把StringLengthComparator实例传递给方法,需要适当的参数类型。使用StringLengthComparator并不好,因为客户端将无法传递任何其他的比较策略。相反,我们要定义一个Comparator接口,并修改StringLengthComparator来实现这个接口。换句话说,我们在设计具体的策略类时,还需要定义一个策略接口(strategy interface),如下所示:

1 public interface Comparator<T> {
2     public int compare(T t1,T t2);
3 }

Comparator接口的这个定义也出现在java.util包中。Comparator接口是泛型的,因此它适合作为除字符串之外的其它对象的比较器,它的compare方法的两个参数类型为T(它正常的类型参数),而不是String。只要声明前面所示的StringLengthComparator类要这么做,就可以用它实现Comparator<String>接口:

1 public class StringLengthComparator implements Comparator<String>{
2     private StringLengthComparator() {};
3     public static final StringLengthComparator INSTANCE = 
4             new StringLengthComparator();
5     public int compare(String s1,String s2) {
6         return s1.length() - s2.length();
7     }
8 }

具体的策略类往往使用匿名类声明,下面的语句根据长度对一个字符串数组进行排序:

 1 String[] stringArray = new String[] {"remotes","result"};
 2 Arrays.sort(stringArray, new Comparator<String>() {
 3     @Override
 4     public int compare(String s1, String s2) {
 5         return s1.length() - s2.length();
 6     }
 7 });
 8 for (String string : stringArray) {
 9     System.out.println(string);
10 }

运行结果:

result
remotes

但是注意,以这种方式使用匿名类时,将会在每次执行调用的时候创建一个新的实例,如果它被重复执行,考虑将函数对象存储到一个私有的静态final域中,并重用它,这样做的好处是,可以为这个函数对象取一个有意义的域名称。

因为策略接口被用作所有具体策略实例的类型,所以我们并不需要为了导出具体策略,而把具体策略做成公有的。相反,“宿主类(host class)”还可以导出公有的静态域(或者静态工厂方法),其类型为策略接口,具体的策略接口类可以是宿主类的私有嵌套类。下面的例子使用静态成员类,而不是匿名类,以便允许具体的策略类实现第二个接口Serializable:

 1 class Host{
 2     private static class StrLenCmp implements Comparator<String>,Serializable{
 3         @Override
 4         public int compare(String t1, String t2) {
 5             return t1.length() - t2.length();
 6         }
 7     }
 8     public static final Comparator<String> STRING_LENGTH_COMPARATOR = 
 9             new StrLenCmp();
10 }

String类利用这种模式,通过它的CASE_INSENSITIVE_ORDER域,导出一个不区分大小写的字符串比较器。

简而言之,函数指针的主要用途就是实现策略(strategy)模式。为了在Java中实现这种模式,要声明一个接口来表示该策略,并且为每个具体策略声明一个实现了该接口的类。当一个具体策略只被使用一次时,通常使用匿名类来声明和实例化这个具体策略模类。当一个具体策略是设计用来重复使用的时候,它的类通常就要被实现为私有的静态成员类,并通过公有的静态final域被导出,其类型为该策略接口。

转载于:https://www.cnblogs.com/remote/p/10121602.html

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

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

相关文章

2021-2022学年编译原理考试重点[华侨大学]

2021-2022学年编译原理考试重点 注&#xff1a;计算部分请参考 编译原理实验报告 名词解释 编译器&#xff1a;编译阶段&#xff0c;用户输入源程序&#xff0c;经编译器翻译生成目标程序&#xff0c;目标程序在运行时接受输入数据&#xff0c;得到数据输出 解释器&#xff1a…

一文读懂全球半导体市场

来源&#xff1a;深城物联作者&#xff1a;孙卓异&#xff0c;供职于赛迪顾问集成电路产业研究中心 半导体是当今信息技术产业高速发展的基础和原动力&#xff0c;已经高度渗透并融合到了经济、社会发展的各个领域&#xff0c;其技术水平和发展规模已经成为衡量一个国家产业竞争…

如何写好一份技术简历?

写简历的基本目的和策略 大部分情况下&#xff0c;写简历是找工作的第一步&#xff0c;考虑到第二步就是面试&#xff0c;那么简历就是敲门砖&#xff0c;为了让企业认识到你的价值&#xff0c;必须把自己的真实水平描述出来&#xff0c;展现出你有能力应对这份工作。甚至要体现…

这是我看过最全的工业机器人知识介绍 !

来源&#xff1a;产业智能官编者按工业机器人广泛使用在产业制造上&#xff0c;汽车制造、电器、食品等&#xff0c;能替代反复机器式操纵工作&#xff0c;是靠本身动力和控制才能来实现种种功用的一种机器。它能够承受人类指挥&#xff0c;也能够按照事先编排的程序运转。今天…

表白网站|程序猿的爱情记录网站模版|情侣日记网页

程序猿的爱情记录网站模版&#xff5c;情侣日记网页设计 介绍 我为我的女朋友制作了这个主页&#xff0c;目的是记录一些值得纪念的时刻。 如果需要&#xff0c;您可以复制和修改此模板作为送给女朋友或妻子的礼物。 Demo Click here to review the website! ❤️ https://…

python-字符串方法

#find方法&#xff1a;查找子串&#xff0c;返回子串所在位置的最左端索引&#xff0c;如果没有找到则返回-1 s"agsa" print(s.find("gs")) print(s.find("agsaa")) #可以指定匹配的起始点和结束点参数,包含第一个索引&#xff0c;不包含第二个索…

智慧食堂数据分析系统

智慧食堂数据分析系统&#xff5c;大数据分析&#xff5c;数据可视化 Demo Repo&#xff1a;https://github.com/sylvanding/AI-Restaurant-Data-Analysis项目演示&#xff08;模拟真实运行环境&#xff09;&#xff1a;http://analysis.sylvanding.online数据展示静态页面&am…

鸿蒙系统全面解析,诞生背景、技术细节生态圈一文看懂

编辑&#xff1a;智东西内参华为6月2日正式发布的鸿蒙系统无疑占据了最近热点话题的C位&#xff0c;虽然不全是赞美的声音&#xff0c;但这种努力打破美国垄断&#xff0c;挑战谷歌、苹果在移动操作系统上垄断地位的尝试必将成为中国科技史上的里程碑事件。本期的智能内参&…

python-字典

字典映射&#xff1a;通过名字来引用值&#xff1b;字典是python中唯一内建的映射类型&#xff1b;1)创建字典&#xff1a;字典有键-值对(项)组成&#xff0c;键和值之间通过冒号(:)隔开&#xff0c;项之间通过逗号(,)分割&#xff0c;整个字典由大括号括起来&#xff1b;空字典…

2021十大人工智能趋势

来源&#xff1a;雷锋网6月5日&#xff0c;以“交叉、融合、相生、共赢”为主题的2021全球人工智能技术大会&#xff08;GAITC 2021&#xff09;在杭州举行。会上&#xff0c;腾讯优图联合厦门大学人工智能研究院共同发布《2021十大人工智能趋势》&#xff08;以下简称“趋势报…

通过CTY、VTY、TTY访问网络设备[计网实践Cisco Packet Tracer]

实验一&#xff1a;接入网络设备 学习目标 CTY访问网络设备VTY访问网络设备TTY访问网络设备WEB访问网络设备 实验环境 Cisco Packet Tracer 6.0 原创文章&#xff0c;转载请注明出处&#xff1a;©️Sylvan Ding ❤️ 实验内容 CTY访问设备 CTY是指通过Console接口访…

python-字符串格式化

1)字符串格式化format代表格式字符串&#xff0c;格式&#xff1a;format%x&#xff0c;x为被格式化的值&#xff0c;如果需要在格式化字符串中包括百分号&#xff0c;必须使用%%&#xff1b;format"Hello,%s.%s!" values(world,python) print(format%values)format&…

细数二十世纪最伟大的10大算法

来源&#xff1a;深度学习于机器视觉编辑&#xff1a;nhyilin一、1946 蒙特卡洛方法[1946: John von Neumann, Stan Ulam, and Nick Metropolis, all at the Los Alamos Scientific Laboratory, cook up the Metropolis algorithm, also known as the Monte Carlo method.]1946…

外连接就是允许不满足条件的字段查询出来

外连接就是允许不满足条件的字段查询出来转载于:https://www.cnblogs.com/classmethond/p/10129069.html

python-元组

不可变序列&#xff1a;元组&#xff0c;字符串元组用两个圆括号()来表示;用逗号分隔一些值&#xff0c;则自动创建了元组a(1,2,3) print(a) print(())#空元组 #一个值的元组需在值后加一个逗号&#xff0c;与括号进行区分&#xff1b; b(1)#非元组 c(1,) print(b) print(c)#函…

MIT发布首个贝叶斯「数据清洗」机器人!8小时洗200万条数据

来源&#xff1a;GitHub和数据派THU编辑&#xff1a;王菁校对&#xff1a;林亦霖脏数据可以说是所有AI从业者、数据分析师、数据科学家的噩梦。好消息来了&#xff01;麻省理工学院的研究人员最近带来了一种全新的系统PClean&#xff0c;能够自动地清洗脏数据&#xff0c;如错误…

我的开源项目——Jerry

在日常工作中&#xff0c;经常会碰到一些问题&#xff0c;比如数字金额要写成千分位形式&#xff08;1234 -> 123,4.00&#xff09;、要写成汉字大写形式&#xff08;123 -> 壹佰贰拾叁圆&#xff09;&#xff0c;又比如要进行 cookie 读写操作&#xff0c;这些问题都比较…

python-列表和元组

python 数据结构 1.序列(包括元组、列表、字符串、buffer对象和xrange对象)序列中第一个元素的索引为0&#xff0c;第二个为1&#xff0c;依次类推序列的最后一个元素标记为-1&#xff0c;最后第二个为-2&#xff0c;依次类推 既可以向前计数&#xff0c;也可以向后计数2.列表和…

李德毅院士:希望智能驾驶成为我国继高铁之后又一张新名片

来源&#xff1a;汽车俱乐部Plus/ 导读 /5月19日&#xff0c;在WIC2021第五届世界智能大会的分论坛“智能交通峰会”上&#xff0c;中国工程院院士&#xff0c;欧亚科学院院士李德毅发表了主题演讲。以下是演讲实录。让我们掌声欢迎中国工程院院士&#xff0c;欧亚科学院院士&a…

windows下vagrant的安装使用

vagrant是简便虚拟机操作的一个软件&#xff0c;而使用虚拟机有几个好处&#xff1a; 1、为了开发环境与生产环境一致&#xff08;很多开发环境为windows而生产环境为linux&#xff09;&#xff0c;不至于出现在开发环境正常而移步到正式生产环境时出现各种问题&#xff0c;而v…