Upload
demian-gutierrez
View
242
Download
1
Embed Size (px)
Citation preview
1
FrameworksUn Ejemplo Ilustrado
(Arquitectura de Software para Practicantes)
Universidad de los AndesDemián GutierrezNoviembre 2012
2
EJEMPLO:¡Implementemos un
Solitario!
Ejemplo de Framework
3
Un solitario es un juegoen el que hay:
Ejemplo de FrameworkEntendiendo el Dominio
Cartas: Unidades básicas que se
mueven de un lado a otro, bien sea de
forma separada o en grupos
Bases: Lugares donde poner cartas, aplican reglas sobre
que cartas se pueden poner /
quitar
Pilas: Grupos de cartas, generalmente sobre una base (o en movimiento, a modo
de un grupo de cartas). Aplican
reglas sobre que cartas se pueden
quitar o añadir de/a una pila
4
El objetivo del juego es acomodar las cartas de cierta forma o
eliminar todas las cartas de las mesa, siguiendo una serie de
reglas predefinidas que dicen que cartas se pueden mover de una pila
a otra...
Ejemplo de FrameworkEntendiendo el Dominio
5
Prácticamente, se pueden definir un conjunto infinito de posibles reglas y
juegos distintos usando el mismo principio
Ejemplo de FrameworkEntendiendo el Dominio
Sólo acepta una “A” de cualquier color
NO
OK
6
Ejemplo de FrameworkEntendiendo el Dominio
Una pila que sólo acepta cartas con valor
descendiente y color alterno
NO
NO
SI
7
Ejemplo de FrameworkEntendiendo el Dominio
Una pila de la que sólo se puede sacar la carta del tope o
grupos de cartas que lleguen alternando su
color con valor descendente al tope
NO
SI
SI
8
Si vamos a programar un juego de solitario hay dos opciones:
1) Programar un sólo juego en especifico, con reglas especificas
2) Programar una serie de clases (framework) que permitan luego “configurar” las reglas
fácilmente para así poder crear cualquier solitario que se requiera
¿Qué opción seleccionaría?¿Por qué?
¿Programar un Solitario o un Framework?
9
Arquitectura de una Posible Implementación
MainFrame representan la IU del solitario Es la clase encargada
de cargar las cartas del disco, en cierto
sentido, representa el “mazo de cartas”
Utilitarios y clases base de Swing
Utilitarios en general
Objetos del Solitario, Cartas, Pilas, “Dibujables”, etc
Panel en el que se dibujan las cartas (o que “contiene”
el solitario)
El código de este ejemplo va adjunto a lastransparencias, son los proyectosCardGames01 y CardGames02
10
Arquitectura de una Posible Implementación
GamePanel se encarga de dibujar las pilas de cartas (que a
su vez dibujan las cartas individuales) así como de manejar los
eventos del ratón
Los eventos del ratón se manejan de forma genérica por parte de GamePanel, es decir, las reglas de que cartas se pueden quitar de una pila o poner en otra no están implementadas en
esta clase
Las reglas de las pilas están implementadas en
cada una de las pilas. Por ejemplo borrowCards es invocado para ver si es
posible quitar un grupo de cartas de una pila,
acceptCards es invocado para ver si es posible
poner un grupo de cartas en una pila particular. Toda la lógica y la verificación se implementa en estos dós métodos de las distintas
pilasVer diagramas de secuenciade las siguientes láminaspara entender el proceso completo de tomar de una pila y poner en otra
11
Arquitectura de una Posible Implementación
Lo que sucede cuando el usuario aprieta el ratón (sobre una pila)
Si el puntero no está sobre una pila
srcStack es nulo
Si no se permite (por reglas) mover las
cartas selecionadas, tmpStack es nulo
12
Arquitectura de una Posible Implementación
Lo que sucede cuando el usuario libera el ratón (sobre una pila)
Si el ratón no se libera sobre una pila tgtStack
será nulo
Si acceptCards retorna falso, quiere decir que la pila por sus “reglas” no aceptó las cartas, y
que deben ser devueltas a la pila de
origen
13
Arquitectura de una Posible Implementación
Es decir, desde el punto de vista de GamePanel, toda la lógica de “si es posible sacar una o más cartas de
una pila” o “si es posible poner una o más cartas en una pila” está implementada en la clase Stack,
específicamente en los métodosborrowCards y acceptCards (respectivamente)
¿Cómo podríamos tener pilas que tengan distintos comportamientos? por ejemplo, ¿Cómo podríamos
tener una pila que acepte sólo cartas del mismo color y otra que acepte cartas de colores alternados?
14
Arquitectura de una Posible Implementación
Que tal si se especializa Stack en distintos tipos de pilas, donde cada una de ellas sobrescribe (overrides) el método
acceptCards() y define reglas particulares para cada tipo de pila que se necesite
¿Desventajas? ¿Inconvenientes?¿Qué tipo de framework, caja negra o caja blanca?
Acepta cartas sólo del mismo color
Acepta cartas de colores intercalados
Acepta cartas sólo de valores descendentes
Acepta cartas sólo de valores ascendentes
15
Arquitectura de una Posible Implementación
El problema es que esta estrategia puede terminar en una situación poco deseable, en la que se produzca una
explosión de clases con funcionalidad redundante, tal como ocurre en el diagrama ...
... y eso que no se ha considerado aún la necesidad de especializar el comportamiento de borrowCards
Acepta cartas sólo de valores descendentes y del
mismo color
Acepta cartas sólo de valores ascendentes y del mismo color (¿¿¿Opps, no
esta esto repetido???)
Acepta cartas sólo de valores ascendentes y
decolores alternados, etc, etc, etc...
16
Arquitectura de una Posible Implementación
¿Alguna solución al problema de la explosión de clases?
17
Arquitectura de una Posible Implementación
En este caso, una pila está compuesta de una serie de “Estrategias” de “prestamo” (BorrowRule) y de “aceptación”
(AcceptRule) de cartas que se pueden combinar independientemente unas de otras
Define la interfaz de una “pequeña” clase
que establece un comportamiento de
“prestamo” de cartas
Define la interfaz de una “pequeña” clase
que establece un comportamiento de
“aceptación” de cartas
La clase pila está compuesta por una serie de reglas de “prestamo” y ”aceptación” de cartas
18
Arquitectura de una Posible Implementación
Cada una de las clases de este color
definen una regla para poder “prestar” una carta o un grupo de
cartas de la pila
Las clases verdes definen una regla de aceptación, por ejemplo DescendantAcceptRule que sólo acepta cartas con valores consecutivos descendientes, que se pueden encadenar con otras reglas,
como SameColorAcceptRule, para obtener una pila que solo acepta cartas descendientes consecutivas en valor del mismo color
El método addAcceptRule recibe una instancia de
una regla y la añade a la lista de reglas a verificar al momento de solicitarle a la pila que “acepte” una carta
o un grupo de cartas.El método acceptCards
funciona de la forma tradicional, sólo que ejecuta la cadena de
reglas añadidas y si todas pasan, entonces acepta la carta o el grupo de cartas
19
Arquitectura de una Posible Implementación
En general, esta es una estrategia completamente caja negra, porque no es necesario conocer como funciona una
clase particular del framework (Stack en este caso) para poder heredar y sobrescribir métodos, simplemente basta con
implementar una serie de interfaces y componer la pila de estas “reglas” que son las que hacen el trabajo
20
Arquitectura de una Posible Implementación
En este ejemplo (y en los que vimos de patrones de diseño) se ve la importancia de programar en función de interfaces
bien definidas, que pueden ser implementadas posteriormente a gusto de los programadores y según las
necesidades que se tengan
21
Gracias
¡Gracias!