2 Patrones GRASP

80
Ingeniería del Software 1 Curso 2010-2011 Diseño de responsabilidades con patrones (GRASP) ATENCIÓN ESTE DOCUMENTO ES UN MATERIAL DE APOYO PARA LAS CLASES DE TEORÍA, NO ESTÁ DISEÑADO COMO MATERIAL DE ESTUDIO. SI QUIERES USARLO PARA ESTUDIAR DEBES COMPLEMENTARLO CON LAS EXPLICACIONES DEL PROFESOR Y/O LA BIBLIOGRAFÍA RECOMENDADA

Transcript of 2 Patrones GRASP

Page 1: 2 Patrones GRASP

Ingeniería del Software 1Curso 2010-2011

Diseño de responsabilidades

con patrones (GRASP)

ATENCIÓN

ESTE DOCUMENTO ES UN MATERIAL DE APOYO PARA LAS

CLASES DE TEORÍA, NO ESTÁ DISEÑADO COMO MATERIAL DE

ESTUDIO. SI QUIERES USARLO PARA ESTUDIAR DEBES

COMPLEMENTARLO CON LAS EXPLICACIONES DEL PROFESOR

Y/O LA BIBLIOGRAFÍA RECOMENDADA

Page 2: 2 Patrones GRASP

Índice

Introducción

Patrones GRASP Básicos

Creador

Experto (en Información)

Bajo Acoplamiento

Controlador

Alta Cohesión

Patrones GRASP Avanzados

Polimorfismo

Fabricación Pura

Indirección

Protección de Variaciones

Page 3: 2 Patrones GRASP

Objetivos del tema

Comprender el uso del diagrama de clases para reflejar

conceptos a distintos niveles de abstracción

Ser capaz de realizar un diseño software que sea

respetuoso con los principios de asignación de

responsabilidades de GRASP

Page 4: 2 Patrones GRASP

Introducción

Perspectiva de análisis vs. perspectiva de diseño en

diagramas de clase UML

Page 5: 2 Patrones GRASP

Introducción: Usos del diagrama de clases

UML incluye los diagramas de clases para ilustrar clases, interfaces

y sus asociaciones.

Éstos se utilizan para el modelado estático de objetos.

Los diagramas de clases se pueden usar tanto desde una

perspectiva conceptual (para el modelo del dominio) como desde una

perspectiva software (para el modelado de la CAPA DE DOMINIO).

Es común hablar de “Diagrama de clases de Análisis” para referirse al diagrama

de clases que representa el modelo de dominio, y a “Diagrama de Clases de

Diseño” para hablar del diagrama de clases que representa a las clases software,

es decir, a las clases que finalmente van a ser implementadas.

EN LA ASIGNATURA NOS VAMOS A CENTRAR EN EL MODO DE DEFINIR LOS

MODELOS DE DISEÑO Y, DENTRO DE ELLOS, EL DIAGRAMA DE CLASES DE

DISEÑO

Page 6: 2 Patrones GRASP

Introducción: Diseño de objetos

El diseño de objetos se describe como:

Tras haber identificado tus requisitos, y haber creado un modelo de dominio,

añade operaciones a las clases y define las secuencias de mensajes entre

objetos para cubrir los requisitos

Estas recomendaciones no son especialmente útiles, ya que hay

principios fundamentales de diseño, nada triviales, que deben ser

tenidos en cuenta a la hora de:

Decidir qué operaciones hay que asignar a qué clases

Cómo los objetos deberían interactuar para dar respuesta a los casos de uso

De hecho, el artefacto más importante del flujo de trabajo de diseño

es el Modelo de Diseño, que incluye el diagrama de clases

software (no conceptuales) y diagramas de interacción.

Page 7: 2 Patrones GRASP

Introducción: Diseño de objetos

Register

...

endSale()

enterItem(...)

makePayment(...)

Sale

time

isComplete : Boolean

/total

makeLineItem(...)

Register

...

Sale

time

isComplete : Boolean

/total

Captures

1

11

Domain Model

conceptual

perspective

Design Model

DCD; software

perspectivecurrentSale

Meta: Low Representational Gap

Page 8: 2 Patrones GRASP

Introducción: Diseño de objetos

the association name, common when drawing a

domain model, is often excluded (though still legal)

when using class diagrams for a software

perspective in a DCD

Register

id: Int

...

Sale

time: DateTime

...

1

currentSale

Register

id : Int

Sale

time : DateTime

Captures-current-sale1 1UP Domain Model

conceptual perspective

UP Design Model

DCD

software perspective

Page 9: 2 Patrones GRASP

Introducción: Del DC de Análisis al DC de Diseño

GENERALIZACIÓN VS HERENCIA

En el modelo de dominio implica que la superclase es un

superconjunto y la subclase un subconjunto.

En un DCD implica la relación de herencia de los lenguajes de

programación OO de una superclase a una subclase.

¡ATENCIÓN! Las relaciones de generalización no tienen

por qué traducirse en relaciones de herencia en el DCD.

P.ej. en C++ el uso de templates puede a veces reducir el número

de clases (alternativa a la herencia).

Page 10: 2 Patrones GRASP

Introducción: Del DC de Análisis al DC de Diseño

DCD: APARICIÓN DE NUEVAS CLASES (1/2)

Clases de Utilidad: clases que encapsulan algoritmos genéricos

que pueden ser accedidos por más de una clase

Como veremos más adelante, añadir esos algoritmos a clases

existentes disminuiría la cohesión de esas clases

Las clases de utilidad también se pueden utilizar para encapsular

clases de librería o aplicaciones/funciones que no son OO

(proporcionan una interfaz OO a dichos módulos)

Librerías: referencias a librerías proporcionadas por el entorno

(p.ej. STL)

Page 11: 2 Patrones GRASP

Introducción: Del DC de Análisis al DC de Diseño

DCD: APARICIÓN DE NUEVAS CLASES (2/2)

Interfaces: abstracción de comportamiento mediante interfaces

que realizan las clases

Clases de ayuda: clases que asisten a una clase existente para la

realización de una tarea, al mismo tiempo que permiten aumentar

la cohesión de la clase origen.

Ejemplo: ManageEmployeeForm: clase que gestiona cosas como

formateo de números de identidad. ¿Pero quién gestiona el control de

que el número de la Seguridad Social es un número válido de la

empresa?

Page 12: 2 Patrones GRASP

Introducción: Responsabilidades

UML define una responsabilidad como “un contrato u

obligación de un clasificador”.

Obligaciones de un objeto en términos de su comportamiento.

Las responsabilidades se asignan a clases software durante el

diseño de objetos

Page 13: 2 Patrones GRASP

Introducción: Tipos de responsabilidades

Hacer:

Hacer algo él mismo (e.g. crear un objeto, realizar un cálculo)

Iniciar la acción en otros objetos.

Controlar y coordinar actividades en otros objetos.

Ejemplo: Un tablero es responsable de crear sus casillas”

Saber o Conocer:

Conocer sus datos privados (encapsulados).

Conocer los objetos con los que se relaciona.

Conocer las cosas que puede derivar o calcular.

Ejemplo: “Un barco es responsable de conocer cuándo está hundido”

Las responsabilidades relacionadas con „conocer‟ son normalmente

inferibles del Modelo de Dominio (debido a los atributos y

asociaciones que éste ilustra)

Page 14: 2 Patrones GRASP

Introducción: Responsabilidades vs. métodos

La complejidad del proceso de traducción de

responsabilidades a clases y operaciones (implementadas

mediante métodos) está influenciada por la granularidad de la

responsabilidad.

Ejemplo: la responsabilidad “proporciona acceso a BD relacional”

puede involucrar docenas de clases y cientos de métodos, mientras

que “crear Venta” podría involucrar sólo uno o un pequeño número de

métodos.

Una responsabilidad no es un método, pero los métodos se

implementan para cubrir responsabilidades.

Los métodos pueden colaborar con otros métodos y objetos

para cubrir una determinada responsabilidad.

Page 15: 2 Patrones GRASP

Introducción: Responsabilidades y D. Interacción

Podemos pensar sobre cómo

asignar responsabilidades

cuando modelamos o cuando

codificamos

Dentro de los artefactos UML,

un contexto común donde estas

responsabilidades

(implementadas como

métodos) se consideran es

durante la creación de

diagramas de interacción.

:Pieza

:Casilla

getCasilla(…)

get(…)

Las piezas tienen la

responsabilidad de saber en

qué casilla están colocadas, y

la manejan con el método

getCasilla().

El cumplimiento de esta

responsabilidad requiere llamar

al método get del atributo

Casilla

Page 16: 2 Patrones GRASP

Patrones GRASP

Page 17: 2 Patrones GRASP

BÁSICOS AVANZADOS

Creador

Experto (en Información)

Bajo Acoplamiento

Controlador

Alta Cohesión

Polimorfismo

Fabricación Pura

Indirección

Protección de Variaciones

GRASP: Introducción

GRASP es un acrónimo para General Responsibility Assignment

Software Patterns.

Describen 9 principios fundamentales del diseño de objetos y de

la asignación de responsabilidades, expresado en términos de

patrones.

Se dividen en dos grupos:

Page 18: 2 Patrones GRASP

GRASP: Introducción

Para ilustrar los patrones vamos a suponer que queremos modelar un

monopoly

Dibujad su modelo de dominio (perspectiva conceptual)

Nota: asume dos dados

Nota: comienza modelando el tablero, las casillas, y el acto de hacer una

tirada y mover las piezas por parte de un jugador

Page 19: 2 Patrones GRASP

Patrones GRASP básicos

Creador

Experto (en información)

Bajo acoplamiento

Controlador

Alta cohesión

Page 20: 2 Patrones GRASP

GRASP: Creador

En el Monopoly, ¿quién debería ser el responsable de

crear Casillas?

Page 21: 2 Patrones GRASP

GRASP: Creador

Problema: ¿Quién debería ser el responsable de crear

una nueva instancia de alguna clase?

Solución: Asigna a la clase B la responsabilidad de crear

una instancia de la clase A si una o más de las siguientes

afirmaciones es cierta:

1) B agrega objetos de tipo A.

2) B contiene objetos de tipo A.

3) B graba objetos de tipo A.

4) B tiene datos inicializadores que serán pasados a A cuando sea

necesario crear un objeto de tipo A (por tanto B es un Experto

con respecto a la creación de A).

Page 22: 2 Patrones GRASP

GRASP: Creador

Discusión

“Creator” busca el objeto creador que requiere estar conectado

al objeto creado en cualquier evento.

Esto soporta “bajo acoplamiento”.

Es común que el “Creator” se encuentre buscando la clase que

tiene los datos de inicialización que serán pasados como

parámetro al objeto creado. Tablero tiene los datos de posición

para el objeto Casilla.

Contraindicaciones

La creación podría ser compleja (por ejemplo “creación

condicional”, “reciclamiento de instancias”, o que la creación de

una instancia sea a partir de una familia de clases similares

basadas en una propiedad externa). En este caso use el patrón

“Factory” (GoF).

Beneficios

Favorece el “bajo acoplamiento”, implicando con ello un nivel

bajo de dependencias de mantenimiento y alta oportunidad de

reuso.

Page 23: 2 Patrones GRASP

GRASP: Experto (en información)

En el Monopoly, imaginad que necesitamos ser capaces de

referenciar una casilla particular, dado su nombre (la calle que

representa). ¿A quién le asignamos la responsabilidad?

Page 24: 2 Patrones GRASP

GRASP: Experto (en información)

Problema: ¿cuál es el principio general de asignación de

responsabilidades a objetos?

Solución: Asigna cada responsabilidad al experto de

información, i.e. la clase que tiene (la mayor parte de) la

información necesaria para cubrir la responsabilidad.

Page 25: 2 Patrones GRASP

GRASP: Experto (en información)

¡ATENCIÓN!

A veces hay que aplicar el

Information Expert en cascada.

Ejemplo: Casa de apuestas

Suponed que queremos asignar

la responsabilidad de calcular la

ganancia/pérdida neta de un

usuario en el siguiente diagrama.

Dibujad el diagrama de

secuencia e indicad los cambios

en el diagrama de clases.

Page 26: 2 Patrones GRASP

GRASP: Experto (en información)

Discusión

Los objetos hacen tareas relacionadas con la información que

poseen.

Principio de “animación”. (caricatura animada).

Tal como en el mundo real: “damos responsabilidades a quien

tiene la información”.

Contraindicaciones

Problemas de cohesion y acoplamiento: ¿Quién debería salvar

en la db las apuestas? No debería ser la clase Apuesta

(incohesivo).

Beneficios

Mantiene encapsulamiento de información (bajo acoplamiento)

Motiva clases “ligeras” distribuyendo responsabilidades.

Page 27: 2 Patrones GRASP

GRASP: Bajo acoplamiento

Asume que necesitamos modelar el acto de tirar los dos dados de un

jugador en el monopoly. ¿A quién asignamos la responsabilidad?

Page 28: 2 Patrones GRASP

GRASP: Bajo acoplamiento

Si el jugador tira los

dados, es necesario

acoplar al Jugador con

conocimiento sobre los

Dados (acoplamiento

que antes no existía)

:Monopoly

makePayment()

: Jugador

d:Dados

1: create()

2:create()

Jugador also coupled to

knowledge of Dados.

3: tiraDados()

4: mueve()

Page 29: 2 Patrones GRASP

GRASP: Bajo acoplamiento

Una solución alternativa

es que sea el propio

Juego el que tire los

dados y envíe el valor

que ha salido al

Jugador.

Se disminuye el

acoplamiento entre

Jugador y Dados y,

desde el punto de vista

del “acoplamiento” es un

mejor diseño.

:Monopoly

makePayment()

: Jugador

d:Dados

1: create()

2:create()

3: r=tiraDados()

4: mueve(r)

Page 30: 2 Patrones GRASP

GRASP: Bajo acoplamiento

Problema: ¿Cómo soportar una baja dependencia, un

bajo impacto de cambios en el sistema y un mayor reuso?

Solución: Asigna una responsabilidad de manera que el

acoplamiento permanezca bajo

Page 31: 2 Patrones GRASP

GRASP: Bajo acoplamiento

Acoplamiento: medida que indica cómo de fuertemente un

elemento está conectado a, tiene conocimiento de, o depende

de otros elementos.

Una clase con un alto acoplamiento depende de muchas otras clases

(librerías, herramientas, etc.)

Problemas del alto acoplamiento:

Cambios en clases relacionadas fuerzan cambios en la clase afectada

por el alto acoplamiento.

La clase afectada por el alto acoplamiento es más difícil de entender

por sí sola: necesita entender otras clases.

La clase afectada por el alto acoplamiento es más difícil de reutilizar,

porque requiere la presencia adicional de las clases de las que

depende.

Page 32: 2 Patrones GRASP

GRASP: Bajo acoplamiento

En general, valora siempre la necesidad de incluir una

nueva relación de dominio en el D. Clases

Page 33: 2 Patrones GRASP

GRASP: Bajo acoplamiento

¿Cómo podríamos desacoplarnos del hecho de que el

monopoly está usando dos dados?

Page 34: 2 Patrones GRASP

GRASP: Bajo acoplamiento

Tipos de acoplamiento

El acoplamiento dentro de los D. Clases puede ocurrir por

varios motivos:

Definición de Atributos: X tiene un atributo que se refiere a una

instancia Y.

Definición de Interfaces de Métodos: p.ej. un parámetro o una

variable local de tipo Y se encuentra en un método de X.

Definición de Subclases: X es una subclase de Y.

Definición de Tipos: X implementa la interfaz Y.

¿CUÁL ES MEJOR?

Page 35: 2 Patrones GRASP

GRASP: Bajo acoplamiento

Discusión

No hay una medida específica para el acoplamiento, pero en

general, clases que son genéricas y candidatas al reuso

DEBERÍAN asegurar un bajo acoplamiento

Siempre habrá algo de acoplamiento entre objetos, ya que de

otro modo no habría colaboración

Contraindicaciones

Rara vez es un problema tener alto acoplamiento con elementos

estables y con elementos “pervasive” (de uso amplio).

Ej.- Una aplicación J2EE puede acoplarse de forma segura con

las bibliotecas propias de Java (java.util, etc.), ya que ellas son

estables y de uso amplio.

No vale la pena “desgastarse” en disminuir acoplamiento

cuando no exista real motivación.

Beneficios

No existen “efectos colaterales” debido a cambios en otros

componentes.

Simple de entender aisladamente.

MUY conveniente para el reuso.

La mayoría de los patrones favorecen EL BAJO

ACOPLAMIENTO!! E.g experto, creador, …

Page 36: 2 Patrones GRASP

GRASP: Controlador

En el Monopoly puede haber

múltiples operaciones del

sistema, que en un principio se

podrían asignar a una clase

System.

Sin embargo esto no significa

que finalmente deba existir una

clase software System que

satisfaga este requisito; es

mejor asignar las

responsabilidades a uno o más

Controllers.

System

initialize(nop)

playGame(). . .

Page 37: 2 Patrones GRASP

GRASP: Controlador

¿En el monopoly, quién debería ser el Controlador para

los eventos de sistema, tales como playGame e initialize?

Page 38: 2 Patrones GRASP

GRASP: Controlador

Existen dos posibilidades:

MonopolyGame

ProcessInitializeHandler (esta solución requiere que haya otros

controladores como ProcessPlayGameHandler, etc.).

:MonopolyGameplayGame()

:ProcessPlayGameHandlerplayGame()

Page 39: 2 Patrones GRASP

GRASP: Controlador

Page 40: 2 Patrones GRASP

GRASP: Controlador

Problema: ¿Quién debería ser el responsable de manejar un

evento de entrada al sistema?

¿Quién es el primer objeto de la capa de dominio que recibe los

mensajes de la interfaz?

Solución: Asigna la responsabilidad de recibir o manejar un

evento del sistema a una clase que represente una de estas

dos opciones:

El sistema completo (Control „fachada‟).

Un escenario de un Caso de Uso.

Estandariza nomenclatura: ControladorRealizarCompra,

CoordinadorRealizarCompra, SesionRealizarCompra,

ControladorSesionRealizarCompra.

Page 41: 2 Patrones GRASP

GRASP: Controlador

El Controlador del

que habla este

patrón es un objeto

que NO pertenece a

la capa de interfaz y

que define el método

para la operación del

sistema.

Normalmente

ventanas, applets etc

reciben eventos

mediante sus propios

controladores de

interfaz, y los

DELEGAN al tipo de

controlador del que

hablamos aquí.

Register

...

endSale()

enterItem()

makeNewSale()

makePayment()

makeNewReturn()

enterReturnItem()

. . .

System

endSale()

enterItem()

makeNewSale()

makePayment()

makeNewReturn()

enterReturnItem()

. . .

system operations

discovered during system

behavior analysis

allocation of system

operations during design,

using one facade controller

ProcessSale

Handler

...

endSale()

enterItem()

makeNewSale()

makePayment()

System

endSale()

enterItem()

makeNewSale()

makePayment()

enterReturnItem()

makeNewReturn()

. . .

allocation of system

operations during design,

using several use case

controllers

HandleReturns

Handler

...

enterReturnItem()

makeNewReturn()

. . .

Page 42: 2 Patrones GRASP

GRASP: Controlador

Mal diseño

Player

:MonopolyJFrame

actionPerformed( actionEvent )

:Board1: playGame()

Interface Layer

Domain Layer

It is undesirable for an interface

layer object such as a window to get

involved in deciding how to handle

domain processes.

Business logic is embedded in the

presentation layer, which is not useful.

MonopolyJFrame should not

send this message.

presses button

Page 43: 2 Patrones GRASP

GRASP: Controlador

Buen diseño

actionPerformed( actionEvent )

:Monopoly

: Jugador

:MonopolyJFrame

presses button

1: playGame()

:Board1.1: playGame()

Interface Layer

Domain Layer

system event message

controller

Es el run()

de las

prácticas

de POO

Page 44: 2 Patrones GRASP

GRASP: Controlador

El Controlador recibe las solicitudes de servicios desde la

capa UI y coordina su realización, generalmente

delegando a otros objetos.

Los Controladores permiten también implementar la

“secuencia de operaciones” o mantener el “estado del

caso de uso”.

P.ej.- initialize( ) no se puede realizar a menos que el juego acabe

de empezar.

¿Cuándo pensáis que es mejor utilizar cada tipo de

Controlador? (controlador único o para cada caso de uso)

Page 45: 2 Patrones GRASP

Monopoly::PlayGame(){

turno=random(numJug);

Dados d[2]=cub.getDados();

int punt=0;

for (i=1 to 2)

punt+=dado[i].tirarDado();

Casilla cAct=jug[turno].getCasillaAct();

Casilla cNueva=cAct+punt;

jug[t].colocaEnCasilla(cNueva)

turno=turno+1 mod numJug;

}

GRASP: Alta cohesión

¿Cómo reescribiríais el siguiente código del monopoly?

Page 46: 2 Patrones GRASP

GRASP: Alta cohesión

Page 47: 2 Patrones GRASP

GRASP: Alta cohesión

Cohesión: medida de cómo de fuertemente se relacionan

y focalizan las responsabilidades de un elemento. Los

elementos pueden ser clases, subsistemas, etc.

Una clase con baja cohesión hace muchas actividades

poco relacionadas o realiza demasiado trabajo.

Problemas causados por un diseño con baja cohesión:

Difíciles de entender.

Difíciles de usar.

Difíciles de mantener.

Delicados: fácilmente afectables por el cambio.

Page 48: 2 Patrones GRASP

GRASP: Alta cohesión

Problema: ¿Cómo mantener la complejidad manejable?

Solución: Asigna las responsabilidades de manera que la

cohesión permanezca alta.

Clases con baja cohesión a menudo representan abstracciones

demasiado elevadas, o han asumido responsabilidades que

deberían haber sido asignadas a otros objetos.

Page 49: 2 Patrones GRASP

GRASP: Alta cohesión

Existen diversos grados de cohesión funcional

Cohesión muy baja: clase responsable de muchas cosas en muchas

áreas distintas.

ej.: una clase responsable de hacer de interfaz con una base de datos y con un

servicio web.

Baja cohesión: clase responsable de una tarea compleja en un área

funcional.

ej.: una clase responsable de interactuar con una base de datos completa

Alta cohesión: clase que tiene responsabilidades moderadas en un área

funcional y colabora con otras clases para realizar una tarea.

ej.: una clase responsable de una parte de la interacción con la BD.

Page 50: 2 Patrones GRASP

GRASP: Alta cohesión

Discusión

Regla general:

Una clase con alta cohesión tiene un número relativamente bajo

de operaciones, con funcionalidad altamente relacionada, y no

hace demasiado trabajo, sino que colabora y delega.

Contraindicaciones

Existen pocos casos que contraindiquen la “Alta cohesión”.

Algunos ejemplos podrían ser:

Agrupar responsabilidades o código en una sola clase o

componente para simplificar el mantenimiento por una sola

persona (cuando el mapeo objeto relacional lo hace un

experto en SQL, pero novato en OO).

Servidor de objetos distribuidos, debido a las impliciaciones

de “overhead” o “performance” asociadas a objetos

remotos y a la comunicación remota. A veces es deseable

crear pocos objetos servidores, menos cohesivos que

ofrezcan una interfaz para muchas operaciones. Esto es

relativo al patrón Interface Remota de Grano grueso.

Beneficios

Clases más fáciles de entender, de usar, de mantener, y menos

sensibles al cambio

Page 51: 2 Patrones GRASP

GRASP: Cohesión vs. acoplamiento

Cohesión y acoplamiento

son el “yin and yang” de la

ingeniería del software,

debido a su interdependencia

e influencia.

Page 52: 2 Patrones GRASP

Patrones GRASP avanzados

Polimorfismo

Fabricación pura

Indirección

Protección de variaciones

Page 53: 2 Patrones GRASP

GRASP: Polimorfismo

Vamos ahora a incluir el concepto de tipos de casillas en el Monopoly.

Distintos tipos de casillas. En función del tipo de casilla, el

comportamiento del método caerEn() varía:

Casillas de suerte: coger una carta de la suerte

Casillas de propiedades: depende de si la casilla tiene propietario o no, y

si lo tiene si soy yo o es un contrincante del juego

Casilla de Vaya a la Cárcel: ir a la cárcel

Casilla de Tasas: pagar tasas

¿A quién asigno la responsabilidad caerEn()?¿Cómo lo implemento?

Page 54: 2 Patrones GRASP

GRASP: Polimorfismo

Problemas:

¿Cómo manejar alternativas basadas en un tipo sin usar sentencias

condicionales if-then o switch que requerirían modificación en el código?

¿Cómo crear componentes software “conectables”?

Viendo los componentes software en una relación cliente-servidor ¿Cómo

reemplazar un componente servidor con otro sin afectar al cliente?

Solución:

Cuando alternativas o comportamientos relacionados varían por el tipo

(clase), asigna la responsabilidad del comportamiento usando

“operaciones polimórficas” a los tipos para los cuales el comportamiento

varía.

Corolario: No preguntes por el tipo del objeto usando lógica condicional

para realizar las alternativas variantes basadas en el tipo.

Page 55: 2 Patrones GRASP

GRASP: Polimorfismo

Page 56: 2 Patrones GRASP

GRASP: Polimorfismo

Page 57: 2 Patrones GRASP

GRASP: Polimorfismo

Discusión

¿Cuándo usar interfaces (y no clases abstractas)? Si hay una

jerarquía de clases con una superclase abstracta C1, considera

hacer una interfaz I1 de las signaturas de los métodos públicos

de C1 y después declara que C1 implementa I1.

Contraindicaciones

Diseñar con polimorfismo cuando no se tiene la certeza de la

posible variación es “tiempo y esfuerzo perdido”. Evalúe la

necesidad y diseñe con verosimilitud.

Beneficios

Extensiones para el manejo de las variaciones son fáciles de

manejar.

Se pueden introducir nuevas implementaciones sin afectar a los

clientes.

Patrones

relacionados

GoF (Adapter, Command, Composite, Proxy, State, Strategy)

También conocido

como

Choosing Message, Don’t Ask “What Kind?”

Page 58: 2 Patrones GRASP

GRASP: Fabricación pura

Es necesario guardar instancias del Monopoly en una base de datos

relacional. ¿Quién debería tener esa responsabilidad?

Por Expert la clase Monopoly debería tener esta responsabilidad, sin

embargo:

La tarea requiere un número importante de operaciones de base de datos, ninguna

relacionada con el concepto de Monopoly, por lo que Monopoly resultaría

incohesiva.

Monopoly quedaría acoplado con la interface de la base de datos (ej.- JDBC en

Java, ODBC en Microsoft) por lo que el acoplamiento aumenta. Además el

acoplamiento sería a una tecnología específica de base de datos, no a otro objeto

del dominio (que sería menos grave).

Guardar objetos en una base de datos relacional es una tarea muy general para la

cual se requiere que múltiples clases le den soporte. Colocar éstas en Monopoly

sugiere pobre reuso o gran cantidad de duplicación en otras clases que hacen lo

mismo.

Page 59: 2 Patrones GRASP

GRASP: Fabricación pura

Solución: Crear una clase (PersistentStorage) que sea

responsable de guardar objetos en algún tipo de

almacenamiento persistente (tal como una base de datos

relacional).

PersistentStorage

insert( Object )

update( Object )

...

By Pure Fabrication

Page 60: 2 Patrones GRASP

GRASP: Fabricación pura

Problemas resueltos:

La clase Monopoly continua bien definida, con alta cohesión y bajo

acoplamiento.

La clase PersistentStorage es, en sí misma, relativamente

cohesiva, tiene un único propósito de almacenar o insertar objetos

en un medio de almacenamiento persistente.

La clase PersistentStorage es un objeto genérico y reusable.

Page 61: 2 Patrones GRASP

GRASP: Fabricación pura

Problema: ¿Qué objeto debería tener la responsabilidad, cuando no

se desean violar los principios de “Alta Cohesión” y “Bajo

Acoplamiento” o algún otro objetivo, pero las soluciones que sugiere

Expert (por ejemplo) no son apropiadas o cuando no es apropiado

asignarlo a una clase software inspirada a partir de una clase

conceptual?

Solución: Asigne un conjunto “altamente cohesivo” de

responsabilidades a una clase artificial conveniente que no

represente un concepto del dominio del problema, algo producto de

la “imaginación” para soportar “high cohesion”, “low coupling” y reuso.

Éste es precisamente el ppio que se aplica cuando se introducen clases

„Helper‟ y clases „Utility‟

Page 62: 2 Patrones GRASP

GRASP: Fabricación pura

En sentido amplio, los objetos pueden dividirse en dos grupos:

Aquellos diseñados por/mediante descomposición

representacional. (Ej.- Monopoly representa el concepto

“partida”)

Aquellos diseñados por/mediante descomposición

conductual. (Ej.- Para agrupar comportamientos o

algoritmos; clases sin nombre ni propósito relacionado con el

mundo real, e.g. TableOfContentsGenerator). Este es el caso

más común para objetos Fabricación pura.

Page 63: 2 Patrones GRASP

GRASP: Fabricación pura

El principio de descomposición conductual para objetos

Fabricación Pura en ocasiones es sobreutilizado por

novatos en diseño y tienden a dividir el software en

términos de funciones.

Exagerando: las funciones se convierten en objetos.

(Clases “functoides”).

¡Tened cuidado con esto si continuamente estáis pasando

objetos como parámetros para que sean procesados por

métodos!

Page 64: 2 Patrones GRASP

GRASP: Indirección

Ejemplo: Cubilete

El objeto Cubilete que hemos comentado cuando hablábamos de

Bajo Acoplamiento es un ejemplo de indirección: un elemento que

no existía en el juego real pero que introducimos para aislarnos del

número de dados que usa el juego.

Page 65: 2 Patrones GRASP

GRASP: Indirección

Problema:

¿Dónde asignar una responsabilidad para evitar acoplamiento

directo entre dos o más cosas? ¿Cómo desacoplar objetos de tal

manera que el bajo acoplamiento se soporte y el reuso potencial

se mantenga alto?

Solución:

Asignad la responsabilidad a un objeto intermedio que medie

entre otros componentes o servicios, de tal manera que los objetos

no estén directamente acoplados. El objeto intermedio crea una

indirección entre los componentes.

Page 66: 2 Patrones GRASP

GRASP: Indirección

“Muchos problemas en ciencias de la computación

pueden resolverse mediante otro nivel de indirección”

es un viejo adagio con relevancia particular en diseño

orientado a objetos (David Wheeler).

Así como muchos patrones de diseño son especializaciones de

Fabricación Pura, muchos otros también lo son de

Indirección (Adapter, Facade, Observer, entre otros).

Además muchas Fabricaciones Puras son generadas por

causa de Indirección.

La motivación principal es el bajo acoplamiento; por lo que

un intermediario se agrega para desacoplar otros componentes

o servicios.

Page 67: 2 Patrones GRASP

GRASP: Protección de variaciones

Imaginad que sois una empresa de creación de juegos de

mesa por internet. Os han pedido que implementéis el

Monopoly, pero sabéis que en breve os van a pedir

también „La isla del tesoro‟, y posiblemente más adelante

otros, como „En busca del imperio cobra‟.

Cada juego utiliza distintos tipos de casilla (variación

entre juegos).

¿Cómo protegeríais el diseño de esa variación?

Page 68: 2 Patrones GRASP

GRASP: Protección de variaciones

Solución: Usar polimorfismo para abstraer los tipos de casilla

ilustraría el concepto de Protección de Variaciones.

El punto de inestabilidad por variaciones son las diferentes interfaces

o APIs de los distintos tipos de casillas de los distintos juegos.

Mediante un nuevo nivel de Indirección, una interfaz y usando

polimorfismo con varias implementaciones Casilla, se logra la

protección de variaciones dentro del sistema a partir de las

variaciones en las APIs externas.

Las partes del sistema comunes colaboran con una interfaz estable;

las implementaciones de las casillas encapsulan las variaciones en

función del juego.

Page 69: 2 Patrones GRASP

GRASP: Protección de variaciones

Problema:

¿Cómo diseñar objetos, subsistemas y sistemas de tal

manera que las variaciones o inestabilidad en estos

elementos no tenga un impacto indeseable sobre otros

elementos?

Solución:

Identifique los puntos de variación o inestabilidad;

asigne responsabilidades para crear una interfaz

estable a su alrededor.

Page 70: 2 Patrones GRASP

Principios de diseño motivados

por la protección de variaciones

Robert C. Martin. Agile Software Development,

Principles, Patterns, and Practices. 2002.

Page 71: 2 Patrones GRASP

Principios de diseño motivados por PV

Encapsulación

Diseñar operaciones de manera que consultan o modifican, pero no hacen ambas cosas a la vez

Separación Modelo-Vista: objetos del modelo no deberían conocer objetos de presentación, para promocionar bajo acoplamiento de otras capas hacia la capa de interfaz (que es la que más cambia)

Principio de Sustitución de Liskov: Una instancia de unaclase derivada debe ser capaz de tomar el lugar de unainstancia de una clase base. Por ejemplo, si un métodotiene un objeto de una clase como argumento, el mismométodo debe ser capaz de trabajar con una instancia de una clase derivada.

Page 72: 2 Patrones GRASP

Principios de diseño motivados por PV

Principio OPEN-CLOSE (Bertrand Meyer)

Los módulos software (paquetes, métodos, clases, etc.) deberían

estar ABIERTOS a la extensión y CERRADOS a la modificación

Diseña el software de manera que puedas extender su capacidad

(añadir nuevas funcionalidades) tocando lo menos posible el código que

ya existe. La mayoría de los cambios se materializan en la adición de

métodos o clases al sistema

No siempre es posible seguir este principio de manera completa,

pero mientras más lo sigas más fácil será después acomodar

nuevos (y quizás inesperados) requisitos.

Page 73: 2 Patrones GRASP

Principios de diseño motivados por PV

PRINCIPIO DE “INVERSIÓN” DE DEPENDENCIA

Los módulos de alto nivel no deberían depender de módulos de bajo nivel.

Tanto unos como otros deberían depender de abstracciones

Las abstracciones no deberían depender de detalles, sino al contrario: los

detalles deberían depender de las abstracciones.

Esto implica que el acoplamiento entre los objetos que usan y los objetos que

son usados se debería hacer siempre a nivel conceptual (en términos de

„servicios‟ que unos requieren de los otros), sin tener en cuenta los detalles

concretos de las implementaciones.

Ojo! Este principio “invierte” la idea convencional de que módulos de alto nivel

deberían depender de módulos de bajo nivel.

Llevar este principio al extremo supondría asumir que…

No deberían existir variables que referenciasen clases concretas

Ninguna clase debería derivar de una clase concreta

Ningún método debería sobreescribir un método implementado de una de

sus clases base

En la práctica no es útil llegar a este extremo, pero sí ser consciente de que

cuando se violan estos principios estamos añadiendo acoplamiento

Page 74: 2 Patrones GRASP

Principios de diseño motivados por PV

Interface Segregation Principle: Clients should not be forced to

depend upon interfaces that they do not use. Many client-specific

interfaces are better than a general-purpose one.

Reuse/Release Equivalency Principle: The granule of reuse is the

same as the granule of release. Only components that are released

through a tracking system can be effectively reused.

Common Reuse Principle: Classes that are not reused together

should not be grouped together.

Common Closure Principle: Classes that change together, belong

together.

Stable Abstractions Principle: The more stable a category of classes

is, the more it should consist of abstract classes. A completely stable

category should consist of only abstract classes.

Page 75: 2 Patrones GRASP

Principios de diseño motivados por PV

Least Astonishment Principle: When two elements of an interface

conflict or are ambiguous, the behavior should be that which least

surprises the software engineer at the time of the conflict, because

the least surprising behavior must be usually the correct one.

Deep Abstract Hierarchies Principle: Class hierarchies should be

deep and abstract.

The Acyclic Dependencies Principle: There should be no cycles in the

dependency graph.

The Stable Dependencies Principle: Depend in the direction of

stability. The dependencies between components in a design should

be in the direction of stability. A component should only depend upon

components that are more stable than it is.

Page 76: 2 Patrones GRASP

Principios de diseño motivados por PV

Don’t Talk to Strangers (Ley de Demeter): Cada unidad(clase, método) sólo debería utilizar un conjunto limitado de otras unidades, y sólo entre aquéllas que están fuertementerelacionadas con la unidad actual

Este principio restringe a qué objetos debería enviárseles mensajes dentro de un método:

Al objeto this (o self).

A un parámetro del método.

A un atributo de this.

A un elemento de una colección que es un atributo de this.

A un objeto creado dentro del método. (local al método).

La intención es evitar acoplamiento con objetos indirectos. Los objetos directos son los “familiares del cliente” los indirectos son los “extraños”.

El cliente debe hablar con los “familiares” no con los “extraños”.

Protege contra cambios estructurales

Page 77: 2 Patrones GRASP

Principios de diseño motivados por PV

ID to Objects: convertir claves e ID‟s de objetos en objetos verdaderos lo más pronto posible (normalmente en cuanto el ID entra en la capa de dominio del modelo de diseño), para a partir de ahí trabajar con el objeto.

¿Por qué?: Tener un objeto real, con información y responsabilidades (y no simplemente un ID) flexibiliza la aplicación según el diseño crece, ya que es probable que necesidades no percibidas originalmente surjan durante la evolución del sistema.

Pasar objeto agregado como parámetro: cuando una operación requiere como parámetros objetos que están agregados dentro de otros, pasar el objeto agregado, y no los objetos „hijos‟.

¿Por qué? Pasar el objeto agregado aumenta flexibilidad del sistema, al permitir que la operación colabore con el objeto agregado en modos que en un principio no habíamos previsto.

Page 78: 2 Patrones GRASP

EJERCICIO

Volved al ejercicio que realizasteis en el tema anterior, en

el que identificasteis, sobre un diagrama de clases de

vuestra elección, el conjunto de elementos que podrían

ser patrones (una buena práctica que deberíais repetir si

os encontráseis ante un problema similar)

Revisar vuestra conclusión inicial a la luz de los patrones

Larman

Page 79: 2 Patrones GRASP

EJERCICIO

EJERCICIO PARA ENTREGAR (OBLIGATORIO)

Bajáos el documento con las reglas completas del Monopoly

Realizad un Modelo de Dominio y un Modelo de Diseño (al menos

el diagrama de clases de diseño) del juego que permita implementar

dicho juego en modo simulación.

Realizad un comentario de vuestro modelo indicando qué principios

GRASP habéis aplicado en las distintas decisiones de asignación de

responsabilidades

A partir de ahora, tened esta versión del juego siempre a mano,

para poder irla flexibilizando según vayamos aprendiendo nuevos

patrones.

Page 80: 2 Patrones GRASP

Ingeniería del Software 1 - Curso 2010/2011

¿Dudas?