¿Qué es un ejemplo de pato escribiendo en Java?

Acabo de enterarme de escribir patos y leí el artículo de Wikipedia al respecto, pero me cuesta mucho traducir los ejemplos a Java, lo que realmente me ayudaría a comprenderlo.

¿Alguien podría dar un ejemplo claro de pato escribiendo en Java y cómo podría usarlo?

Por definición, Java no es apto para el tipado de patos. La forma en que puedes elegir hacerlo es reflexionar:

public void doSomething(Object obj) throws Exception { obj.getClass().getMethod("getName", new Class[] {}).invoke(obj); } 

Pero recomendaría hacerlo en un lenguaje dynamic, como Groovy, donde tiene más sentido:

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

Referencia

Vea esta publicación en el blog . Proporciona una descripción muy detallada de cómo usar los proxies dynamics para implementar el tipado de pato en Java.

En resumen:

  • crea una interfaz que represente los métodos que deseas usar mediante el tipado de patos
  • crear un proxy dynamic que use esta interfaz y un objeto de implementación que invoca métodos de la interfaz en el objeto subyacente por reflexión (suponiendo que las firmas coincidan)

revisa esta biblioteca :

 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. 

Con una interfaz, el tipado de pato es simple usando un Proxy dynamic , debe coincidir con el nombre del método y el tipo de retorno.

Java no implementa la tipificación de pato.

Con java 8, tienes 2 formas:

nº1: si solo necesitas un método, utiliza lambdas

 static interface Action { public int act(); } public int forEachAct(List actionlist) { int total = 0; for (Action a : actionList) total += a.act(); } public void example() { List actionList = new ArrayList<>(); String example = "example"; actionList.add(example::length); forEachAct(actionList); } 

nº2: utiliza clases anónimas (no muy en cuanto a rendimiento, pero en algunas partes no críticas se puede hacer)

 static interface Action { public int act(); public String describe(); } public void example() { List actionList = new ArrayList<>(); String example = "example"; actionList.add(new Action(){ public int act() { return example.length(); } public String describe() { return "Action: " + example; } }); } 

Escribir en Java es nominal: la compatibilidad se basa en nombres. Si necesita un ejemplo de cómo se puede ver el tipado de pato (o tipado estructural) en Java, mire esta página: http://whiteoak.sourceforge.net/#Ejemplos que proporciona ejemplos para el progtwig escrito en Whiteoak: A Java- lenguaje compatible que también es compatible con la tipificación estructural.

Por lo general, la tipificación de pato se usa con lenguajes tipados dinámicamente. Comprobaría en el tiempo de ejecución la existencia de métodos o propiedades necesarios para satisfacer sus necesidades, independientemente de las jerarquías de herencia.

Además de usar el reflection, que se pondría feo, lo más cercano que puede obtener es mediante el uso de interfaces mínimas que coincidan con los criterios de lo que necesitaría para el tipado de pato. Esta publicación de blog hace un buen trabajo describiendo el concepto. Pierde gran parte de la simplicidad del pato al escribir en python o ruby ​​o javascript, pero en realidad es una práctica bastante buena en Java si está buscando un alto nivel de reutilización.

Buena definición:

Los objetos son polimórficos sin estar relacionados por una clase base común o interfaz.

Referencia

Escribí una clase de utilidad para crear decoradores dinámicamente para un objeto. Podrías usarlo para tipar patos: https://gist.github.com/stijnvanbael/5965616

Ejemplo:

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

Salida:

 Quack! Ribbip! 

Tarde a la fiesta (como de costumbre), pero escribí una clase rápida para hacer algo de pato escribiendo yo mismo. Mira aquí .

Solo irá a las interfaces, pero para un ejemplo de uso:

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

Admite métodos de interfaz predeterminados, parámetros, comprobación Los tipos de excepción son compatibles y verificará todos los métodos de la clase del PseudoDuck (incluido el privado). Sin embargo, aún no hemos hecho ninguna prueba con interfaces genéricas.