2009-07-03 2 views
28

Я только недавно слышал о том, как утка печаталась, и я читал об этом Wikipedia article, но мне сложно перевести примеры на Java, что действительно помогло бы мне понять.Какой пример печати уток в Java?

Может ли кто-нибудь дать ясный пример утиного набора текста на Java и как я могу его использовать?

+1

Да, но другие здесь не могли бы прочитать эту статью. –

ответ

38

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() 
} 

Reference

+2

++ Хороший пример утки, мне нравится новый метод создания объекта. – Secko

+3

Прошел через элегантную библиотеку под названием «duckapter», если вы идете по пути отражения Java: http://code.google.com/p/duckapter/ – penfold

+0

Я хочу знать, почему трудно или невозможно реализовать утиную печать java или любой статический тип языка? Люди говорят, используя интерфейс, который мы можем. Plz объясняет. – kamal

5

check this library:

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, вы должны совпадать с именем метода и тип возвращаемого значения.

+1

Следует отметить, что это не строго утиная печать, а использование динамических прокси (это то, что это делает), как можно ближе к Java. – cletus

4

Java не реализует утиную печать.

1

Ввод на Java является номинальным - совместимость основана на именах. Если вам нужны примеры того, как может выглядеть утиная (или структурная типизация) в Java, посмотрите эту страницу: http://whiteoak.sourceforge.net/#Examples, где представлены примеры для программы, написанной в Whiteoak: Java-совместимый язык, который также поддерживает структурную типизацию.

1

Как правило, утиная печать используется с динамически типизированными языками. Вы проверяете во время выполнения наличие методов или свойств, необходимых для удовлетворения ваших потребностей, независимо от иерархии наследования.

Помимо использования отражения, которое станет уродливым, ближайший вы можете получить, используя минимальные интерфейсы, которые соответствуют критериям того, что вам нужно для печати утки. Этот blog post хорошо описывает эту концепцию. Он теряет большую часть простоты утиного ввода в python или ruby ​​или javascript, но на самом деле это довольно хорошая практика на Java, если вы ищете высокий уровень повторного использования.

10

См. this blog post. Он дает очень подробный отчет о том, как использовать динамические прокси для реализации утиного ввода в Java.

В итоге:

  • создать интерфейс, который представляет методы, которые вы хотите использовать с помощью утки набрав
  • создать динамический прокси, который использует этот интерфейс и объект реализации, который вызывает методы интерфейса на основной задачей при отражении (предполагая сигнатурам)
+0

Это хорошая статья - как вы думаете, вы могли бы суммировать решение, данное здесь, на случай, если с ним что-нибудь случится? – Shog9

+1

Добавлено очень простое объяснение. –

+0

Утка, использующая * динамические прокси *, может быть реализована даже в меньшем количестве кода - см. [Этот текст] (https://gist.github.com/unix-junkie/b9481245904892f07780). Обратите внимание, что порядок, в котором интерфейсы, реализованные с помощью «Прокси», перечислены, имеет значение: если это неверно, вы получите объект java.lang.IllegalArgumentException: объект не является экземпляром объявления класса. – Bass

3

с Java 8, у вас есть 2 пути:

п º1: если вам нужен только один метод, используйте лямбды

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; } 
    }); 
} 
0

Nice определение:

Объекты полиморфны, не связанные общим базовым классом или интерфейсом.

Reference

0

Я написал класс утилита динамически создавать декоратор для объекта. Вы можете использовать его для утиной типизации: 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!