Diseño de los Objetos
3.
Identificación de la concurrencia
4.
Asignación
6.
Administración de los recursos
9.
Algoritmos
10.
Controles
11.
Asociaciones
12.
Bibliografía
El diseño del sistema es la estrategia de alto nivel para resolver problemas y construir una solución. Éste
incluye decisiones acerca de la organización del sistema en subsistemas, la asignación de
subsistemas a componentes hardware y software, y decisiones fundamentales conceptuales y de política
que son las que constituyen un marco de trabajo para el diseño detallado
La organización global del sistema es lo que se
denomina la arquitectura del sistema. Existe un cierto
número de estilos frecuentes de arquitectura, cada uno de los cuales es
adecuado para ciertas clases de aplicaciones. Una forma de caracterizar una
aplicación es por la importancia relativa de sus modelos de objetos, dinámico
y funcional. Las distintas arquitecturas ponen distintos grados de énfasis en
los tres modelos.
El diseño de sistemas es la primera fase de
diseño en la cual se selecciona la aproximación básica para resolver el
problema. Durante el diseño del sistema, se decide la estructura y el estilo global. La arquitectura
del sistema es la organización global del mismo en
componentes llamados subsistemas. La arquitectura proporciona el contexto en el
cual se toman decisiones más detalladas en una fase posterior del diseño. AL
tomar decisiones de alto nivel que se apliquen a todo el sistema, el diseñador
desglosa el problema en subsistemas, de tal manera que sea posible realizar más
trabajo por parte de varios diseñadores que trabajarán independientemente en
distintos subsistemas. El diseñador de sistemas debe tomar las siguientes decisiones:
-
Organizar el sistema en subsistemas
-
Identificar la concurrencia inherente al problema
- Asignar
los subsistemas a los procesadores y tareas
-
Seleccionar una aproximación para la administración de almacenes de datos
- Manejar
el acceso a recursos globales
-
Seleccionar la implementación de control en software
- Manejar
las condiciones de contorno
-
Establecer la compensación de prioridades
En todas
las aplicaciones, salvo en las más pequeñas, el primer paso para diseñar un
sistema consiste en dividir el sistema en un pequeño número de componentes.
Cada uno de los componentes principales de un sistema se llama subsistema. Cada
subsistema abarca aspectos del sistema que comparten alguna propiedad común.
Un subsistema
no es ni una función ni un objeto, sino un paquete de
clases, asociaciones, operaciones, sucesos y restricciones
interrelacionados, y que tienen una interfaz razonablemente bien definida y
pequeña con los demás subsistemas. Normalmente, un subsistema se identifica por
los servicios que proporciona. Un servicio es un grupo de funciones relacionadas que comparten algún
propósito común, tal como el procesamiento de entrada-salida, dibujar imágenes o efectuar cálculos aritméticos. Un
subsistema define una forma coherente de examinar un aspecto del problema.
Cada
subsistema posee una interfaz bien definida con el resto del sistema. Ésta
especifica la forma de todas las interacciones y el flujo de información entre los límites de subsistemas, pero no especifica
cómo está implementado internamente el subsistema. Cada subsistema se puede
diseñar, entonces, independientemente, sin afectar a los demás.
Los
subsistemas deberían definirse de tal manera que la mayoría de las
interacciones se produzcan dentro de y no entre los límites de distintos subsistemas, con objeto
de reducir las dependencias existentes entre ellos. Todo sistema debería
dividirse en un pequeño número de subsistemas. Cada subsistema, a su vez, debe
descomponerse en subsistemas propios aún más pequeños. Los subsistemas de más
bajo nivel se denominan módulos.
La
relación entre dos subsistemas puede ser cliente-proveedor o punto a punto. En las
primeras, el cliente debe conocer la interfaz del
proveedor, pero éste no necesita conocer las interfaces de aquellos porque
todas las interacciones son iniciadas por los clientes, empleando la interfaz del proveedor.
En una relación entre pares, cada subsistema puede llamar a los demás. Una comunicación desde un subsistema hacia otro no
va necesariamente seguida por una respuesta inmediata. Las interacciones entre
pares son más complejas porque los subsistemas deben conocer las interfaces del
otro. Hay ciclos de comunicaciones que son difíciles de entender y
proclives a sutiles errores de diseño. Hay que buscar descomposiciones
cliente-proveedor siempre que sea posible, porque una interacción monodireccional es mucho más fácil de construir, comprender
y modificar que una interacción bidireccional.
Identificación
de la concurrencia
EN el modelo de análisis, al igual que en el mundo real y en
el hardware, todos los objetos son concurrentes.
En una implementación, sin embargo, no todos los objetos del software son concurrentes, porque un procesador puede dar soporte a muchos objetos.
En la práctica, se pueden implementar muchos objetos en un único procesador si los objetos no pueden estar
activados a la vez. Un objetivo importante del diseño del sistema es
identificar los objetos que deben estar activados concurrentemente, y los
objetos que tienen actividad que sea mutuamente exclusiva. Estos últimos
objetos se pueden plegar y juntar en un único hilo de control o tarea.
Cada
subsistema concurrente debe ser asociado a una unidad de hardware, bien a un
procesador de propósito general o a una unidad funcional especializada. El diseñador
del sistema deberá:
- Estimar
las necesidades de rendimiento y los recursos necesarios para satisfacerlas
-
Seleccionar las implementaciones de hardware o de software para los subsistemas
- Asignar
los subsistemas de software a los procesadores para satisfacer las necesidades
de rendimiento y para minimizar la comunicación entre procesadores
-
Determinar las conexiones de las unidades físicas que implementan los
subsistemas.
Los almacenes de datos internos y externos dentro de un sistema
proporcionan puntos limpios de separación entre subsistemas con interfaces bien
definidas. En general, todo almacén de datos puede combinar estructuras de datos, archivos y bases de datos implementados en memoria o bien en dispositivos de almacenamiento secundario. Los
distintos tipos de almacenes de datos proporcionan diversas compensaciones
entre costo, tiempo de acceso, capacidad y fiabilidad.
Los archivos son una forma de almacenamiento de datos barata, sencilla y
permanente. Sin embargo, las operaciones de archivos son de bajo nivel y
las aplicaciones deben incluir un código adicional para proporcionar un nivel de
abstracción adecuado. Las implementaciones de los archivos son distintas según los
diferentes sistemas de computadoras, así que las aplicaciones
transportables deben de aislar cuidadosamente las dependencias con sistemas de
archivos. Las implementaciones para archivos secuenciales son las más comunes,
pero las ordenes y los formatos de almacenamiento para ficheros de acceso aleatorio e indexados varían mucho.
Las bases de datos, que son administradas mediante
sistemas de gestión de bases de datos, son otro tipo de
almacenamiento. Existen varios tipos de sistemas de gestión disponibles comercialmente:
jerárquicos, en red, relacionales, orientados a objetos y
lógicos. Estos sistemas intentan reservar los datos de acceso frecuente en memoria, con objeto de alcanzar la mejor
combinación posible de costo y rendimiento desde y hacia la memoria y el almacenamiento en disco. Las
bases de datos son potentes y hacen que las aplicaciones sean más fáciles de
transportar a sistemas operativos y a distintas plataformas,
por cuanto el vendedor transporta el código del sistema de gestión. Una desventaja
es que tienen una interfaz compleja.
Las
siguientes líneas generales caracterizan el tipo de datos que pertenece a una base de datos formal:
- Datos
que requieran un acceso a niveles finos de detalle por parte de múltiples
usuarios
- Datos
que puedan ser administrados eficientemente mediante ordenes
de un sistema gestor de base de datos
- Datos
que deban transportarse a través de múltiples sistemas operativos y muchas plataformas
hardware
- Datos a
los que deba acceder más de un programa de aplicación
Las
siguientes líneas caracterizan las clases de datos que pertenecen a un archivo y no a una base de datos relacional:
- Datos
que sean voluminosos respecto a cantidad pero difíciles de estructurar en los
confines de un sistema de datos.
- Datos
que sean voluminosos en cantidad y con una baja densidad de formación
- Datos
crudos que estén resumidos en la base de datos
- Datos
volátiles que se mantengan durante un corto periodo de tiempo y se descarten después.
Administración
de los recursos
El
diseñador de sistemas debe identificar los recursos globales y tiene que
determinar mecanismos para controlar el acceso a ellos. Entre los recursos
globales se cuentan: unidades físicas, tales como procesadores, unidades de
cinta y satélites de comunicación; espacio, tal como el espacio en
disco, una pantalla de una estación de trabajo, y los botones de un ratón;
nombres lógicos, tales como la identificación de los objetos, nombres de
archivos y nombres de clases; y el acceso a datos compartidos, tales como bases
de datos.
Si el
recurso es un objeto físico se puede controlar a sí mismo estableciendo un protocolo para obtener el acceso dentro de un
sistema concurrente. SI el recurso es una entidad lógica, tal como la identidad de un objeto, o una base de datos,
existe el peligro de que el acceso produzca conflictos en un entorno compartido. Podría
ser, por ejemplo, que varias tareas independientes utilizasen simultáneamente
la misma identidad de un objeto. Todo recurso global
debe ser poseído por un objeto guardián que controle el acceso a éste. Un
objeto guardián puede controlar varios recursos. Todo el acceso al recurso debe
pasar a través del objeto guardián. Por ejemplo, la mayoría de los
administradores de bases de datos son tareas libres a las cuales invocan otras
tareas para obtener datos de la base de datos. La asignación de cada recurso
global compartido a un único objeto es un reconocimiento de que ese recurso
tiene una identidad.
Un recurso
lógico también se puede descomponer lógicamente, de forma que los subconjuntos
se asignan a distintos objetos guardianes para ser controlados de modo
independiente.
En una
aplicación en la cual el tiempo sea crítico, el costo de pasar todo el acceso a
un recurso a través de un objeto guardián resulta a veces excesivo, por lo que
los clientes deben acceder directamente al
recurso. En este caso, se pueden situar bloqueos en subconjuntos del recurso.
Un bloqueo es un objeto lógico asociado con algún subconjunto definido de algún
recurso que proporciona a quien posea el bloqueo el derecho de acceder
directamente a ese recurso. Sigue siendo necesario que exista un objeto
guardián para asignar los bloqueos, pero tras una interacción con el guardián
para obtener un bloqueo, el usuario del recurso puede acceder directamente al
recurso. Esta aproximación es más peligrosa porque hay que confiar en que todos
los usuarios de recursos se comporten correctamente en su acceso al mismo. El
uso de accesos directos a recursos compartidos no debe de propugnarse en un
diseño orientado a objetos a no ser que resulte absolutamente necesario.
Durante el
análisis, todas las interacciones se muestran
como sucesos entre objetos. El control del hardware se parece mucho al modelo de análisis, aunque el diseñador de
sistemas de be escoger entre varias maneras de implementar el control en
software. Aún cuando no existe una necesidad lógica de que todos los subsistemas utilicen
la misma implementación, lo normal es que el diseñador seleccione un único
estilo de control. Existen dos clases de flujos de control en un sistema de
software: el control externo y el interno.
El control
externo es el flujo de los sucesos externamente visibles entre los objetos del
sistema. Existen tres clases de control para sucesos externos: secuencial,
controlado por procedimientos, secuencial controlado por
sucesos, y concurrente. El estilo de control que se adopte dependerá de los
recursos disponibles y de la trama de interacciones existentes en la
aplicación.
El control interno es el flujo de control dentro
de un proceso. Solo existe en la implementación y,
por tanto, no es inherentemente concurrente ni secuencial. El diseñador puede
decidir descomponer un proceso en varias tareas por claridad lógica o
por rendimiento. A diferencia de los sucesos externos, las transferencias
internas de control, tales como las llamadas a procedimientos o las llamadas entre tareas,
están dirigidas por el programa y se pueden estructurar de la forma
que más convenga. Son frecuentes tres clases de control de flujo: llamadas a
procedimientos, llamadas entre tareas que son casi concurrentes y llamadas
entre tareas concurrentes. Las llamadas entre tareas casi concurrentes, tales
como las corrutinas o procesos ligeros, son conveniencias de programación en las cuales existen múltiples
espacios de direcciones o pilas de llamada, pero en las que solamente
puede estar activo un hilo de control en cada momento.
La fase de
análisis determina lo que debe hacer la implementación y la fase de diseño del
sistema determina el plan de ataque. La fase de diseño de objetos
determina las definiciones completas de las clases y asociaciones que se
utilizarán en la implementación, así como las interfaces y algoritmos de los métodos utilizados para implementar las
operaciones. La fase de diseño de objetos añadirá objetos internos para la
implementación y optimizará las estructuras de datos y los algoritmos. El diseño de objetos es análogo a
la fase preliminar de diseño del ciclo de vida de desarrollo de software tradicional.
Aspectos
generales del diseño de objetos
Durante el
diseño de objetos, se ejecuta la estrategia seleccionada durante el diseño del
sistema y se rellenan los detalles. Se produce un desplazamiento del énfasis
pasando de los conceptos del dominio de la aplicación a los propios de las computadoras. Los objetos descubiertos durante
el análisis sirven como esqueleto del diseño, pero el diseñador debe escoger
distintas formas de implementarlos con el objetivo de minimizar el tiempo de ejecución, la memoria y el costo. En particular, las operaciones
identificadas durante el análisis deben expresarse en forma de algoritmos,
descomponiendo las operaciones complejas en operaciones internas más sencillas.
Las clases, atributos y asociaciones del análisis deben de implementarse en
forma de estructuras de datos específicas. Es necesario introducir nuevas
clases de objetos para almacenar resultados intermedios durante la ejecución
del programa y para evitar la necesidad de recalcularlos. La optimización del
diseño no debería llevarse a extremos exagerados porque la facilidad de
implementación y mantenimiento y la extensibilidad son también objetivos importantes.
Cada
operación especificada en el modelo funcional debe ser formulada como un algoritmo. El análisis de especificaciones
dice lo que hace la operación desde el punto de vista de sus clientes y los
algoritmos muestran cómo se hace. Un algoritmo se puede subdividir en llamadas a
operaciones más sencillas y así sucesivamente, hasta que las operaciones del
nivel más bajo sean suficientemente sencillas para implementarlas directamente
sin más refinamiento.
El
diseñador de algoritmos debe:
-
Seleccionar algoritmos que minimicen el costo de implementar las operaciones
-
Seleccionar estructuras de datos adecuadas para los algoritmos
- Definir
nuevas clases y operaciones internas según sea necesario
- Asignar
la responsabilidad de las operaciones a las
clases adecuadas
El
diseñador debe refinar la estrategia para implementar los modelos de estados y
sucesos presentes en el modelo dinámico. Como parte del diseño del sistema, se
habrá seleccionado una estrategia básica para construir el modelo dinámico.
Durante el diseño de objetos, es necesario desarrollar esta estrategia.
Para
implementar el modelo dinámico hay tres aproximaciones básicas:
- Utilizar
la posición dentro del programa para almacenar el estado (sistema controlado por
procedimientos
-
Implementación directa de un mecanismo de máquina de estados (sistema
controlado por sucesos)
-
Utilización de tareas concurrentes
Las
asociaciones son el pegamento de nuestro modelo de objetos, y proporcionan vías
de acceso entre objetos siendo entidades conceptuales útiles para el modelado y
el análisis. Durante la fase de diseño de objetos hay que formularse una
estrategia para implementar las asociaciones habidas en el modelo de objetos.
Se puede seleccionar una estrategia global para implementar todas las
asociaciones uniformemente o bien seleccionar una técnica particular para cada
asociación, teniendo en cuenta la forma en que será utilizada en la aplicación.
Para tomar decisiones inteligentes acerca de las asociaciones se necesita
analizar primero la forma en que serán utilizadas.
"Modelado
y Diseño Orientados a Objetos"
James Rumbaugh et al
Ed. Prentice Hall 1997
Octavio
Mancilla González
Universidad
Tecnológica de México