0% encontró este documento útil (0 votos)
26 vistas11 páginas

Patrones de Diseño GRASP

Descargar como pdf o txt
Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1/ 11

Patrones GRASP

08.23

Experto en información:
Nos dice que la responsabilidad de crear un objeto o una clase o implementar un método es
responsabilidad de la clase que conoce toda la información para crearlo.
El beneficio de esto es crear un diseño con mayor cohesión y así la información se
mantiene encapsulada y con mayor acoplamiento.

este patrón se relaciona con el patrón CREADOR.

Problema:

¿Cuál es un principio general para asignar responsabilidad a los objetos?

Solución:

El principio para que exista un experto en información es que la clase tenga toda la
información necesaria para crear la clase.

Ejemplo que incumple "Experto en información":


public class Informe
{
public int[] Parciales { get; set; }
}

public class InformePresenter


{
Informe _informe;

public void CalculateTotalButtonClicked()


{
var total = 0;
foreach (var parcial in _informe.Parciales)
{
total = total + parcial;
}
// TRUCO GRATIS: éste bucle lo podemos convertir en un una expresión funcional
usando Linq:
// var total = _informe.Parciales.Aggregate(0, (current, parcial) => current + parcial);
}
}

¿Por qué viola éste principio?

Por lo mismo que viola la S de SOLID, la responsabilidad de InformePresenter es,


como su propio nombre indica, presentar un informe y en éste caso está
calculando el total. ¡Mal! El total debería dárselo la clase Informe, que es la que
tiene toda la información al respecto, ella es la experta y quien debería
calcularlo.

Solución:
public class Informe
{
public int[] Parciales { get; set; }

public void CalcularTotal()


{
var total = 0;
foreach (var parcial in Parciales)
{
total = total + parcial;
}
}
}

public class InformePresenter


{
private Informe _informe;

public void CalculateTotalButtonClicked()


{
_informe.CalcularTotal();
}
}

Beneficios: Con la utilización de este patrón se conserva el encapsulamiento, ya que los


objetos se valen de su propia información para hacer lo que se les pide. El omportamiento
se distribuye entre las clases que cuentan con la información requerida, alentando con ello
definiciones de clases sencillas y más cohesivas que son más fáciles de comprender y
mantener.
Creador:

Se le asigna la responsabilidad de instanciar determinadas clases, debido a que se le


asigna la información necesaria para tener la responsabilidad de crear las clases, objetos o
implementar métodos necesarios.

NOTA:

No todo Experto en información es creador, pero todo creador es


un experto en información

Problema:

¿Quién debería ser el responsable de la creación de una nueva instancia de alguna clase?
Solución:

El patrón Creador guía la asignación de responsabilidades relacionadas con la creación de


objetos. El propósito fundamental de este patrón es encontrar un creador que se debe
conectar con el objeto producido en cualquier evento.

Beneficios:
Brinda un soporte a un bajo acoplamiento –patrón que será descrito más adelante– lo que
supone menos dependencias respecto al mantenimiento y mejores oportunidades de
reutilización.

Bajo Acoplamiento:
El acoplamiento es una medida de la fuerza con que una clase está conectada a otras
clases, con que las conoce y con que recurre a ellas. Una clase con bajo (o débil)
acoplamiento no depende de muchas otras clases. Una clase con alto (o fuerte)
acoplamiento recurre a muchas otras. Este tipo de clases no es conveniente, ya que
presentan los siguientes problemas:

Los cambios de las clases afines ocasionan cambios locales.


Son más difíciles de entender cuando están aisladas.
Son más difíciles de reutilizar porque se requiere la presencia de otras clases de las que
dependen.

Problema:

¿Cómo soportar bajas dependencias, bajo impacto del cambio e incremento de la


reutilización?

Solución:
Asignar una responsabilidad de manera que el acoplamiento permanezca bajo.

Beneficios:
Con el uso de este patrón los componentes no se afectan por cambios de otros
componentes, son fáciles de entender por separado y fáciles de reutilizar.

Alta cohesión:
En la perspectiva del diseño orientado a objetos, la cohesión es una medida de cuan
relacionadas y enfocadas están las responsabilidades de una clase. Una alta cohesión
caracteriza a las clases con responsabilidades estrechamente relacionadas que no
realicen un trabajo enorme. Una clase con baja cohesión hace muchas cosas no afines o
un trabajo excesivo. No conviene este tipo de clases pues presentan los siguientes
problemas:

Son difíciles de comprender.


Son difíciles de reutilizar.
Son difíciles de conservar.
Son delicadas: las afectan constantemente los cambios.

Las clases con baja cohesión a menudo representan un alto grado de abstracción o
han asumido responsabilidades que deberían haber delegado a otros objetos.

Problema:

¿Cómo mantener la complejidad manejable?

Solución:

Asignar una responsabilidad de manera que la cohesión permanezca alta.

Beneficios:
Con el uso de este patrón mejoran la claridad y la facilidad con que se entiende el diseño.
Se simplifican el mantenimiento y las mejoras en funcionalidad. A menudo se genera un
bajo acoplamiento. La ventaja de una gran funcionalidad soporta una mayor capacidad de
reutilización, porque una clase muy cohesiva puede destinarse a un propósito muy
específico.

Controlador:
Un evento del sistema es un evento de alto nivel generado por un actor externo; es un
evento de entrada externa. Se asocia a operaciones del sistema: las que emite en
respuesta a los eventos del sistema.
Un Controlador es un objeto de interfaz no destinada al usuario que se encarga de manejar
un evento del sistema. Define además el método de su operación.

La mayor parte de los Sistemas reciben eventos de entrada externa, los cuales
generalmente incluyen una interfaz gráfica para el usuario operado por una persona. Otros
medios de entrada son los mensajes externos o las señales procedentes de sensores como
sucede en los sistemas de control de procesos. En todos los casos, si se recurre a un
diseño orientado a objetos, hay que elegir los controladores que manejen esos eventos de
entrada. Este patrón ofrece una guía para tomar decisiones apropiadas que generalmente
se aceptan. La misma clase controlador debería utilizarse con todos los eventos sistémicos
de un caso de uso, de modo que se pueda conservar la información referente al estado del
caso.

Problema:

¿Quién debería ser el responsable de gestionar un evento de entrada al sistema?

Solución:

Asignar una responsabilidad de recibir o manejar un mensaje de evento del sistema a una
clase que representa una de las opciones siguientes:

Representa el sistema global, dispositivo o subsistema.

El “sistema” global (controlador de fachada).

La empresa u organización global (controlador de fachada).

Algo en el mundo real que es activo (por ejemplo, el papel de una persona) y que
pueda participar en la tarea (controlador de tareas).

Un manejador artificial de todos los eventos del sistema de un caso de uso


(controlador de casos de uso).

Representa un caso de uso en el que tiene lugar el evento del sistema a menudo
denominado <nombre del caso de uso> Manejador, <nombre del caso de uso>
coordinador, <nombre del caso de uso> Sesión.

•Utilice la misma clase controlador para todos los eventos del sistema en el mismo
escenario de caso de uso.

•Informalmente, una sesión es una instancia de una conversación con un actor. Las
sesiones pueden tener cualquier duración, pero se organizan a menudo en función de casos
de uso.
Beneficios:
Garantiza que la empresa o los procesos de dominio sean manejados por la capa de los
objetos del dominio y no por la de la interfaz. Al delegar a un controlador la responsabilidad
de la operación de un sistema entre las clases del dominio favorece la reutilización de la
lógica para manejar los procesos afines del negocio en aplicaciones futuras.

Polimorfismo:
En patrones GRASP es asignar el mismo nombre a servicios en diferentes objetos cuando
los servicios son parecidos ya que tienen asignados una misma responsabilidad o están
relacionados por la jerarquía de clases

Problema:

¿Cómo manejar alternativas basadas en el tipo (clase)?

¿Cómo crear componentes de software conectables?

Solución:

Cuando los comportamientos varían según el tipo asignar la responsabilidad del


comportamiento al tipo que varía, no utilizar condicionales para comprobaciones del tipo de
objeto para realizar la operación.
.
Mala implementación:

public enum TipoDeLog


{
Debug,
Error
}

public class Log


{
StreamWriter _ficheroLog;

public void Registrar(string mensaje, TipoDeLog tipoDeLog)


{
switch (tipoDeLog)
{
case TipoDeLog.Debug:
_ficheroLog.WriteLine("[DEBUG];{0}", mensaje);
break;
case TipoDeLog.Error:
_ficheroLog.WriteLine("[ERROR]:{0}", mensaje);
break;
}
}
}

public class CualquierPresentador


{
Log _log;
public void AlgoHaSucedido()
{
_log.Registrar("Algo ha sucedido y queremos dejar constancia en un registro.",
TipoDeLog.Debug);
}
}

¿Por qué?

Se ve claramente la dependencia de la clase Log y el método registrar con el TipoDeLog.


Podemos evitar ésto creando una interfaz para el mensaje implementada de dos formas
distintas, una por cada tipo, y sólo tendremos que pedir a la clase Log que registre un
IMensaje. Y dependiendo de qué mensaje queramos registrar, quien sepa de qué tipo debe
ser registrado, es decir, el experto en información, que cree una instancia concreta y llame a
Log.Registrar.

Bien implementado:
public interface IMensajeDelLog
{
string Valor { get; }
}

public class MensajeDebug : IMensajeDelLog


{
readonly string _mensaje;

public MensajeDebug(string mensaje)


{
_mensaje = mensaje;
}

public string Valor


{
get
{
return string.Format("[DEBUG];{0}", _mensaje);
}
}
}
public class MensajeError : IMensajeDelLog
{
readonly string _mensaje;

public MensajeError(string mensaje)


{
_mensaje = mensaje;
}

public string Valor


{
get
{
return string.Format("[ERROR];{0}", _mensaje);
}
}
}

public class Log


{
StreamWriter _ficheroLog;

public void Registrar(IMensajeDelLog message)


{
_ficheroLog.WriteLine(message.Valor);
}
}

public class CualquierPresentador


{
Log _log;

public void AlgoHaSucedidoYQueremosRegistrarUnError()


{
_log.Registrar(new MensajeError("Algo ha sucedido y queremos dejar constancia en
un registro."));
}

public void AlgoHaSucedidoYQueremosRegistrarloParaDepurar()


{// Por ejemplo una excepción
_log.Registrar(new MensajeDebug("Algo ha sucedido y queremos dejar constancia en
un registro."));
}
}
Fabricación Pura:
Patrón que se basa en la creación de clases artificiales que agrupan comportamientos o
funciones comunes entre clases del dominio para soportar los conceptos de Alta Cohesión y
Bajo Acoplamiento.

Problema:

¿Qué Objetos deberían tener la responsabilidad para evitar la baja cohesión y el alto
acoplamiento ocasionados en algunos casos por otros patrones como el Experto?

SOLUCIÓN:

Asignar un conjunto de responsabilidades comunes (funciones) a una clase artificial que no


representa un concepto del dominio del problema y que al implementarlas en otras clases
provoca baja cohesión y alto acoplamiento en ellas. Esta clase nueva soporta alta cohesión
y bajo acoplamiento.

Uso:
disminuye el acoplamiento y aumenta la cohesión, esto ayuda a potenciar la reutilización
del código.

Soluciona que una clase sea poco cohesiva y no tenga otra clases en la que implementar
algunos métodos.

En desventaja del exceso de este principio se puede tener muchas clases de un solo
método como si fueran funciones.

Indirección:
Problema:

¿a quien se le asignan las responsabilidades a fin de evitar/reducir el acoplamiento directo


entre elementos y mejorar la reutilización?

Solución:

Se asigna la responsabilidad a un objeto intermedio para que se medie entre otros


componentes o servicios y estos no terminen directamente acoplados.
El intermediario crea una relación indirecta entre el resto de los componentes o servicios.
Variaciones Protegidas:
Variaciones protegidas, es el principio fundamental de protegerse frente a nuevos requisitos.

Así lo que podamos ver en un análisis previo y sea susceptible a modificaciones lo


extraemos a una interfaz para crear varias implementaciones y extender nuestro código
todo lo posible sin que nuestro código sufra por la cohesión y el acoplamiento.

De ésta forma, si nos entra un nuevo requisito, este debe repercutir lo mínimo. Este
principio introduce el polimorfismo y la indirección.

También podría gustarte

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy