- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
This关于函数式编程和面向对象编程之间的区别,Stack Overflow 上的流行答案是这样说的:
Object-oriented languages are good when you have a fixed set of operations on things, and as your code evolves, you primarily add new things. This can be accomplished by adding new classes which implement existing methods, and the existing classes are left alone.
Functional languages are good when you have a fixed set of things, and as your code evolves, you primarily add new operations on existing things. This can be accomplished by adding new functions which compute with existing data types, and the existing functions are left alone.
假设我有一个 Animal
界面:
public interface Animal {
public void speak();
}
我有一只Dog
、Cat
、Fish
和Bird
,它们都实现了该接口(interface)。如果我想向 Animal
添加一个名为 jump()
的新方法,我将不得不遍历所有子类并实现 jump()
.
访问者模式可以缓解这个问题,但似乎随着 Java 8 中引入的新功能特性,我们应该能够以不同的方式解决这个问题。在 scala
中,我可以轻松地使用模式匹配,但 Java 还没有。
Java 8 真的让在现有事物上添加新的操作变得更容易了吗?
最佳答案
您要完成的工作虽然令人钦佩,但在大多数情况下并不适合 Java。但在我开始之前......
Java 8 为接口(interface)添加了默认方法!您可以根据接口(interface)中的其他方法定义默认方法。这已经可用于抽象类。
public interface Animal {
public void speak();
public default void jump() {
speak();
System.out.println("...but higher!");
}
}
但最终,您将不得不为每种类型提供功能。我没有看到添加新方法和创建访问者类或部分函数之间的巨大差异。只是地点的问题。你想按 Action 或对象组织你的代码吗? (功能性或面向对象,动词或名词等)
我想我想表达的意思是 Java 代码是按“名词”组织的,原因不会很快改变。
访问者模式和静态方法可能是您按操作组织事物的最佳选择。但是,我认为访问者在不真正依赖于所访问对象的确切类型时最有意义。例如,可以使用 Animal visitor 让动物说话然后跳跃,因为所有动物都支持这两件事。跳跃访客对我来说意义不大,因为这种行为对于每只动物来说都是固有的。
Java 使真正的“动词”方法有点困难,因为它根据参数的编译时类型选择要运行的重载方法(参见下文和 Overloaded method selection based on the parameter's real type)。方法仅根据 this
的类型动态分派(dispatch)。这就是继承是处理此类情况的首选方法的原因之一。
public class AnimalActions {
public static void jump(Animal a) {
a.speak();
System.out.println("...but higher!");
}
public static void jump(Bird b) { ... }
public static void jump(Cat c) { ... }
// ...
}
// ...
Animal a = new Cat();
AnimalActions.jump(a); // this will call AnimalActions.jump(Animal)
// because the type of `a` is just Animal at
// compile time.
您可以使用 instanceof
和其他形式的反射来解决这个问题。
public class AnimalActions {
public static void jump(Animal a) {
if (a instanceof Bird) {
Bird b = (Bird)a;
// ...
} else if (a instanceof Cat) {
Cat c = (Cat)a;
// ...
}
// ...
}
}
但现在您只是在做 JVM 为您设计的工作。
Animal a = new Cat();
a.jump(); // jumps as a cat should
Java 有一些工具可以更轻松地向大量类添加方法。即抽象类和默认接口(interface)方法。 Java 专注于基于调用方法的对象来分派(dispatch)方法。如果您想编写灵活且高性能的 Java,我认为这是您必须采用的一种习惯用法。
P.S. 因为我是 That Guy™,所以我将介绍 Lisp,特别是 Common Lisp Object System (CLOS)。它提供了基于所有参数进行分派(dispatch)的多重方法。 Practical Common Lisp 一书甚至提供了 an example of how this differs from Java .
关于java - Java 8 是否提供了访问者模式的替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29090179/
我应该编写一个函数来打印一组给定的三个数字中两个较大数字的平方和。 我对这种情况的处理相当笨拙。我没有编写返回一组 3 中最大的两个数字的函数,而是编写了函数,以便表达式减少到两个所需的数字。 # S
如果有人可以提供帮助,我将不胜感激。我一直在敲我的头一天试图让这个工作。我已经在互联网上搜索并重新阅读了手册,但我就是不明白。 guile << __EOF__ ( define heading-li
目前我正在处理一个方案问题,其中我们正在使用方案列表表示一个图。我们使用的第一个变体是表示为 的边列表图 '((x y) (y z) (x z)) 我们正在使用的图的第二个变体被称为 x 图,表示为
我正在尝试创建一个函数,该函数将两个函数作为参数并执行它们。 我尝试使用 cond ,但它只执行 action1 . (define seq-action (lambda (action1 act
我提前为我的原始英语道歉;我会尽量避免语法错误等。 两周前,我决定更新我对 Scheme(及其启示)的知识,同时实现我在手上获得的一些数学 Material ,特别是我注册的自动机理论和计算类(cla
Scheme中有没有函数支持分数的“div”操作? 意思是 - 11 格 2.75 = 4。 最佳答案 我认为你的问题的答案是:没有,但你可以定义它: #lang racket (define (di
我在scheme中实现合并排序,我必须通过定义两个辅助方法来实现:merge和split。 Merge 需要两个列表(已经按递增顺序)并将它们合并在一起。我这样做了如下: (define merge
尝试从终端加载方案文件。我创建了一个名为 test.scm 的文件,其中包含以下代码: (define (square x) (* x x)) (define (sum-of-squares x y)
我有以下代码: (define (howMany list) (if (null? list) 0 (+ 1 (howMany (cdr list))))) 如果我们执行以
我有点了解如何将基本函数(例如算术)转换为Scheme中的连续传递样式。 但如果函数涉及递归怎么办?例如, (define funname (lambda (arg0 arg1)
我正在尝试附加两个字符串列表 但我不知道如何在两个单词之间添加空格。 (define (string-concat lst1 lst2) (map string-append lst1
这个问题已经有答案了: How do I pass a list as a list of arguments in racket? (2 个回答) 已关闭 8 年前。 我有一个函数,它需要无限数量的
我对这段代码的工作方式感到困惑: (define m (list 1 2 3 '(5 8))) (let ((l (cdr m))) (set! l '(28 88))) ==>(1 2 3 (5 8
我正在为学校做一项计划作业,有一个问题涉及我们定义记录“类型”(作为列表实现)(代表音乐记录)。 我遇到的问题是我被要求创建一个过程来创建这些记录的列表,然后创建一个将记录添加到该列表的函数。这很简单
我有以下代码: (define (howMany list) (if (null? list) 0 (+ 1 (howMany (cdr list))))) 如果我们执行以
我正在尝试附加两个字符串列表 但我不知道如何在两个单词之间添加空格。 (define (string-concat lst1 lst2) (map string-append lst1
如何使用抽象列表函数(foldr、foldl、map 和 filter 编写函数),无需递归,消耗数字列表 (list a1 a2 a3 ...) 并产生交替和 a1 - a2 + a3 ...? 最
我试图找出在 Scheme 中发生的一些有趣的事情: (define last-pair (lambda (x) (if (null? (cdr x))
这个问题在这里已经有了答案: Count occurrence of element in a list in Scheme? (4 个答案) 关闭 8 年前。 我想实现一个函数来计算列表中元素出现
我正在尝试使用下面的代码获取方案中的导数。谁能告诉我哪里出错了?我已经尝试了一段时间了。 (define d3 (λ (e) (cond ((number? e) 0) ((e
我是一名优秀的程序员,十分优秀!