Imagine que tiene un módulo de software, que es un complemento de algún programa (similar a Eclipse) y desea que tenga una API que otros complementos puedan llamar. Su complemento no está disponible de forma gratuita, por lo que desea tener un módulo API separado, que está disponible gratuitamente y es lo único que otros complementos necesitan vincular directamente: los clientes API pueden compilar solo con el módulo API y no el módulo de implementación, en el camino de construcción. Si la API se ve obligada a evolucionar de manera compatible, los complementos del cliente podrían incluso incluir el módulo API en sus propios archivos jar (para evitar cualquier posibilidad de que se Error
produzca el acceso a clases inexistentes).
Las licencias no son la única razón para colocar la API y la implementación en módulos separados. Podría ser que el módulo de implementación sea complejo, con innumerables dependencias propias. Los complementos de Eclipse generalmente tienen paquetes internos y no internos, donde los paquetes no internos son similares a un módulo API (ambos están incluidos en el mismo módulo, pero podrían separarse).
He visto algunas alternativas diferentes para esto:
La API está en un paquete separado (o grupo de paquetes) de la implementación. Las clases API llaman directamente a las clases de implementación. La API no se puede compilar desde la fuente (lo cual es deseable en algunos casos poco comunes) sin la implementación. No es fácil predecir los efectos exactos de llamar a métodos API cuando la implementación no está instalada, por lo que los clientes generalmente evitarán hacerlo.
package com.pluginx.api; import com.pluginx.internal.FooFactory; public class PluginXAPI { public static Foo getFoo() { return FooFactory.getFoo(); } }
La API está en un paquete separado y utiliza la reflexión para acceder a las clases de implementación. La API se puede compilar sin la implementación. El uso de la reflexión puede causar un impacto en el rendimiento (pero los objetos de reflexión se pueden almacenar en caché si es un problema. Es fácil controlar lo que sucede si la implementación no está disponible.
package com.pluginx.api; public class PluginXAPI { public static Foo getFoo() { try { return (Foo)Class.forName("com.pluginx.internal.FooFactory").getMethod("getFoo").invoke(null); } catch(ReflectiveOperationException e) { return null; // or throw a RuntimeException, or add logging, or raise a fatal error in some global error handling system, etc } } }
La API consta solo de interfaces y clases abstractas, además de una forma de obtener una instancia de una clase.
package com.pluginx.api; public abstract class PluginXAPI { public abstract Foo getFoo(); private static PluginXAPI instance; public static PluginXAPI getInstance() {return instance;} public static void setInstance(PluginXAPI newInstance) { if(instance != null) throw new IllegalStateException("instance already set"); else instance = newInstance; } }
Lo mismo que arriba, pero el código del cliente necesita obtener la referencia inicial de otro lugar:
// API package com.pluginx.api; public interface PluginXAPI { Foo getFoo(); } // Implementation package com.pluginx.internal; public class PluginX extends Plugin implements PluginXAPI { @Override public Foo getFoo() { ... } } // Client code uses it like this PluginXAPI xapi = (PluginXAPI)PluginManager.getPlugin("com.pluginx"); Foo foo = xapi.getFoo();
No lo hagas Haga que los clientes se vinculen directamente al complemento (pero aún así evite que llamen a métodos que no sean API). Esto dificultaría que muchos otros complementos (y la mayoría de los complementos de código abierto) utilicen la API de este complemento sin escribir su propio contenedor.
¿Has echado un vistazo a los mecanismos de ServiceLoader en Java? Básicamente, puede especificar la implementación de una interfaz a través del archivo de manifiesto en un jar. Oracle también proporciona más información sobre complementos en programas Java.
fuente
Por lo que entiendo, la gente a menudo usa el patrón de fábrica para esto.
Pusieron las interfaces API en un módulo separado (digamos un archivo jar), y luego, cuando los clientes quieren usar la API y tienen acceso a una implementación de la API, la implementación de la API tendrá un punto de entrada de fábrica para que los clientes puedan usarla. comenzar a crear objetos concretos implementando esa API.
Esto significa que su primera idea de lo anterior es el parecido más cercano.
fuente