你有一份8千offer待签收
大运营时代的到来,深度打造网络营销复合人才 多渠道运营,紧贴企业...
一个有自己主意的孩子才是有前途的孩子
高考成绩不理想,该何去何从? fun88网职业技术学校 就业早一步,...
"5年后不会再有互联网公司,因为所有的公司都在用互联网!"李彦宏在...
选学校,选专业,就选fun88网
电商公开着陆页
东莞fun88网金码学校,东莞电脑培训,计算机专业技能培训,东莞北大青...
其他语言(包括 Java 下一代语言)存在巨大的扩展潜力。在本期和接下来的两期文章中,我将探索扩展 Java 类而不涉及继承性的途径。在本文中,您会了解如何向现有类添加方法,无论是直接还是通过语法糖 (syntactic sugar)。
表达式问题
表达式问题是最近的计算机科学历史上的一个众所周知的观察结果,首创于贝尔实验室的 Philip Wadler 的一篇未发表的论文(参见 参考资料)。(Stuart Sierra 在其 developerWorks 文章 “通过 Clojure 1.2 解决表达式问题” 中出色地解释了它。在这篇文章中,Wadler 说道:
表达式问题是老问题的新名字。我们的目标是通过案例定义数据类型,在这里,在不重新编译现有代码的情况下,您可以将新的案例添加到数据类型和数据类型的新函数中,同时保留静态类型安全(例如,没有转换)。
换句话说,您如何向一个分层结构中的类添加功能,而不求助于类型转换或 if 语句?
我们将通过一个简单的例子来表明表达式问题在真实世界中的表现形式。假设您公司始终假设应用程序中的长度单位为米,没有在您的类中为任何其他长度单位构建任何功能。但是,有一天,您公司与一家竞争对手合并了,而这个竞争对手始终假设长度单位为英尺。
解决该问题的一种方法是,通过使用转换方法扩展 Integer,使两种格式之间的切换变得无关紧要。现代语言提供了多种解决方案来实现此目的;在本期中,我将重点介绍其中的 3 种:
开放类包装器类协议回页首Groovy 的类别和 ExpandoMetaClass
Groovy 包含两种使用开放类 扩展现有的类的不同方式,“重新开放” 一个类定义来实现更改(例如添加、更改或删除方法)的能力。
类别类
类别类(一种借鉴自 Objective-C 的概念)是包含静态方法的常规类。每个方法至少接受一个参数,该参数表示方法扩充的类型。如果希望向Integer 添加方法,例如我需要接受该类型作为第一个参数的静态方法,如清单 1 所示:
清单 1. Groovy 的类别类
class IntegerConv {
static Double getAsMeters(Integer self) {
self * 0.30480
}
static Double getAsFeet(Integer self) {
self * 3.2808
}
}
清单 1 中的 IntegerConv 类包含两个扩充方法,每个扩充方法都接受一个名为 self(一个通用的惯用名称)的 Integer 参数。要使用这些方法,我必须将引用代码包装在一个 use 代码块中,如清单 2 所示:
清单 2. 使用类别类
@Test void test_conversion_with_category() {
use(IntegerConv) {
assertEquals(1 * 3.2808, 1.asFeet, 0.1)
assertEquals(1 * 0.30480, 1.asMeters, 0.1)
}
}
清单 2 中有两个特别有趣的地方。首先,尽管 清单 1 中的扩展方法名为 getAsMeters(),但我将它称为 1.asMeters。Groovy 围绕 Java 中的属性的语法糖使我能够执行 getAsMeters() 方法,好像它是名为 asMeters 的类的一个字段一样。如果我在扩展方法中省略了 as,对扩展方法的调用需要使用空括号,就像 1.asMeters() 中一样。一般而言,我喜欢更干净的属性语法,这是编写特定于域的语言 (DSL) 的一种常见技巧。
清单 2 中第二个需要注意的地方是对 asFeet 和 asMeters 的调用。在 use 代码块中,我同等地调用新方法和内置方法。该扩展在 use 代码块的词法范围内是透明的,这很好,因为它限制了扩充(有时是一些核心)类的范围。
ExpandoMetaClass
类别是 Groovy 添加的第一种扩展机制。但事实证明对构建 Grails(基于 Groovy 的 Web 框架)而言,Groovy 的词法范围限制太多了。由于不满类别中的限制,Grails 的创建者之一 Graeme Rocher 向 Groovy 添加了另一种扩展机制:ExpandoMetaClass。
ExpandoMetaClass 是一种懒惰实例化的扩展持有者,它可从任何类 “成长” 而来。清单 3 展示了如何使用 ExpandoMetaClass,为我的Integer 类实现我的扩展:
清单 3. 使用 ExpandoMetaClass 扩展 Integer
class IntegerConvTest{
static {
Integer.metaClass.getAsM { ->
delegate * 0.30480
}
Integer.metaClass.getAsFt { ->
delegate * 3.2808
}
}
@Test void conversion_with_expando() {
assertTrue 1.asM == 0.30480
assertTrue 1.asFt == 3.2808
}
}
在 清单 3 中,我使用 metaClass holder 添加 asM 和 asFt 属性,采用与 清单 2 相同的命名约定。对 metaclass 的调用出现在测试类的一个静态初始化器中,因为我必须确保扩充操作在遇到扩展方法之前发生。
类别类和 ExpandoMetaClass 都在内置方法之前调用扩展类方法。这使您能够添加、更改或删除现有方法。清单 4 给出了一个示例:
清单 4. 取代现有方法的扩展类
@Test void expando_order() {
try {
1.decode()
} catch(NullPointerException ex) {
println("can't decode with no parameters")
}
Integer.metaClass.decode { ->
delegate * Math.PI;
}
assertEquals(1.decode(), Math.PI, 0.1)
}
清单 4 中的第一个 decode() 方法调用是一个内置的静态 Groovy 方法,它设计用于更改整数编码。正常情况下,它会接受一个参数;如果调用时没有任何参数,它将抛出 NullPointerException。但是,当我使用自己的 decode() 方法扩充 Integer 类时,它会取代原始类。
回页首Scala 的隐式转换
Scala 使用包装器类 来解决表达式问题的这个方面。要向一个类添加一个方法,可将它添加到一个帮助类中,然后提供从原始类到您的帮助器的隐式转换。在执行转换之后,您就可以从帮助器隐式地调用该方法,而不是从原始类调用它。清单 5 中的示例使用了这种技术:
清单 5. Scala 的隐式转换
class UnitWrapper(i: Int) {
def asFt = {
i * 3.2808
}
def asM = {
i * 0.30480
}
}
implicit def unitWrapper(i:Int) = new UnitWrapper(i)
println("1 foot = " + 1.asM + " meters");
println("1 meter = " + 1.asFt + "foot")
在 清单 5 中,我定义了一个名为 UnitWrapper 的帮助器类,它接受一个构造函数参数和两个方法:asFt 和 asM。在拥有转换值的帮助类后,我创建了一个 implicit def,实例化一个新的 UnitWrapper。要调用该方法,可以像调用原始类的一个方法那样调用它,比如 1.asM。当 Scala 未在 Integer 类上找到 asM 方法时,它会检查是否存在隐式转换,从而允许将调用类转换为一个包含目标方法的类。像 Groovy 一样,Scala 拥有语法糖,因此我能够省略方法调用的括号,但这是一种语言特性而不是命名约定。
Scala 中的转换帮助器通常是 object 而不是类,但我使用了一个类,因为我希望传递一个值作为构造函数参数(object 不允许这么做)。
Scala 中的隐式转换是一种扩充现有类的精妙且类型安全的方式,但不能向开放类一样,使用这种机制更改或删除现有方法。
回页首Clojure 的协议
Clojure 采用了另一种方法来解决表达式问题的这个方面,那就是结合使用 extend 函数和 Clojure 协议 抽象。协议在概念上类似于一个 Java 接口:一个没有实现的方法签名集合。尽管 Clojure 实质上不是面向对象的,而是偏向于函数,但您可以与类进行交互(并扩展它们),并将方法映射到函数。
为了扩展数字以添加转换,我定义了一个协议,它包含我的两个函数(asF 和 asM)。我可使用该协议 extend 一个现有类(比如Number)。extend 函数接受目标类作为第一个参数,接受该协议作为第二个参数,以及一个使用函数名为键并使用实现(以匿名函数形式)为值的映射。清单 6 显示了 Clojure 单位转换:
清单 6. Clojure 的扩展协议
(defprotocol UnitConversions
(asF [this])
(asM [this]))
(extend Number
UnitConversions
{:asF (fn [this] (* this 3.2808))
:asM #(* % 0.30480)})
我可以在 Clojure REPL(interactive read-eval-print loop,交互式读取-重新运算-打印循环)上使用新的扩展来验证该转换:
user=> (println "1 foot is " (asM 1) " meters")
1 foot is 0.3048 meters
在 清单 6 中,两个转换函数的实现演示了匿名函数声明的两种语法变体。每个函数只接受一个参数(asF 函数中的 this)。单参数函数很常见,以至于 Clojure 为它们的创建提供了语法糖,如 AsM 函数中所示,其中 % 是参数占位符。
协议创建了一种将方法(以函数形式)添加到现有类中的简单解决方案。Clojure 还包含一些有用的宏,使您能够将一组扩展整合在一起。例如,Compojure Web 框架(参见 参考资料)使用协议扩展各种类型,以便它们 “知道” 如何呈现自身。清单 7 显示了来自 Compojure 中的Renderable 的一段代码:
清单 7. 通过协议扩展许多类型
(defprotocol Renderable
(render [this request]
"Render the object into a form suitable for the given request map."))
(extend-protocol Renderable
nil
(render [_ _] nil)
String
(render [body _]
(-> (response body)
(content-type "text/html; charset=utf-8")))
APersistentMap
(render [resp-map _]
(merge (with-meta (response "") (meta resp-map))
resp-map))
IFn
(render [func request]
(render (func request)
; . . .
在 清单 7 中,Renderable 协议是使用单个 render 函数来定义的,该函数接受一个值和一个请求映射作为参数。Clojure 的 extend-protocol宏(它可用于将协议定义分组到一起)接受类型和实现对。在 Clojure 中,您可使用下划线代替不关心的参数。在 清单 7 中,这个定义的可看见部分为 nil、String、APersistentMap 和 IFn(Clojure 中的函数的核心接口)提供了呈现指令。(该框架中还包含其他许多类型,但为节省空间,清单中省略了它们。)可以看到这在实践中非常有用:对于您可能需要呈现的所有类型,您可将语义和扩展放在一起定义。
人们为了改变现状,追求自己的幸福生活,越来越多的人都选择了拼搏。那么在拼搏的路上是否真能实现自己的目标,很关键的一步便在于最初的选择,那你需要有一技之长的技术,那么在这个社会,现在学什么技术工资高,就业不用愁呢?那肯定是 学一门好的电脑专业了,高薪资,好就业,前景广阔,提升空间大。要满足这些条件的技术工作,数IT行业最合了!
许多合作企业会根据用人需求和企业发展情况不定期到fun88网东莞金码学校现场招聘IT专业人才,上千家合作企业遍布全国各地,学员根据自己的
项目实训招募啦~~fun88网东莞金码学校合作企业、学术团队举行项目实训招募活动,让学员有机会根据自己的喜好选择项目实训,参与项目的开发。
fun88网东莞金码组织学员进行各种户外拓展、郊游、烧烤等集体活动,让学员们充分感受集体生活的温暖和团队的力量。
2017年1月12日,嘉华教育集团在深圳南山文体中心隆重举办了11周年庆典。出席本次庆典的嘉宾有原外交部副部长胡恩才先生、原深圳大学校长
根据前程无忧的统计数据,截至2013年5月31日,前程无忧的网上发布职位数中面向应届生人群开放的职位数超过11万个,占招聘职位总数的4 25%,
现在越来越多的企业采取小组面试(Panel Interview)。似乎这种面试的形式逐渐成为一种流行的趋势。不仅是初级员工,包括很多高级人才和职业
面试官类型不同,到底都有哪些种类呢?跟着来看看吧。一、呆板稚嫩型这类面试官一般出现在面试的第一轮,他们由于缺乏面试经验,大多数情况
翻遍诸多面试攻略,一般都有这么一条金科玉律:面试一开始不能询问薪水,作为卖方市场的求职者,每次面试时我们都会谨慎言行。明明是正大光
说到面试,大家最关心的,想必是怎样才能从容应对面试官的提问了。虽然,我们在面试经验分享的文章中常能看到求职者要学会包装自己并向面试
有了这些法宝,妈妈以后再也不用担心我加班了~一、产品狗、运营猫的数据处理中心1 infogr am infogr am是一个强大的数据可视化图表创作
本篇文章将记录如何编写一个最简单的WebPart的最后一部分,即添加WebPart,包括把WebPart添加到网站的WebParts列表中,及把WebPart添加到AS
1 splice(start,[,length,newValue ])对数组中某索引范围进行删除 声明数组对象var myArray = ["a", "b", "c", "d", "e"]; 从数
随着移动互联网技术的不断发展,移动互联网用户发送和上传的数据量达到1 3exabytes,相当于10的18方。BigData大数据是继云计算、物联网之后
现在,在各种营销手段都百家争鸣、百花齐放的时代,电子邮件营销几乎一夜之间便显得逊色了许多。然而,令许多企业和厂商纠结不已的是,电子邮件营销虽然已经“人老珠黄”,
初中生无学历无技能,不进工厂上班还可以做什么呢?这是很多低学历人群想要提升自己,却又找到出路的迷茫问题。难道初中生就只有在工厂干体
2015年是嘉华职业教育集团十周年,为了营造浓厚的校园文化艺术氛围,提供给学生一个展示自我、彰显个性的舞台,带动更多学子走进IT职业领域
6月22日下午,青鸟学社全体成员参与了由学习部举办的第二期学习经验交流会,怀着激动的心情,同学们坐等着交流会的开始!随着激动人心的曲子
01岗位了解所谓的工程师是通过学习和训练,掌握网络技术的理论知识和操作技能的网络技术人员。网络工程师能够从事计算机信息系统的设计、建
春节、元宵节是我国民间最重要的传统节日,是我国人民庆贺丰收、祈福风调雨顺、家人团聚的日子。而猜灯谜、吃汤圆则是元宵佳节必不可少的活