Cómo implementar solo una parte de una interfaz

14

Al desarrollar en OOP, a veces una biblioteca / interfaz proporciona una interfaz / contrato que no puede modificar. Llamemos a esta interfaz J.

Ahora tiene un objeto de clase A que consume objetos que implementan esta interfaz. Dentro de A solo se necesita una pequeña parte de las definiciones de la interfaz. Creé algunas de las clases de objetos durante el proyecto (llamemos a una de ellas tipo D), por lo que hay una sobrecarga en la implementación de todo dentro de la interfaz J.

Quiero implementar un subconjunto de la funcionalidad en la interfaz J, pero mis soluciones hasta ahora no me satisfacen:

  • implementar todos los aspectos de J y luego arrojar "notImplementedExceptions" desinforma al usuario de mis objetos: parecería que mis objetos de tipo D se ajustan a la interfaz J, pero no lo hacen, y otros consumidores de mis objetos (que aceptan objetos que implementan la interfaz J) no puedo confiar en la integridad de mis objetos.
  • Implementar una interfaz recién definida me prohíbe usar objetos que implementen solo la interfaz J, aunque la interfaz J es totalmente compatible con mi propia interfaz.
  • Dejar que mis objetos personalizados implementen la interfaz J crearía una sobrecarga significativa, porque no necesitan toda esta funcionalidad.

Cuando podía alterar la interfaz J, creaba una "superinterfaz" K que tenía este subconjunto de la funcionalidad de la interfaz J, y hacía que la interfaz J heredara de la interfaz K. Pero no puedo alterar la interfaz J.

¿Cuál es una solución orientada a objetos para este problema? ¿La mejor solución sigue implementando la interfaz "justa" J? ¿O hay formas OOP de "superclasificar" una interfaz sin alterarla?

vstrien
fuente
1
Vea cómo las clases * Adapter en Swing hacen esto.

Respuestas:

9

si no controlas la interfaz J, estás atascado.

puede, para mayor claridad, implementar su propia interfaz subJ e interfaz J, y usar subJ en su propio código para dejar en claro que los métodos adicionales en la interfaz J no son necesarios, pero no creo que eso realmente le gane mucho

si es posible, implemente toda la interfaz J completamente

si es posible, comuníquese con el propietario de la interfaz J y pídale que la modifique para adaptarla mejor a sus propósitos.

Steven A. Lowe
fuente
2
Como compromiso: puede pedirle al propietario de la interfaz J que herede de su interfaz más pequeña SubJ.
k3b
27

El objetivo de implementar una interfaz es proporcionar un contrato firme entre la persona que llama y la persona que llama que nunca cambia mientras que los detalles de implementación pueden variar.

Al implementar la interfaz J, le está diciendo al mundo exterior lo que puede hacer.

Si no necesita la mitad de lo que hace J, entonces la interfaz realmente debería subdividirse, ya que no es tan pequeña como podría ser, o debe agregar NotImplementedExceptionlos métodos y propiedades que no necesita. Sin embargo, esta no es la mejor solución, ya que confunde las expectativas de las personas sobre lo que puede hacer su código.

ChrisF
fuente
5

Si su clase de consumidor A no requiere toda la interfaz J, entonces sugeriría crear una nueva interfaz (llamada K), que describa exhaustivamente todo lo que sí requiere.

Esto proporciona una señal clara a cualquiera que use la clase A en cuanto a cuál es su lado del contrato. De este modo, se mejoran las posibilidades de reutilización. Si alguien necesita proporcionar un objeto que implemente una interfaz grande y compleja, para hacer algo relativamente simple, es probable que termine escribiendo lo que la clase A hace por sí mismo.

Para permitir que la clase A consuma objetos que implementan la interfaz J solo, puede proporcionar una clase de contenedor que implemente la interfaz K y transfiera las llamadas apropiadas a un miembro de la interfaz J.

Carnicero paul
fuente
3

Si bien estoy de acuerdo con las respuestas existentes que dicen que realmente necesita implementar J completamente (con excepciones para los métodos no implementados) o no aplicarlo, una posible solución es la siguiente:

  • Cree una interfaz K más pequeña que sea un subconjunto de J e implemente los métodos requeridos.
  • Cree un contenedor para A que acepte objetos que implementan J y K.
  • En el caso de un pase en J, simplemente empuje hacia la instancia de A.
  • En el caso de una K aprobada, instancia una implementación anónima de J, conectando solo los métodos de K a J que están allí. Pase el resultado a la instancia de A.

Tenga en cuenta que esta es una solución bastante fea, ya que requiere un contenedor que acepta varias cosas que son esencialmente lo mismo. Pero logra lo siguiente:

  • No hay cambios en J o A.
  • No hay implementaciones "expuestas" de J que estén incompletas.

Si su lenguaje OO no permite la creación de instancias de interfaz anónima, puede crear una implementación ficticia de la interfaz e instanciar eso.

Deckard
fuente
1

¿Cuánto tiempo le llevaría implementar toda la interfaz?

Si le tomara una cantidad considerable de tiempo, esto indica un problema de diseño, y le aconsejaría (como lo hizo Steven A. antes que yo) que se comunique con el propietario y vea si se puede cambiar en el futuro.

¿Utiliza la interfaz en su propio código, independiente de la biblioteca de la interfaz?

Como Steven A. sugirió, puede usar su propia interfaz como le gustaría verla en su propio código. Esto al menos mantiene limpio su código interno. También puede enviar esto al propietario como la interfaz que esperaría encontrar. Tal vez él esté de acuerdo con usted, o tal vez pueda explicarle por qué la interfaz no debe dividirse.

¿Alguna vez su implementación necesitaría los miembros no utilizados de la interfaz?

En caso de que pueda esperar que nunca se les llame ya que 'no son compatibles', prefiero usar el NotSupportedException. Esto proporciona una indicación clara de que nunca admitirá esta interfaz, en lugar de que no la haya implementado.

Steven Jeuris
fuente
Una buena idea al usarlo NotSupportedExceptiondeja en claro que no es compatible con ese método.
ChrisF
@ChrisF: Solo lo uso NotImplementedExceptionpara el código de producción, donde de lo contrario escribiría "TODO: Implemente esto" Lamentablemente, no aparecen en la lista de tareas de Visual Studio . Pero en la práctica, apenas dejo un método sin implementar por más de dos días. Resharper también muestra esas excepciones en negrita (al menos con mi configuración). :)
Steven Jeuris 01 de
0

Implemente lo que necesita y arroje una excepción NoImplementedException en los demás.

Esto es una cuestión de uso. Si no usa la interfaz, o sabe que su código no usará la interfaz, no invierta tiempo en esto, ya que no necesita invertir tiempo en código redundante.

Trabaje para la tarea en cuestión y mantenga un buen rastro para que otros lo sigan si desean usar la interfaz.

Muchas interfaces en Java no están implementadas al máximo.

Este es el enfoque de Apache para las cosas: http://commons.apache.org/lang/api-2.4/org/apache/commons/lang/NotImplementedException.html

Nombre para mostrar
fuente
Quizás discuta por qué cree que esta es una solución adecuada. Esto no agrega nada a la pregunta.
Steven Jeuris 01 de
no hay necesidad de implementar todo, ya que no hay una necesidad real de explicarlo todo. si ese fuera su caso, partes de la interfaz eran redundantes, la recogería de inmediato.
Nombre para mostrar el