Tengo un problema conceptual con una implementación adecuada del código que parece requerir una herencia múltiple, eso no sería un problema en muchos lenguajes OO, pero como el proyecto es para Android, no existe tal cosa como múltiples extends
.
Tengo un montón de actividades, derivadas de diferentes clases de base, tales como sencilla Activity
, TabActivity
, ListActivity
, ExpandableListActivity
, etc. También tengo algunos fragmentos de código que I necesidad de colocar en onStart
, onStop
, onSaveInstanceState
, onRestoreInstanceState
y otros controladores de eventos estándar en todas las actividades.
Si tengo una sola clase base para todas las actividades, colocaría el código en una clase derivada intermedia especial y luego crearía todas las actividades extendiéndola. Desafortunadamente, este no es el caso, porque hay múltiples clases base. Pero colocar las mismas porciones de código en varias clases intermedias no es un camino a seguir, en mi humilde opinión.
Otro enfoque podría ser crear un objeto auxiliar y delegar todas las llamadas de los eventos mencionados anteriormente al auxiliar. Pero esto requiere que se incluya el objeto auxiliar y que todos los controladores se redefinan en todas las clases intermedias. Entonces, no hay mucha diferencia con el primer enfoque aquí: todavía hay muchos duplicados de código.
Si ocurriera una situación similar en Windows, subclase la clase base (algo que "corresponde" a la Activity
clase en Android) y atrapa los mensajes apropiados allí (en un solo lugar).
¿Qué se puede hacer en Java / Android para esto? Sé que hay herramientas interesantes como la instrumentación de Java ( con algunos ejemplos reales ), pero no soy un gurú de Java, y no estoy seguro de si vale la pena intentarlo en este caso específico.
Si me perdí algunas otras soluciones decentes, por favor, menciónelas.
ACTUALIZAR:
Para aquellos que puedan estar interesados en resolver el mismo problema en Android, he encontrado una solución simple. Existe la clase de aplicación , que proporciona, entre otras cosas, la interfaz ActivityLifecycleCallbacks . Hace exactamente lo que necesito, permitiéndonos interceptar y agregar algo de valor en eventos importantes para todas las actividades. El único inconveniente de este método es que está disponible a partir del nivel 14 de API, que en muchos casos no es suficiente (la compatibilidad con el nivel 10 de API es un requisito típico hoy en día).
decordator pattern
. Este es un último recurso, que aunque en realidad demuestra lo que preferiría evitar: la duplicación de código. Aceptaré tu respuesta, si no hay otras ideas interesantes. ¿Puedo usar genéricos para generalizar el código de los "intermedios"?Creo que estás tratando de evitar el tipo incorrecto de duplicación de código. Creo que Michael Feathers escribió un artículo sobre esto, pero desafortunadamente no puedo encontrarlo. La forma en que lo describe es que puede pensar que su código tiene dos partes como una naranja: la corteza y la pulpa. La corteza es la materia como declaraciones de métodos, declaraciones de campo, declaraciones de clase, etc. La pulpa es la materia dentro de estos métodos; la implementación.
Cuando se trata de SECO, debes evitar duplicar la pulpa . Pero a menudo en el proceso creas más corteza. Y eso esta bien.
Aquí hay un ejemplo:
Esto se puede refactorizar en esto:
Agregamos mucha corteza en esta refactorización. Pero, el segundo ejemplo tiene mucho más limpio
method()
con menos violaciones DRY.Dijiste que te gustaría evitar el patrón decorador porque conduce a la duplicación de código. Si observa la imagen en ese enlace, verá que solo duplicará la
operation()
firma (es decir, cáscara). Laoperation()
implementación (pulpa) debe ser diferente para cada clase. Creo que su código terminará más limpio como resultado y tendrá menos duplicación de pulpa.fuente
Debes preferir la composición sobre la herencia. Un buen ejemplo es el " patrón " de IExtension en el marco .NET WCF. Básicamente tiene 3 interfaces, IExtension, IExtensibleObject e IExtensionCollection. Luego puede componer los diferentes comportamientos con un objeto IExtensibleObject agregando instancias IExtension a su propiedad Extension IExtensionCollection. En java debería verse algo así, sin embargo, no tiene que crear su propia implementación de IExtensioncollection que llama a los métodos adjuntar y desconectar cuando se agregan / eliminan elementos. También tenga en cuenta que depende de usted definir los puntos de extensión en su clase extensible. El ejemplo utiliza un mecanismo de devolución de llamada similar a un evento:
Este enfoque tiene el beneficio de la reutilización de extensiones si logra extraer puntos de extensión comunes entre sus clases.
fuente
processor.addHandler(console)
provisto queConsoleProcessor
implementaría la interfaz de devolución de llamada en sí. El patrón de "extensión" parece una combinación devisitor
ydecorator
, pero ¿es necesario en este caso?A partir de Android 3.0, puede ser posible resolver esto elegantemente usando un Fragmento . Los fragmentos tienen sus propias devoluciones de llamada del ciclo de vida y se pueden colocar dentro de una Actividad. Sin embargo, no estoy seguro de que esto funcione para todos los eventos.
Otra opción de la que tampoco estoy seguro (que carece de un profundo conocimiento de Android) podría ser usar un Decorador de la manera opuesta que k3b sugiere: crear uno
ActivityWrapper
cuyos métodos de devolución de llamada contengan su código común y luego reenviarlo a unActivity
objeto envuelto (su clases de implementación reales), y luego haga que Android inicie ese contenedor.fuente
Es cierto que Java no permite la herencia múltiple, pero puede simularlo más o menos haciendo que cada una de sus subclases SomeActivity extienda la clase de actividad original.
Tendrás algo como:
fuente