【发布时间】:2010-11-07 23:08:31
【问题描述】:
我最近刚听说过鸭子打字,我阅读了Wikipedia article 关于它,但我很难将这些示例翻译成 Java,这对我的理解很有帮助。
谁能给出一个用 Java 进行鸭式输入的清晰示例以及我可能如何使用它?
【问题讨论】:
-
是的,但这里的其他人可能没有读过那篇文章。
标签: java duck-typing
我最近刚听说过鸭子打字,我阅读了Wikipedia article 关于它,但我很难将这些示例翻译成 Java,这对我的理解很有帮助。
谁能给出一个用 Java 进行鸭式输入的清晰示例以及我可能如何使用它?
【问题讨论】:
标签: java duck-typing
interface MyInterface {
void foo();
int bar(int x, int y);
int baz(int x);
}
public class Delegate {
public int bar() {
return 42;
}
}
DuckPrxy duckProxy = new DuckPrxyImpl();
MyInterface prxy = duckProxy.makeProxy(MyInterface.class, new Delegate());
prxy.bar(2, 3); // Will return 42.
使用Dynamic Proxy 的接口duck 输入很简单,您应该匹配方法名称和返回类型。
【讨论】:
Java 在设计上不适合鸭式打字。您可能选择这样做的方式是反射:
public void doSomething(Object obj) throws Exception {
obj.getClass().getMethod("getName", new Class<?>[] {}).invoke(obj);
}
但我会提倡使用动态语言(例如 Groovy),这样更有意义:
class Duck {
quack() { println "I am a Duck" }
}
class Frog {
quack() { println "I am a Frog" }
}
quackers = [ new Duck(), new Frog() ]
for (q in quackers) {
q.quack()
}
【讨论】:
Java 没有实现鸭子类型。
【讨论】:
Java 中的输入是名义上的——兼容性是基于名称的。如果您需要 Java 中鸭子类型(或结构类型)的示例,请查看此页面:http://whiteoak.sourceforge.net/#Examples,它提供了用 Whiteoak 编写的程序示例:一种也支持结构类型的 Java 兼容语言。
【讨论】:
通常,duck 类型与动态类型语言一起使用。您将在运行时检查是否存在满足您的需求所需的方法或属性,而不管继承层次结构如何。
除了使用会变得丑陋的反射之外,最接近的方法是使用符合鸭子类型所需条件的最小接口。这个blog post 很好地描述了这个概念。它失去了在 python、ruby 或 javascript 中输入鸭子的许多简单性,但如果您正在寻找高水平的可重用性,它实际上在 Java 中是非常好的实践。
【讨论】:
见this blog post。它非常详细地说明了如何使用动态代理在 Java 中实现鸭子类型。
总结:
【讨论】:
Proxy 实现的接口的列出顺序很重要:如果不正确,您将收到 java.lang.IllegalArgumentException: object is not an instance of declaring class。
使用 java 8,您有两种方法:
nº1:如果您只需要一种方法,请使用 lambdas
static interface Action { public int act(); }
public int forEachAct(List<Action> actionlist) {
int total = 0;
for (Action a : actionList)
total += a.act();
}
public void example() {
List<Action> actionList = new ArrayList<>();
String example = "example";
actionList.add(example::length);
forEachAct(actionList);
}
nº2:使用匿名类(在性能方面不是很明智,但在某些非关键部分可以做到)
static interface Action {
public int act();
public String describe();
}
public void example() {
List<Action> actionList = new ArrayList<>();
String example = "example";
actionList.add(new Action(){
public int act() { return example.length(); }
public String describe() { return "Action: " + example; }
});
}
【讨论】:
【讨论】:
我编写了一个实用程序类来为对象动态创建装饰器。您可以将其用于鸭子打字: https://gist.github.com/stijnvanbael/5965616
例子:
interface Quacking {
void quack();
}
class Duck {
public void quack() { System.out.println("Quack!"); }
}
class Frog {
public void quack() { System.out.println("Ribbip!"); }
}
Quacking duck = Extenter.extend(new Duck()).as(Quacking.class);
Quacking frog = Extenter.extend(new Frog()).as(Quacking.class);
duck.quack();
frog.quack();
输出:
Quack!
Ribbip!
【讨论】:
聚会迟到了(和往常一样),但我写了一个快速课程来自己做一些鸭子打字。见here。
它只会转到接口,但对于一个用法示例:
interface Bird {
void fly();
}
interface Duck extends Bird {
void quack();
}
class PseudoDuck {
void fly() {
System.out.println("Flying");
}
void quack() {
System.out.println("Quacking");
}
}
class Tester {
@Test
void testDuckTyping() {
final Duck duck
= DuckTyper.duckType(new PseudoDuck(), Duck.class);
}
}
支持默认接口方法,参数,检查异常类型是否兼容,会检查PseudoDuck类的所有方法(包括私有)。不过,尚未对通用接口进行任何测试。
【讨论】: