Какой пример утиной печати на Java?

Недавно я слышал о том, как печатать утки, и я прочитал статью Википедии об этом, но мне сложно перевести примеры в Java, что действительно помогло бы мне понять.

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

Ответ 1

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

Ссылка

Ответ 2

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

Вкратце:

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

Ответ 3

проверить эту библиотеку:

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

Ответ 4

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

Ответ 5

С помощью java 8 у вас есть 2 способа:

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

Хорошее определение:

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

Ссылка

Ответ 9

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