OOP, Refactoring, y Android

Este articulo fue escrito con el fin de explicar la oop y varios conceptos relacionados con ella, como el polimorfismo, y la la asignacion de responsabilidades aplicando alta cohesion y bajo acoplamiento y el patron strategy. Para hacer este articulo me baso en el codigo que es explicado en otros dos articulos, los cuales les recomiendo que lean, para que puedan entender a la perfeccion lo que voy a explicar, las ligas son las siguientes:

El codigo es hecho para la plataforma Android, pero creo que a la mayoria le ayudara, ya que esta bien explicado.

Primero se analizara el codigo(recuerden que este codigo fue para enseñar algo en particular, asi que me imagino, omitieron muchas cosas) y se mencionaran los errores, posteriormente en el diseño se implementaran algunas buenas practicas, tratando de explicar el porque, entonces empezamos:

 

Analisis

En los siguientes metodos existe mucha dependencia, fallara el codigo si se cambia el orden del tipo de las figuras que se van agregando al array, no se pueden agregar mas figuras, ademas el color de la figura se maneja en el metodo onDraw, ¿Que pasara si quieres manejar 100 figuras con diferente color?.

 

Este codigo calcula sobre que figura el usuario oprime la patalla. Como se puede observar solo se esta considerando el manejo de dos tipos de figuras, sin embargo, si crece el numero de figuras, este algoritmo se hara mas dificil de manejar.
 

Este codigo cambia las coordenadas del centro de la figura seleccionada cuando el usuario mueve el dedo sobre la superficie de la pantalla del dispositivo, al igual que el codigo anterior con el tiempo no se podra dar mantenimiento, ademas de que esta muy enfocado a solo dos figuras.
 

Si se desea implementar cualquier otra funcionalidad en este codigo, sera una proeza hacerlo, por ejemplo, cuando se selecciona una figura, esta no se muestra encima de la otra, ¿cuanto trabajo sera necesario para implementar que la figura seleccionada se muestre sobre la otra?, ¿que coste tendra que la aplicacion pueda manejar un numero indeterminado de las figuras que ahorita tiene?, al menos, sera necesario agregarle varias sentencias de control, lo que lo hara mas...

Analisis

Asignacion de responsabilidades

Generalmente se piensa en el codigo como algo inanimado, es decir sin vida, bueno, asi lo pensamos muchos pero la OOP se creo con el fin de simular el comportamiento de las cosas del mundo real en la computadora. Consideremos los siguiente: al oir nuestro nombre generalmente volteamos, o cuando nos señalan, sabemos que refieren a nosotros, y sabemos que nos llamaron o señalaron y actuamos como resultado de esa accion, tambien tu sabes si estas de malas o buenas.

Si homologamos todo la anterior, ¿la figura tendria que saber que a ella la seleccionaron?, ¿la misma figura tendria que saber de que color es?, ¿la misma figura tendria la obligacion de pintarse?, ¿Que necesita saber la figura en este contexto de aplicacion para que sea funcional?.

La figura necesita saber: su color, las coordenadas del centro de la figura, si fue seleccionada, y como se va a pintar. Considerando que como se va a pintar es un metodo, entonces la clase inicial que va a representar la figura quedaria, en una forma inicial, asi:

 

Implementado diseño, polimorfismo y el patron strategy

Analicemos mas a fondo el metodo onDraw:
 

Se obtiene del array figuras cada una de las figuras, se obtiene de cada figura las coordenadas y se pinta la figura muy explicitamente. Imaginemos que vamos a utilizar muchos tipos de figuras y una gran cantidad de ellas, entonces lo que necesitariamos es que todas las clases que hereden de Shape tengan el mismo metodo, con los mismos parametros, con el fin de que con un solo bucle se puedan pintar solas.
Entonces el metodo quedaria asi en la clase Shape (se esta omitiendo lo innecesario para el ejemplo):
 

Y quedaria asi implementado en dos clases (recuerda que Shape tiene las coordenadas del centro de la figura):
 

El metodo onDraw se transformaria y quedaria asi:
 

Algunas observaciones:
El for va de mas a cero, con el fin de que se dibuje hasta el ultimo la figura seleccionada.

El bajo acoplamiento de Shape esta aumentado, ya que debe de manejar las clases Canvas, Paint.

Estamos usando el polimorfismo en toda la expresion de la palabra, ya que lo que contiene el array shapes son objetos de la clase Circle y Square.

Lo importante de el algoritmo mostrado abajo son los if que se escribieron despues del comentario, hacen el calculo para saber si el toque de la pantalla queda dentro del area de cada figura, en caso de que sea asi, figuraActiva obtiene el id de la figura, para hacer ese calculo es necesario obtener las coordenadas del toque y las coordenadas del centro de la figura.

 

Entonces si la figura tiene las coordenadas del centro, solo es necesario que sepa las coordenadas del toque:
 

Asi estaria implementadas en las clases que heredan de Shape:
 

Y asi se reduciria el codigo:
 
El segundo for es para pasar al inicio del array la primera figura que fue activada, con el fin de mostrarse hasta el ultimo en el metodo onDraw.

Continuamos con el siguiente codigo, a traves del cual se obtiene las coordenadas del centro de la figura, las cuales sirven para indicar en donde se pintara la figura mientras el usuario recorre la pantalla con el dedo, al analizar el algoritmo nos podemos dar cuenta que lo unico necesario es pasar las coordenadas en donde el dedo del usuario hace contacto con la pantalla:

 

Esta funcionalidad la vamos a implementar en las clases de la siguiente manera: en la clase Shape, el metodo quedara asi:
 

Ya implementado en Circle y Square:
 

Y el codigo dentro del case:
 

Asi se agregarian las figuras que se quieran mostrar dentro de la aplicacion:
 

Lo unico que se hizo fue asignar responsabilidades correctamente y la calidad de la aplicacion aumento considerablemente.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

Bien!

Creo hace falta más contenido relacionado con Android, buen aporte

Imagen de beto.bateria

Falta subir codigo.

Falta subir el codigo, en un rato lo subo.

Imagen de paranoid_android

Esta bueno el ejercicio. Comento solo por teorizar.

Hola.
Aclaro que tu refactoring está bastante bien. (Me quede por dudas por eso de que el código no esta completo)
Y solo por disfrutar del gusto, jajaja.
En estas líneas:
 
¿Vale la pena optimizar? Reducir la complejidad ciclomática.
Calcular estos valores al momento de crear el círculo o el cuadrado y/o si habría una manera visual más legible de expresarlo.
Saludos.

Imagen de beto.bateria

Ese codigo sirve para saber

Ese codigo que escribiste, sirve para saber si el toque del usuario es sobre el area de la figura, y solo se ejecuta cuando se toca la pantalla del dispositivo, no creo que se pueda optimizar. Respecto al codigo faltante, son los archivos del proyecto ya funcionando, para que puedan probarlo,

Imagen de paranoid_android

Ahora veo

Ok ahora entiendo.
Solo es sugerencia, lo único que se me ocurre...

 
Esta interesante tu post. Un saludo

Imagen de beto.bateria

Te voy a responder con un

Te voy a responder con un ejemplo:

Hace tiempo hice una aplicacion en donde la informacion del xml, y el ResultSet los pasaba a un DTO y despues esa informacion la convertia en otro formato. Tiempo despues deje de trabajar en esa empresa, y otro programador se dio cuenta que era algo lento ese procedimiento, lo que hizo el es quitar el DTO y, por ejemplo, pasar la informacion del ResulSet a XML directamente, la cuestion es ¿cual de los dos procedimientos esta mal? la respuesta: ninguno, todo depende de los requerimientos. El hecho de pasar todo a DTO hace mas flexible la aplicacion en cuanto a cambios, si haces la conversion directamente es mas rapido.

Debes de considerar: ¿cual es el costo de la mano de obra?, ¿cual es el costo de comprar hardware mas rapido?, ¿Vale la pena pasar todo a DTO y despues hacer otra conversion?, es lo mismo con tu ejemplo.

Una observacion: En este ejemplo en especial, estamos manejando graficos, por lo cual los algoritmos deberian ser lo mas rapido posible, es decir, hasta donde se pueda evitar la OOP y "optimizaciones"(como tu ejemplo) para el programador (aqui se debe de considerar que un buen programador escribe codigo entendible).

Imagen de paranoid_android

Es cierto.

Hola Beto. Es cierto a veces no se puede optimizar en todo se tiene que decidir optimizar en performance o en complejidad.
Esa optimización ya es un lujo normalmente no da tiempo para esas cosas.
Otro intermedio podría ser lo mismo pero con comentarios.
 
Solo la sugerí por compartir, disfrutar de la programación y del refactoring.
En el fondo ninguna de esas optimizaciones es necesaria, solo por el mero gusto de aportar.
En un programa que se hace por gusto y no por obligación da tiempo para esas cosas ;)

Saludos.

Imagen de beto.bateria

Los leere...

Los leere...