我最近刚听说过鸭子类型,并且阅读了有关它的Wikipedia 文章,但是我很难将这些示例翻译成 Java,这确实有助于我的理解。
任何人都能够给出一个在 Java 中进行鸭式输入的清晰示例以及我可能如何使用它?
我最近刚听说过鸭子类型,并且阅读了有关它的Wikipedia 文章,但是我很难将这些示例翻译成 Java,这确实有助于我的理解。
任何人都能够给出一个在 Java 中进行鸭式输入的清晰示例以及我可能如何使用它?
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 中实现鸭子类型。
总之:
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.
使用动态代理的接口鸭子类型很简单,您应该匹配方法名称和返回类型。
Java 没有实现鸭子类型。
使用 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!
Java 中的输入是名义上的——兼容性是基于名称的。如果您需要 Java 中的鸭子类型(或结构类型)的示例,请查看此页面:http : //whiteoak.sourceforge.net/#Examples,它提供了用 Whiteoak 编写的程序示例:A Java-也支持结构类型的兼容语言。
通常,duck 类型与动态类型语言一起使用。您将在运行时检查是否存在满足您的需求所需的方法或属性,而不管继承层次结构如何。
除了使用会变得丑陋的反射之外,您可以获得的最接近的方法是使用符合鸭子类型所需标准的最小接口。这篇博文很好地描述了这个概念。它失去了在 python 或 ruby 或 javascript 中输入鸭子的大部分简单性,但如果您正在寻找高水平的可重用性,它实际上在 Java 中是非常好的实践。
聚会迟到了(像往常一样),但我写了一个快速课程来自己做一些鸭子打字。见这里。
它只会转到接口,但对于一个使用示例:
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类的所有方法(包括私有方法)。不过,尚未对通用接口进行任何测试。