Escolar Documentos
Profissional Documentos
Cultura Documentos
Diseño de Software
Apuntes 01
Arquitectura de Software
Grupo 40
Integrantes:
II Semestre 2018
Diseño de software
El objetivo de la arquitectura es tratar de interferir en la vida del hombre
trabajando a su favor, esta debe ser la respuesta a un problema y no una
imposición. Por lo que, la principal función del arquitecto de software es ayudar al
programador a dar los pasos necesarios para la creación del software. además la
idea es utilizar algo que sea de verdad útil, ya que el poder hacerlo no justifica el
hacerlo, o visto de otra forma, no crear problemas para justificar malas soluciones.
Además una aplicación sin “plano” es caminar sin un rumbo, por eso la arquitectura
es la base de un sistema de software.
❖ Comprensión del dominio del problema, con tal de brindar una respuesta
acertada a una problemática.
❖ Conocimiento abstracto y la capacidad de conceptualizar.
❖ Métodos probados lo que puede consistir en la comprensión de patrones o
nuevas tecnologías probadas para la resolución de problemas de naturaleza
similar.
❖ Perspicacia técnica.
Tabla de contenido
Programación Orientada a Objetos (POO)............................................................................................................................. 2
Pilares de la POO.............................................................................................................................................................. 2
Abstracción.................................................................................................................................................................. 2
Encapsulamiento ......................................................................................................................................................... 2
Herencia ...................................................................................................................................................................... 3
Polimorfismo ............................................................................................................................................................... 3
Clases abstracta e interfaces ............................................................................................................................................ 4
Clases abstractas ......................................................................................................................................................... 4
Interfaces .................................................................................................................................................................... 4
Diagrama de clases............................................................................................................................................................... 6
Contenidos de diagrama de clases.................................................................................................................................... 8
Clases .......................................................................................................................................................................... 8
Modelo de Estudio ............................................................................................................................................................. 11
Problema ....................................................................................................................................................................... 11
Solución ......................................................................................................................................................................... 11
Model ........................................................................................................................................................................ 12
View .......................................................................................................................................................................... 13
Controller .................................................................................................................................................................. 14
Código ........................................................................................................................................................................... 15
Referencias ........................................................................................................................................................................ 16
Página 1 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Pilares de la POO
Abstracción
Pensamiento genérico, es decir que un objeto puede repetirse e interactuar con otros para lograr “objetos” más complejos.
Encapsulamiento
Empacar las clases, es decir generar genéricos que modifican o realizan determinada acciones a los objetos.
Página 2 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Herencia
Un objeto añadido en otro contexto y aumentar características básicas. Un odontólogo, y un estudiante tienen atributos
similares muy a pesar de que se comportan distinto, por lo que podemos tener similitudes y diferencias sin necesidad de
crear dos objetos distintos (Todo lo igual se copia no se crea).
Polimorfismo
Un objeto puede responder de alguna forma diferente dependiendo, del entorno.
Podemos aplicarlo a una forma genérica que lo explica mejor:
La importancia es la reusabilidad de los objetos, para generar un código limpio en menos cantidad de instrucción.
Cohesión es decir que todo esté encapsulado al buscar un objeto, y que están realmente relacionadas, un objeto no
funciona sin otro, generando un alto acople.
Un objeto es una cosa con significado, es decir que tenemos bien limitado cuales son las funciones que realiza y tiene:
• Estado: Es decir puede cambiar constantemente de estados para realizar un fin común.
• Comportamiento: Se comporta de determinada forma y realiza una única acción.
• Identidad: Se identifica de los demás, porque tienen una identidad y un comportamiento distinto a los demás, de
la misma forma un identificador único que suele ser el nombre.
Página 3 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Clases abstractas
Una clase abstracta no se puede instanciar y sus métodos no tienen implementación, por lo general se denotan con la
palabra “abtract” y para UML utilizamos itálica para definirla
Cuando deseamos definir una abstracción que englobe objetos de distintos tipos y queremos hacer uso del polimorfismo.
Figura
#X #Y
Cuadrado Círculo
-lado -radio
+área() +área()
Figura es una clase abstracta (nombre en cursiva en UML) porque no tiene sentido calcular su área, pero sí la de un
cuadrado o un
círculo. Si una subclase de Figura no redefine area() solamente la implementa, deberá declararse también como clase
abstracta.
Interfaces
Una interfaz es una clase completamente abstracta (una clase sin implementación)
En el ejemplo anterior, si no estuviésemos interesados en conocer la posición de una Figura, podríamos eliminar por
completo su implementación y convertir Figura en una interfaz:
Página 4 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Figura
+área()
Cuadrado Círculo
-lado -radio
+área() +área()
En la declaración de una interfaz, lo único que puede aparecer son declaraciones de métodos (su nombre y signatura, sin su
implementación) y definiciones de constantes simbólicas.
Una interfaz no encapsula datos, sólo define cuáles son los métodos que han de implementar los objetos de aquellas clases
que implementen la interfaz.
Una clase puede implementar varios interfaces simultáneamente, podemos ver un ejemplo a continuación.
Página 5 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Diagrama de clases
Primero que todo estos diagramas se modelan siguiendo una estructura, la cual suele ser UML que es ante todo un lenguaje
que nos permite seguir un estándar en las representaciones gráficas de las clases y los objetos así como sus relaciones.
Página 6 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Página 7 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Clases
• Tipos
• Visibilidad
Página 8 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
• Relaciones
a. Asociación
i. Asociación simple
Página 9 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
c. Composición
Es una forma más fuerte de agregación, en la que el todo no puede existir sin sus partes. En el siguiente
diagrama se muestra la clase grupo, donde se puede mostrar que un grupo deja de existir sin el profesor o
el curso, sin embargo si uno de los estudiantes se va, el grupo continúa existiendo.
e. Generalización
Indica que una subclase hereda los métodos y atributos especificados por una super clase. La subclase
además de poseer sus propios métodos y atributos poseerá las características y atributos visibles de la
super clase (public y protected).
Página 10 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Modelo de Estudio
Se plantea el siguiente modelo de estudio con el objetivo de poner en práctica los conceptos, vistos anteriormente, en un
problema concreto.
Problema
• Crear un sistema administrador de usuarios con POO.
• Hacer un diseño detallado de un modelo de tipo estático.
Solución
Se utilizó un estilo de arquitectura MVC (Model View Controller), de manera que se tenga bajo acoplamiento entre los
módulos por medio de la descomposición en 3 tipos de responsabilidades. Estas responsabilidades se dividen en:
• El Modelo que contiene una representación de los datos que maneja el sistema, su lógica de negocio, y sus
mecanismos de persistencia.
• La Vista, o interfaz de usuario, que compone la información que se envía al cliente y los mecanismos interacción
con éste.
• El Controlador, que actúa como intermediario entre el Modelo y la Vista, gestionando el flujo de información entre
ellos y las transformaciones para adaptar los datos a las necesidades de cada uno.
Página 11 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Model
En el modelo se crearon las 5 clases de información que se necesita conservar de manera permanente, Usuario, Estado,
Bitácora, Rol y Permiso. Cabe destacar que Estado y Permiso son valores de tipo enumerado, esto se debe a que ambas
tienen un rango finito de valores posibles. Al diseñarlos como enumeraciones se cumple con el principio de abstracción y se
evitan errores a la hora de ingresar los datos.
Usuario:
• La clase usuario cuenta con un atributo estado de tipo Estado. La relación entre Estado y Usuario es de tipo
dependencia, donde Usuario usa a Estado para obtener los posibles valores de su atributo.
• Se da una relación de agregación donde el Usuario el TODO y el Rol una PARTE. Un rol puede pertenecer a
varios usuarios, puede existir aunque no haya usuarios que lo contengan, puede cambiar de usuario y por
último, al eliminar un usuario no se elimina el rol al que pertenece. Debe tener al menos un rol el usuario.
Rol:
• Un Rol está compuesto por una serie de permisos. La serie particular de permisos asignados a un rol solo
pertenecen a dicho rol y al eliminar el rol sus permisos también son eliminados. Puede tener de 0 a n
permisos.
• Implementa la interfaz ITransaccional para que realice las funciones CRUD de permisos con el formato
estándar.
Bitácora:
• La Bitácora recibe mensajes de un Usuario, donde el Usuario cumple el rol de autor del registro que se guarda
en la Bitácora. La relación es un tipo de asociación unidireccional.
Página 12 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Página 13 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Controller
En el controlador se diseñó siguiendo el principio de descomposición al crear subsistemas para la administración de roles,
bitácoras y usuarios. En total está compuesto por 5 clases y dos interfaces.
ITransaccional
• La interfaz ITransaccional se creó para ser un molde de las funciones CRUD, de esta manera el diseño cumple
con el principio de separación de interfaz e implementación. Por medio de esta interfaz se aíslan los detalles
de como cada componente realiza las funciones y se estandariza lo que conocen otros componentes acerca de
esta.
IValidable
• En el caso de la interfaz IValidable sirve como plantilla para la validación de objetos. Aunque en el sistema
actual solo la utiliza una vez se justifica su creación en por la escalabilidad. Al igual que en el caso anterior,
esta interfaz ayuda a separar la interfaz de las implementaciones.
GestorGeneral:
• Es una clase abstracta en la que se ignoran las posibles diferencias entre los gestores para enfocarse en su
similitud.
• Implementa la interfaz ITransaccional para que realice las funciones CRUD con el formato estándar.
GestorBitácora:
• Se da una relación de herencia con el GestorGeneral.
• Depende de la clase Bitácora, que se encuentra en el modelo, para realizar sus funciones.
GestorRoles:
• Se da una relación de herencia con el GestorGeneral.
Página 14 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
• Depende de la clase Rol, que se encuentra en el modelo, para realizar sus funciones.
GestorUsuarios:
• Se da una relación de herencia con el GestorGeneral.
• Depende de la clase Usuario, que se encuentra en el modelo, para realizar sus funciones.
• Implementa la interfaz IValuable para validar el acceso de los usuarios.
Controlador:
• Recibe mensajes del GestorBitácora, GestorRoles, GestorUsuarios para sus funciones.
• Realiza todas las funciones de los gestores uniéndolas con la información que devuelve la vista.
Código
Tanto el diagrama como el código del sistema se encuentran disponibles en el TecDigital en Semana 3.
Página 15 de 16
IC6821 Diseño de Software
Apunte 02: Repaso Conceptos Básicos OO
Referencias
Universidad de Alicante. (s.f.). Modelo vista controlador (MVC). Servicio de Informática ASP.NET MVC 3 Framework.
Obtenido de Universidad de Alicante: https://si.ua.es/es/documentacion/asp-net-mvc-3/1-dia/modelo-vista-
controlador-mvc.html
Página 16 de 16
Instituto Tecnológico de Costa Rica.
Ingeniería en Computación.
Grupo 40
Apuntes #3 – SOLID
Estudiantes:
Agosto.
II Semestre 2018.
pág. 1
Índice
Principios SOLID………………………………………………………………………3
pág. 2
Principios SOLID
Los principios SOLID son cinco principios enunciados por Robert C. Martin
alrededor del año 2000 enfocados a la elaboración de software de calidad. Cuando
estos principios se aplican en conjunto es más probable que un desarrollador cree
un sistema que sea fácil de mantener y ampliar en el tiempo. Los principios SOLID
son guías que pueden ser aplicadas en el desarrollo de software para eliminar
código sucio provocando que el programador tenga que refactorizar el código fuente
hasta que sea legible y extensible. Forma parte de la estrategia global del desarrollo
ágil de software y programación adaptativa.
Esta definición es perfectamente válida y se podría resumir diciendo que son cinco
principios que hay que tener siempre presentes si queremos desarrollar un software
de calidad legible, entendible y fácilmente testeable.
Estos principios fueron creados para dar una mejor solución a problemas como los
siguientes:
• Rigidez
• Fragilidad
• Inmovilidad
• Viscosidad
• Complejidad innecesaria
• Repetición innecesaria
• Opacidad
pág. 3
SRP: Single Resposibility Principle
Una clase debería concentrarse sólo en hacer una cosa de tal forma que cuando
cambie algún requisito en mayor o menor medida dicho cambio sólo afecte a dicha
clase por una razón.
Divide las clases que sean muy grandes y que tengan muchas funcionalidades en
otras más pequeñas, pero que de igual manera cumplan con las funciones.
UML
pág. 4
¿Porqué incumple el principio de única responsabilidad?
SRP dice que sólo debería haber un motivo para cambiar una clase o una interfaz
y, por ende, las clases que la implementan. En éste caso la traducción literal es
clara, si cambiara el contenido habría que modificar el código cada vez que
añadamos algún tipo de contenido o si, cambiara el protocolo y quisiéramos añadir
más campos también habría que modificar la clase email. Por tanto hay más de un
motivo por el que tendríamos que modificar ésta clase.
UML
pág. 5
Si en vez de un contenido String utilizamos una interfaz IContenido que suponga un
contrato para hacer viable cualquier tipo de contenido cada vez que nos pidan que
añadamos un tipo de contenido sólo tendremos que modificar dicha interfaz y/o las
clases que lo implementen, a lo que afecte el cambio, y no a la clase
CorreoElectronico y a su interfaz.
En este caso un único cambio presente en algún programa puede llegar a dar como
resultado una cascada de cambios en aquellos módulos que sean dependientes,
por otro lado, dicho programa puede llegar a exhibir los atributos indeseables, los
cuales se pueden asociar con un mal diseño. Por otro lado, este programa se puede
volver frágil, rígido, impredecible y no pueda ser reutilizado, por eso este abierto
principio ataca esto de una manera muy directa. En este se establece que se deben
diseñar módulos que nunca deben cambiar cuando los requisitos lo hacen,
extendiendo el comportamiento de dichos módulos con la agregación de nuevo
código, entonces no se debería cambiar el código anterior que ya funciona.
Descripción
Pareciera que estos dos atributos se encuentran en desacuerdo uno del otro, la
forma natural en la que se puede extender el comportamiento de un módulo en
específico es realizando algún tipo de cambio en el. Por esta situación, un módulo
que no puede cambiarse normalmente se piensa que tiene un comportamiento fijo.
pág. 6
El uso más común de extensión es por medio de la herencia y también al volver a
implementar métodos, existe otra alternativa, la cual consiste en usar métodos que
puedan aceptar una interfaz de manera que podemos ejecutar cualquier clase que
sea usada por dicha interfaz. Se puede decir que prácticamente en todos los casos,
el comportamiento de la clase cambia sin que se haya hecho una sola modificación
en el código interno. Puede llegar un momento en el cual las necesidades sean tan
imprevisibles que los métodos definidos en la interfaz o en los métodos que sean
extensibles, no sean suficientes para cubrir las necesidades, por lo que se deberá
romper este principio y refactorizar.
La abstracción es la clave
Las abstracciones son clases base abstractas, a su vez en estas se puede llegar a
representar un grupo ilimitado de comportamientos posibles, esto en todas las
clases derivadas de ser posible. Un módulo en específico podría llegar a manipular
una abstracción, en donde este módulo puede llegar a cerrarse para algún tipo de
modificación ya que puede estar dependiendo de una abstracción fija, sin embargo,
el comportamiento de dicho módulo puede llegar a extenderse mediante la creación
de nuevos derivados de la abstracción.
Ejemplo
pág. 7
Básicamente es una clase que especifica su tipo mediante un enumerado, podemos
tener por ejemplo un enum con un par de tipos:
Mientras no necesitemos dibujar más tipos de vehículos ni veamos que este switch
se repite en varias partes de nuestro código, en mi opinión no debes sentir la
necesidad de modificarlo. Incluso el hecho de que cambie la forma de dibujar un
coche o una moto estaría encapsulado en sus propios métodos y no afectaría al
resto del código.
Pero puede llegar un punto en el que necesitemos dibujar un nuevo tipo de vehículo,
y luego otro. Esto implica crear un nuevo enumerado, un nuevo case y un nuevo
método para implementar el dibujado. En este caso sería buena idea aplicar el
principio Open/Closed.
pág. 8
Añadir nuevos vehículos ahora es tan sencillo como crear la clase correspondiente
que extienda de Vehicle:
pág. 9
LSP: Liskov Substitution Principle
El Principio de Sustitución de Liskov fue acuñado por Barbara Liskov en el año 1987
durante una conferencia sobre Jerarquía y Abstracción de datos. Su principal
cometido es la de asegurar en la herencia entre clases de la Programación
Orientada a Objetos que una clase derivada no únicamente es sino que debe
comportarse como la clase base.
Si por cada objeto o1 del tipo S existe un objeto o2 del tipo T tal que para todos los
programas P definidos en términos de T y el comportamiento de P permanece
invariable cuando o1 es sustituido por o2, entonces S es un subtipo de T.
modificado cada vez que se crea una nueva derivada de la clase base.
pág. 10
Por otro lado, este principio no dicta tanto el “qué” sino el “cómo" debe heredarse
tipos. El uso de DbC está estrechamente ligado y puede ser de utilidad en herencias
de tipos más complejos para preservar el comportamiento en el tipo derivado. El
impacto de este principio en los nuevos lenguajes de desarrollo los podemos ver
por ejemplo los argumentos de métodos para los subtipos o la covariancia para el
retorno, tanto en delegados como en interfaces.
Ejemplo
En la vida real tenemos claro que un cuadrado es un rectángulo con los dos lados
iguales. Si intentamos modelar un cuadrado como una concreción de un rectángulo,
vamos a tener problemas con este principio:
pág. 11
La definición del cuadrado sería la siguiente:
¿Cómo lo solucionamos?
Hay varias posibilidades en función del caso en el que nos encontremos. Lo más
habitual será ampliar esa jerarquía de clases. Podemos extraer a otra clase padre
las características comunes y hacer que la antigua clase padre y su hija hereden de
ella. Al final lo más probable es que la clase tenga tan poco código que acabes
teniendo un simple interfaz, esto no supone ningún problema en absoluto:
pág. 12
Pero para este caso en particular, nos encontramos con una solución mucho más
sencilla, la razón por la que no se cumple que un cuadrado sea un rectángulo, es
porque estamos dando la opción de modificar el ancho y alto después de la creación
del objeto. Podemos solventar esta situación simplemente usando inmutabilidad. La
inmutabilidad es un tema muy interesante, consiste en que una vez que se ha
creado un objeto, el estado del mismo no puede volver a modificarse. La
inmutabilidad tiene múltiples ventajas, entre ellas un mejor uso de memoria (todo su
estado es final) o seguridad en múltiples hilos de ejecución. Pero ciñéndonos al
ejemplo, ¿cómo nos ayuda aquí la inmutabilidad? De esta forma:
Desde el momento de la instanciación del objeto, todo lo que hagamos con él será
válido, ya usemos un rectángulo o un cuadrado. El problema que había detrás de
este ejemplo es que la asignación de una parte del estado modifica mágicamente
otro campo. Sin embargo, con este nuevo enfoque, al no permitir las modificaciones,
el funcionamiento de ambas clases es totalmente predecible.
pág. 13
ISP: Interface Segregation Principle
Este principio se basa en evitar el uso de las interfaces "gordas". Las clases que
tienen interfaces "gordas" son clases cuyas interfaces no son cohesivas. En otras
palabras, las interfaces de la clase se pueden dividir en grupos de funciones
miembro. Cada grupo sirve a un conjunto diferente de clientes. Por lo tanto, algunos
clientes usan un grupo de funciones miembro, y otros clientes usan los otros grupos.
El ISP reconoce que hay objetos que requieren interfaces no cohesivas; sin
embargo, sugiere que los clientes no deberían saber sobre ellos como una sola
clase. En cambio, los clientes deben saber acerca de las clases base abstractas
que tienen interfaces cohesivas.
Para que una clase pueda implementar una interface debe programar todos los
métodos que esta contiene, sin embargo, si existen métodos que una clase no sabe
de qué manera implementarlos y, por lo tanto, se tienen que dejar vacíos o que
tengan que lanzar una excepción, hacen que dicha interface se convierta en una
interface gorda o contaminada, un ejemplo es el siguiente:
Primero tenemos una interface llamada Product, que tiene métodos para
obtener el nombre, cantidad en el stock, números de discos y la fecha de
lanzamiento. Esta interface es implementada por la clase CD, de momento, no se
está incumpliendo con el principio, pero resulta que también se quieren vender
películas DVD y estos necesitan tener la clasificación por edad, lo que normalmente
hacen es agregar el método que necesita la nueva clase y pueda seguir usando
esta interface sin problemas.
pág. 14
Sin embargo, que pasaría con la clase CD, le tocaría implementar el método
edad de recomendación (getRecommendedAge()), pero resulta que normalmente
los CD no tienen una edad de recomendación, por lo tanto, se debería de dejar que
no haga nada o lanzar una excepción de la siguiente manera:
Si la interface es implementada por clases que son muy diferentes entre ellos,
clases que son totalmente aparte, las interfaces también deberían estar aparte, es
decir, que cada uno tenga su propia interface, ya que pueden surgir algún cambio y
diferentes partes pueden verse afectadas.
pág. 15
Los cambios pueden aparecer porque el sistema necesita un parámetro más en
uno de los métodos de la interface, entonces, algunas clases que usan estas
interfaces pueden tener problemas, pueden ser que no todas necesitan dicho
parámetro y por consiguiente se tendrán errores. Otra forma de que aparezca un
cambio es que más bien sea a solicitud de uno de los clases, es decir, una clase
determinada necesita que la interface realice ciertas modificaciones en su
definición, de manera que las demás clases también se podrían ver afectados, por
ello, es importante que si se trata de clases distintas sus interfaces estén separadas
y no tener esa dependencia.
Si una clase depende de otra clase que contiene una interface y la primera clase
no la usa, aun así, se tiene una dependencia de esa interface y por lo tanto,
cualquier cambio que pueda ocurrir en la interface también puede afectar a esta
primera clase, ya que si la interface cambia afecta a la clase que la implementa y
por consiguiente la primer clase puede verse afectada.
pág. 16
Door y TimerCliente son interfaces y la clase TimedDoor necesita de ambas
interfaces ya está heredando Door, y una solución para acceder a la otra
interface es definir el objeto DoorTimerAdapter que básicamente lo contendrá
TimedDoor en su definición, de manera que con esa instancia puede invocar
los métodos que tienen el adapter, los cuales son los mismos que TimerClient
ya que hereda de este. Sin embargo, se dice que esta no es la solución más
adecuada.
pág. 17
La fragilidad es la tendencia de un programa a romperse en muchos lugares
cuando se produce un solo cambio hecho. A menudo, los nuevos problemas se
encuentran en áreas que no tienen una relación conceptual con el área que fue
cambiada. Un diseño es inmóvil cuando las partes deseables del diseño son
altamente dependientes sobre otros detalles que no son deseados, si el diseño es
altamente interdependiente, entonces esos diseñadores también se sentirán
intimidados por la cantidad de trabajo necesario para separar la parte deseable del
diseño, en estos casos a veces resulta mejor diseñarlo de nuevo. Lo veremos con
un ejemplo:
Se tiene un módulo Copy el cual hace una copia de caracteres y los escribe en
una impresora, Copy funciona por medio ReadKeyboard y WritePrinter, el primero
permite leer caracteres de teclado, el segundo escribe los caracteres con una
impresora, nótese que estos últimos módulos puede ser reutilizables para accesos
al teclado o impresora, pero el módulo Copy como tal no puede ser reutilizables ya
que funciona únicamente con un teclado y una impresora, es decir, hay una
dependencia de esos dispositivos.
pág. 18
El principio de inversión de dependencias, busca que las clases que están en
un alto nivel no tengan dependencia de las clases de niveles inferiores, ambas
clases deberían de depender de abstracciones, entonces si regresamos al ejemplo,
vemos que la clase Copy depende de sus clases de nivel inferior lo cual está
incumpliendo el principio, por lo tanto, se tiene invertir esa dependencia, para ello,
se debe encontrar alguna forma de que el módulo Copy funcione independiente de
los detalles que controla. Una posible solución es la siguiente:
pág. 19
La programación del diseño queda de la siguiente manera:
Se declara las clases Reader y Writer que tendrán un método virtual, para que
las clases que hereden puedan programar dicho método de la forma que
corresponda.
En este caso, se declara Copy como un método, por lo tanto, tiene que recibir
las dos agregaciones y lo que hace este método es invocar el método Read y Write
de los objetos recibidos sin importar de los detalles, Copy también se pudo haber
hecho como una clase y en su constructor recibir los dos objetos.
Los módulos de alto nivel no tienen que depender de sus niveles inferiores, los
de alto nivel contienen las decisiones políticas importantes, modelos comerciales y
son la identidad de una aplicación. Si lo módulos inferiores cambian, pueden verse
afectados los superiores y esos cambios obligan a que estos también tengan que
cambiar para que se adapten al funcionamiento del sistema, lo cual es absurdo. Son
los módulos de alto nivel los que deberían estar forzando a los módulos de bajo
nivel para cambiar. Son los módulos de alto nivel los que deberían tener prioridad
sobre los módulos de nivel inferior, además, siempre son los módulos de alto nivel
los que se desean reutilizar, por lo tanto, no debe de existir esa dependencia.
Ejemplo
pág. 20
Supongamos que se trata de un sistema de seguridad para el hogar. El objeto
Button detecta que un usuario ha activado o lo desactivó. El objeto de la lámpara
afecta el entorno externo. Al recibir un TurnOn mensaje, ilumina una luz de algún
tipo. Al recibir un mensaje TurnOff, se extingue esa luz. El mecanismo físico no es
importante. Podría ser un LED en una computadora consola, un vapor de mercurio
lámpara en un estacionamiento, o incluso el láser en una impresora láser.
El código de la derecha
representa la programación del
diseño, donde se tiene la clase
Lamp con sus métodos y luego
la clase Button como vemos es
una agregación por lo tanto, se
recibe por parámetro una
instancia de Lamp, y al inicio se
encuentra el “include lamp.h”
esto es lo que representa un
dependencia de la case Lamp,
es decir, Button es una clase de
alto nivel y necesita de una
clase inferior, por lo que se está
violentando con el principio de
inversión de dependencias.
pág. 21
La abstracción subyacente de este caso es detectar un gestor de encendido /
apagado de un usuario y transmitir ese gesto a un objeto objetivo ¿Qué mecanismo
se usa para detectar el gesto del usuario? ¡Irrelevante! ¿Cuál es el objeto objetivo?
¡Irrelevante! Estos son detalles que no afectan la abstracción. Por lo tanto, debemos
aislar esta abstracción de los detalles del problema, entonces nosotros debemos
dirigir las dependencias del diseño tal que los detalles dependan de las
abstracciones.
pág. 22
Este modelo es reutilizable con cualquier tipo de botón, y con cualquier tipo de
dispositivo que necesita ser controlado. Además, no se ve afectado por cambios en
los mecanismos de bajo nivel. Por lo tanto, es robusto en presencia de cambios,
flexible y reutilizable.
Bibliografía
pág. 23