Escolar Documentos
Profissional Documentos
Cultura Documentos
Captulo 1
Captulo 2
Captulo 3
Captulo 4
Captulo 5
Captulo 6
UNIVERSIDAD NACIONAL
EXPERIMENTAL DE GUAYANA
SECRETARA
_______________________________________________
Modelo y Programacin Orientado a Objetos
Un efonque prctico
Mauricio Paletta Nannarone
_______________________________________________
Editor
Fondo Editorial UNEG
http://fondoeditorial.uneg.edu.ve
Cuidado de la edicin
Ing. Ana Mara Contreras
Diseo, diagramacin y montaje
TSU. Emerson Guerrero Ibez
Diseo de portada
TSU. Emerson Guerrero Ibez
Coordinacin editorial
Ing. Ana Mara Contreras
Impresin
Copiados Unidos C.A.
Tiraje
100 Ejemplares
Hecho el Depsito de Ley
Depsito Legal: lfx93320140011741
ISBN:
978-980-6864-54-2
Todos los ttulos publicados bajo el sello Fondo Editorial UNEG. Reservados
todos los derechos.El contenido de esta obra est protegido por la ley que
establece penas de prisin y/o multa adems de las correspondientes
indemnizaciones por daos y perjuicios para quienes reproduzcan, plagien,
distribuyan o comuniquen pblicamente en todo una obra literaria, artstica
o cientfica, o su transformacin, interpretacin o ejecucin artstica fijada en
cualquier tipo de soporte o comunicado a travs de cualquier medio sin la
respectiva autorizacin.
Autoridades
Dra. Mara Elena Latuff
Rectora
Dr. Arturo Franceschi
Vice - Rector Acadmico
Dr. Wilfredo Guaita
Vice - Rector Administrativo
Dra. Leonarda Casanova
Secretaria
Dr. Alexnder Mansutti
Coord. General de Investigacin y Postgrado
Dra. Juana Ordaz
Coord. General de Pregrado
Dra. Zulema Melndez
Coord. Gral. de Extensin y Difusin Cultural
PREFACIO
Varios aos de grata experiencia en el rea acadmica en la cual he tenido la oportunidad de
ensear diseo y programacin orientados a objetos, me permiti identificar una necesidad
que lleg a ser la principal motivacin en escribir este libro. Para ese entonces, muchos
estudiantes me consultaron en relacin a alguna bibliografa que explicara la manera en la cual
se tienen que resolver problemas similares a los que usualmente se asignan como trabajos
prcticos en asignaturas en las cuales se ensea a programar, como es el caso particular de
la programacin orientada a objetos.
Si bien es cierto que existe una gran cantidad de bibliografa que abordan temas especficos,
como por ejemplo: 1) usar algn lenguaje de programacin particular (entre los cuales estn
C++, Java y C#); 2) el modelado de problemas con alguna herramienta especfica (por ejemplo
el lenguaje de modelado unificado o UML); 3) el uso de alguna metodologa o mtodo de
resolucin de problemas, entre otros, no se encuentran opciones, al menos en el momento
en la cual fue escrito este libro, que aborden todos estos aspectos en conjunto, es decir, el
modelado y resolucin de problemas utilizando tecnologa orientada a objetos y siguiendo una
metodologa especfica.
En este sentido, los estudiantes que deben resolver problemas prcticos con diferentes niveles
de complejidad, encuentran libros que les ensean a programar en Java, por ejemplo, y a
usar UML, pero no les ensean cmo proceder desde el momento que tienen un enunciado
de algn problema hasta lograr la implementacin orientada a objetos de ese problema. Esta
necesidad de los estudiantes que se les ayude a cmo proceder en la resolucin de los trabajos
prcticos que le son asignados como requisito para aprobar asignaturas relacionadas con
programacin, es el principal objetivo de este libro. En este sentido, este libro es para ustedes
los estudiantes de asignaturas relacionadas con la programacin orientada a objetos; gracias
por haberme dado la oportunidad de descubrir su necesidad; espero haber logrado el objetivo
y haber producido un libro que les ayude tanto como sea posible.
En otro orden de ideas, adems de varias figuras y tablas identificadas con un nmero
consecutivo ordenado por captulo, este libro contiene otra serie de elementos cuyo formato se
muestra a continuacin. Mis notas sobre ciertos aspectos se presentan como sigue:
VOLVER A MEN
Finalmente, una gran cantidad del libro est formado por cdigo fuente de los problemas
resueltos. Cabe mencionar que todos los problemas fueron resueltos haciendo uso tanto
de C++ como de Java y C#. Adicionalmente, en todos los problemas resueltos se incluye el
modelado en UML correspondiente. Se quizo hacer de esta manera para que el libro sea de
utilidad para la mayor cantidad de estudiantes posible. El cdigo fuente se muestra dentro de
una caja gris en la cual los comentarios aparecen en estilo cursiva y las palabras reservadas
del lenguaje en estilo negrilla. A continuacin un ejemplo del formato utilizado.
// Esto es un comentario
//
Palabra reservada
Sentencia
Por otro lado y a fin de evitar que el libro sea muy voluminoso, no se incluye en el texto todo
el cdigo fuente inherente a los problemas resueltos. Se obvian los detalles relativos a la
interfaz. Sin embargo, el libro viene acompaado de un CD con la totalidad de los cdigos. El
CD incluye tambin los diagramas UML y todo el software utilizado para la construccin de los
modelos y los programas.
Este libro est constituido por seis captulos con los siguientes contenidos:
El Captulo 1 presenta una introduccin sobre los orgenes y la razn de ser de la orientacin
a objetos.
En el Captulo 2 se aborda toda la fundamentacin terica inherente a la orientacin a
objetos.
El Captulo 3 describe el lenguaje de modelado unificado o UML.
La programacin orientada a objetos haciendo uso de los lenguajes de programacin C++,
Java y C# se encuentra en el Captulo 4.
En el Captulo 5 se describe un proceso metodolgico para la resolucin de problemas bajo
5
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
CONTENIDO
Prefacio
Captulo 1
El origen de la Orientacin a Objetos
1.1 Introduccin
1.2 Descomposicin
1.3
Abstraccin
1.4 Jerarqua
1.5
1.6
Algo de historia
1.7 Ejercicios
11
14
14
16
16
17
21
25
Captulo 2
28
2.1 Introduccin
28
2.2 Principios de la OO 28
2.3 Trmino tcnico
38
2.4 Conceptos bsicos de la OO
39
2.5 Ejercicios
50
Fundamentos tericos de la Orientacin a Objetos
Captulo 3
UML: El Lenguaje de Modelado Unificado
3.1
Introduccin
3.2
Componentes
3.3
Diagramas
3.4
Mecanismos Generales
3.5
Resumen de la sintaxis
3.6
Ejercicios
VOLVER A MEN
54
54
55
57
82
84
85
Captulo 4
La programacin Orientada a Objetos
4.1 Introduccin
4.2
Definicin de clases
4.3
Instanciacin de objetos
4.4
4.5 Constructor
4.6
Polimorfismo
4.7
4.8 Destructor
4.9
Elementos estticos
90
90
92
96
98
99
101
103
105
106
110
112
116
118
127
128
131
144
Captulo 5
Una metodologa Orientada a Objetos
5.1 Introduccin
5.2
Anlisis OO
5.3
Diseo OO
5.4 Resumen
5.5 Ejemplo
5.6 Ejercicios
148
148
150
158
162
163
171
Captulo 6
Modelado y programacin de problemas
6.1 Introduccin
6.2
6.3
6.4
6.5
172
172
173
219
240
297
6.6
El generador de energa
6.7
La fbrica de galletas
6.8
6.9
ndice de Tablas
743
746
755
ndice
756
10
390
416
459
513
647
732
VOLVER A MEN
CAPTULO 1
VOLVER A MEN
Haber usuarios insatisfechos con los sistemas y con los departamentos o grupos de desarrollo que se preguntan: Por qu el desarrollo de software es tan costoso? Por qu
toma tanto tiempo? Hay alguna perspectiva de mejora?
Como bien lo dijo Brooks en su momento, sobre esta crisis en la cual lleg a estar el desarrollo
de software, es una propiedad esencial, no accidental (Brooks, 1987), es natural que
esto haya ocurrido y, gracias a ello hubo respuestas para tratar este fenmeno. Una de las
primeras respuestas tiene que ver con analizar la complejidad como caracterstica inherente
del desarrollo del software que, segn Booch, es necesario entenderla y administrarla (Booch,
1996). En este sentido, este autor identifica cuatro factores que influyen en la complejidad del
software:
1) Complejidad del dominio del problema:
Problemas que involucran elementos de gran complejidad (muy especficos) versus problemas
que involucran elementos simples (ms conocidos y comunes).
Existencia de requerimientos contradictorios cuando hay varios usuarios involucrados en el
problema.
Distancia entre el usuario y el desarrollador lo que genera diferentes perspectivas del problema.
2) Dificultad de administrar el proceso de desarrollo:
Se quiere dar la ilusin de simplicidad pero no lo es.
Manejo de un grupo de trabajo y los posibles problemas de comunicacin, coordinacin e
integracin que pudieran haber.
3) Flexibilidad exigida al software:
Eficiencia (tiempo de respuesta) versus eficacia (calidad en la respuesta).
Optimizacin de recursos versus calidad en la respuesta.
El usuario quiere que se haga todo, que todo se haga bien y, que adems no haya que pagar
mucho por ello (bueno, bonito y barato).
4) Problemas que plantean la caracterizacin del comportamiento de sistemas discretos:
Administracin de la cantidad de elementos (variables, estructuras, funciones, entre otras) que
pueden haber en un programa de cierta envergadura.
Relacionado con el mantenimiento del software, el cual puede ser de tres tipos:
o Correctivo: corregir errores en los programas (20 % del tiempo total que se dedica al
mantenimiento).
o Adaptativo: implementar cambios en los requerimientos producto de una adaptacin a los
mismos (25 % del tiempo total que se dedica al mantenimiento).
o Perfectivo: tratar de mantener el software lo ms actualizado posible en base a los avances
tecnolgicos, a fin de garantizar su continuidad operativa (55 % del tiempo total que se
dedica al mantenimiento).
12
VOLVER A MEN
En este mismo orden de ideas, a medida que aument la complejidad del software requerido,
se redujo proporcionalmente las habilidades para manejar la complejidad inherente a ste,
agravando entonces el problema de la crisis del software. Esta problemtica agravada lleg
a caracterizarse como una situacin de desorden y descontrol hasta el punto de asociarse o
identificarse con el concepto que los fsicos dan a los sistemas en desorden, es decir, caos.
La llegada del caos al desarrollo de software y, por ende tratar esta situacin, origin una
reaccin de parte de los entes interesados que se puede resumir en las siguientes acciones:
Tratar el software como una ingeniera.
Promover el uso de metodologas estructuradas.
Promover una mayor participacin del usuario en las etapas de desarrollo.
Realizar pruebas planificadas y documentadas.
Promover el uso de herramientas automatizadas para el control de los desarrollos.
El esfuerzo del mundo cientfico para sacar al desarrollo de software del caos plante entonces
un nuevo paradigma de visualizacin de los proyectos de desarrollo de software que implica
la realizacin de tres cosas: descomposicin, abstraccin y jerarqua. Posteriormente, a este
nuevo paradigma de hacer software se le dio el nombre de Orientacin a Objetos.
Figura 1.1. Hacer descomposicin, abstraccin y jerarqua para salir del caos
(imagen realizada por Juan C. Candelori / www.pietrogiordano.info).
13
VOLVER A MEN
1.2 Descomposicin
La tcnica de dominar la complejidad se conoce desde tiempos remotos: divide et impera
(divide y vencers) (Dijkstra, 1979). La descomposicin de un problema basado en un
sistema de software se fundamenta en esta tcnica. A medida que el problema o sistema es
ms complejo, es esencial descomponerlo en partes, cada una de las cuales con un nivel de
complejidad menor al problema total, de manera tal que a la hora de resolver el problema,
es decir hacer el sistema, el impacto de algo muy complejo se reduce al impacto de varios
sub-problemas de complejidad no tan alta. La solucin del problema macro ser entonces la
integracin de las partes. Para entender un nivel dado de un sistema, basta con comprender
unas pocas partes a la vez, la descomposicin del todo en sus partes permite disminuir la
complejidad inherente al software (Dijkstra, 1979).
Es necesario hacer una divisin inteligente del problema, ya que los dos extremos posibles no
son adecuados: 1) tener partes con una complejidad que sigue siendo alta y que pueden ser
descompuestas an ms (quedarse muy arriba); 2) tener partes con una complejidad casi nula
que indica que se descompuso ms de la cuenta (quedarse muy abajo). En el primer caso se
pierde la principal ventaja de descomponer: reducir la complejidad para tener una visin ms
simple del problema y permitir as que ste sea resuelto adecuadamente. El segundo caso
puede llevar a la generacin de muchos mdulos que por su cantidad, pueden hacer ms difcil
el proceso de integracin.
De manera de ejemplo y para entender mejor lo dicho anteriormente, suponga que se tiene
el problema de hacer un vehculo automotor. Una primera descomposicin de este problema
nos puede llevar a las siguientes partes: motor y sistemas mecnicos, carrocera y accesorios
incluyendo el tablero, chasis, sistema elctrico, resto de elementos. Est claro que cada una
de estas partes, en particular el motor y sistemas mecnicos, puede ser descompuesto en s
mismo en otro conjunto de partes. Ntese que la integracin (o ensamblado) de un vehculo
teniendo cada una de las partes antes identificadas es ms sencillo que tener todas las subpartes de cada parte juntas. En otras palabras, no es lo mismo tener el motor listo para ser
usado como una parte del vehculo que tener todas las partes del motor para resolver el mismo
problema. Un problema es hacer el vehculo y para ello se ha identificado que una de sus
partes es el motor; otro problema es hacer el motor y para ello se han identificado otro conjunto
de partes. La Figura 1.2 muestra una ejemplificacin del caso anterior y en la cual se observa
al robot OO ensamblando otros robots.
14
VOLVER A MEN
15
VOLVER A MEN
1.3 Abstraccin
Una de las tareas que se deben hacer cuando se quiere descomponer un problema en partes,
con el objeto de administrar o reducir la complejidad del problema, es identificar esos elementos
potenciales que van a representar cada una de esas partes. Para ello es conveniente basarse en
conceptos conocidos, en ignorar los detalles no significativos de cada elemento. La abstraccin
es esta capacidad para adquirir conceptos que, combinada con la descomposicin brinda un
enorme poder para manejar la complejidad de los problemas.
Hacer una adecuada conceptualizacin del dominio del problema y/o definir tipos abstractos
de datos son ejemplos de actividades que tienen que ver con la abstraccin.
1.4 Jerarqua
Muchos de los conceptos que han sido identificados haciendo uso de la abstraccin con
miras de lograr una adecuada descomposicin del problema, pueden relacionarse entre s
de manera de lograr definir uno de estos conceptos basado en la existencia de otros. La
adecuada identificacin de estas relaciones permite lograr una organizacin de los conceptos
que, no slo incrementa el contenido semntico de las piezas de informacin identificadas,
sino que tambin ayuda a la comprensin del funcionamiento del sistema. Por otro lado, es de
gran ayuda a posteriori para la adecuada implementacin de los conceptos.
Por un lado, los conceptos pueden ser organizados en niveles de categora mediante una
relacin semntica del tipo caso particular de. A este tipo de relacin se le suele llamar una
generalizacin y su objetivo es especializar un concepto basado en la existencia de otros
menos generales. Algunos ejemplos de este tipo de relacin son:
Trabajador es un caso particular de Persona.
Mamfero es un caso particular de Animal.
Vehculo automotor es un caso particular de Vehculo.
Una recomendacin para saber si un concepto C1 es un caso particular de otro concepto C2,
es considerar el hecho que C1 es un C2 con algunos elementos adicionales. Por ejemplo, un
Trabajador es una Persona con un salario y posiblemente algo ms; un Mamfero es un Animal
con sangre caliente y posiblemente algo ms; un Vehculo automotor es un Vehculo que tiene
un motor y posiblemente algo ms.
16
VOLVER A MEN
Por otro lado, los conceptos se pueden organizar mediante la composicin o agregacin
entre ellos a travs de una relacin semntica del tipo forma parte de. El objetivo es agregar
conceptos como elementos de otros conceptos que tienen una definicin ms compleja.
Algunos ejemplos de este tipo de relacin son:
Trabajador forma parte de una Empresa.
Disco duro forma parte de una PC.
Motor forma parte de un Vehculo automotor.
Una recomendacin para saber si un concepto C1 forma parte de otro concepto C2, es
considerar el hecho que para que C2 exista, ste puede o no requerir de uno o ms elementos
del tipo C1. Es importante notar en la oracin anterior, el uso de puede o no y de uno o
ms. Esto quiere decir que la inclusin de C1 en C2 es opcional y que esta relacin puede
implicar que varios elementos de C1 pueden estar en C2. En la literatura se suele llamar a
la inclusin no obligatoria composicin; mientras que a la inclusin obligatoria se le suele
llamar agregacin. En general, a la cantidad de elementos de un mismo concepto que estn
relacionados o asociados con otro concepto se le denomina multiplicidad. Por ejemplo, est
claro que 1 o ms Trabajadores pueden formar parte de una Empresa. Lo mismo ocurre con
el Disco duro y una PC, ms an, pudiera concebirse la existencia de una PC sin Disco duro,
por lo que esta relacin puede verse como opcional. Con respecto al ejemplo Motor forma
parte de un Vehculo automotor, es notorio el hecho que no existe un Vehculo automotor sin
un Motor por lo que esta relacin es definitivamente obligatoria.
17
VOLVER A MEN
Descomposicin
Abstraccin
Jerarqua
VOLVER A MEN
19
VOLVER A MEN
Descomposicin funcional
Orientacin a Objetos
Encapsulamiento / Mensajes
Diagramas jerrquicos de clases
20
VOLVER A MEN
1957
1967
1970
1970
1975
1976
1977
1980
1986
1986
21
VOLVER A MEN
1988
1989
1989
1990
1990
1990
1996
2000
Haciendo un anlisis de la Tabla 1.3, es posible dividir la historia de la OO en las cuatro fases
que se muestran en la Tabla 1.4. Ntese que de un enfoque inicial orientado principalmente
en la programacin, la OO evoluciona a otros enfoques como la interfaz grfica, las bases de
datos, la Inteligencia Artificial y el modelado.
Fase I
Fase II
Fase III
Fase IV
dcada de los
70 (poca de
invencin)
Simulacin de
sucesos discretos
dcada de los
80 (poca de
confusin)
Interfaces
WIMP
dcada de los
90 (poca de
madurez)
nfasis en el
anlisis y el diseo
Simula
Xerox y Apple
Kay: mquina
FLEX
Extensiones
LISP
Sistemas abiertos
Aplicaciones
PARC: Dynabook
Entornos de
Inteligencia
Artificial
Nuevos lenguajes: Eiffel,
C++, Java
Smalltalk
22
VOLVER A MEN
Bases de datos
OO
Estndares
Bsqueda de niveles
ms altos de abstraccin (Agentes,
cubos, etc.)
C#
Paradigma de todas
las plataformas de
desarrollo
UML
La OO ha tenido mucho auge desde sus inicios llegando a convertirse en un estndar para
el desarrollo de productos de software. Una prueba de ello es la evolucin que han tenido
los lenguajes de programacin desde Fortran, considerado como el primer lenguaje de
programacin de alto nivel. La Figura 1.4 muestra esta evolucin; ntese que los lenguajes
encerrados en un rectngulo son no OO mientras que los que estn encerrados en un valo si
son OO. Como puede verse en la Figura 1.4, todos los lenguajes creados desde los inicios de
1980 hasta la actualidad son OO.
En otro orden de ideas y, dado el hecho de la existencia en la dcada de los 90s de muchos
lenguajes de modelado basados en OO utilizados principalmente para cubrir necesidades de
anlisis y diseo, surgi la intencin de buscar un estndar o unificacin en este sentido. El
resultado fue UML (Lenguaje de Modelado Unificado). La Figura 1.5 muestra la evolucin de
los lenguajes de modelado OO hasta UML, estndar universalmente aceptado hoy en da.
23
VOLVER A MEN
24
VOLVER A MEN
1.7 Ejercicios
1) Explique brevemente por qu surge la OO? Qu significa hacer OO?
2) Identifique las caractersticas resaltantes que describen la evolucin histrica de la OO,
desde los aos 70 hasta los aos 90.
3) Por qu se da el fenmeno de la complejidad del software?
4) Identifique y explique los elementos que dieron origen a la OO.
5) Cul fue el aporte de Simula en la evolucin histrica de la OO?
6) Cules tres puntos se proponen para traer orden al caos en la Ingeniera de Software?
a) Descomposicin, abstraccin y jerarqua.
b) Objeto, clase y herencia.
c) Anlisis, diseo y programacin OO.
d) Ninguna de las anteriores.
7) Cul de las siguientes observaciones relativas a la evolucin histrica de la OO es falsa?
a) Simula fue el primer lenguaje con estructuras OO.
b) Primero hubo inters por el diseo OO y luego por la programacin.
c) GUI es un concepto importante en la historia de la OO.
d) Todas las observaciones son verdaderas.
8) La abstraccin es: ?
a) La capacidad de adquirir conceptos.
b) La capacidad de construir jerarquas de generalizaciones.
c) Ninguna de las anteriores.
d) Tanto la opcin (a) como la (b).
9) Entre los conceptos Equipo y Jugador se puede establecer una relacin del tipo: ?
a) Jerarqua: Caso-particular-de.
b) Agregacin: Parte-de.
c) Ni (a) ni (b).
d) Tanto (a) como (b) dependiendo del contexto.
10) Entre los conceptos Pieza de Ajedrez y Piezas Negras se puede establecer una relacin
del tipo: ?
a) Jerarqua: Caso-particular-de.
25
VOLVER A MEN
b) Agregacin: Parte-de.
c) Ni (a) ni (b), se trata de una instancia particular.
d) Tanto (a) como (b) dependiendo del contexto.
11) Cul de los siguientes fenmenos relativos al software fue importante para que se originara
la OO?
a) La aparicin del computador personal.
b)
12) Cules tres puntos propone la Ingeniera de Software para traer orden al caos?
a) Descomposicin, abstraccin y jerarqua.
b) Objeto, clase y herencia.
c) Anlisis, diseo y programacin OO.
d) Ninguna de las anteriores.
13) Cul de los siguientes lenguajes de programacin fue el primero en tener estructuras
OO?
a) Simula.
b) Pascal.
c) C++.
d) Java.
14) Indique si las siguientes afirmaciones relativas a la evolucin histrica de la OO son
verdaderas falsas.
a) El lenguaje de programacin Simula fue el primero en definir estructuras OO.
b) Primero hubo inters por el diseo OO y luego por la programacin.
c) A medida que pasa el tiempo hay mayor inters en aumentar los niveles de abstraccin.
d) C# es uno de los primeros lenguajes de programacin OO, precursor de C++.
15) Con los siguientes conceptos que se enumeran a continuacin, indique las relaciones de
composicin o agregacin (forma parte de) y las relaciones de generalizacin (caso
particular de)
a) Circuito electrnico, resistencia, condensador, resistencia de 100 K, resistencia de 10 K,
condensador de 1 microfaradio, componente electrnico, circuito integrado, transistor.
26
VOLVER A MEN
27
VOLVER A MEN
Captulo 2
2.2 Principios de la OO
La Abstraccin. El mundo que nos rodea est completamente representado por conceptos:
persona, mesa, vehculo, pelota, rbol, empresa, universidad, estudiante, son alguno de los
innumerables ejemplos que se pueden citar. No es error decir entonces que todo problema
particular que requiera ser modelado, estudiado o resuelto, tambin tenga que ver con un
conjunto de conceptos. El principio de abstraccin determina la capacidad para adquirir los
conceptos necesarios y suficientes involucrados en el entorno del problema que se quiere
modelar. Es importante tener en cuenta que los conceptos son ideas particulares o lo que
vemos y comprendemos del mundo que nos rodea.
Hacer un breve anlisis de la complejidad de los conceptos o elementos involucrados en
el problema es una sugerencia para hacer abstraccin. Si se tiene la conviccin de que un
28
VOLVER A MEN
concepto tiene un nivel alto de complejidad y ste puede ser descompuesto en otros conceptos,
la abstraccin permite entonces identificar otros conceptos involucrados. Por ejemplo, un
vehculo automotor tiene la suficiente complejidad para observar en l otros conceptos como
el motor, el sistema elctrico, el chasis, entre otros.
Nota: La abstraccin es una forma de manejar la complejidad de los objetos.
Una segunda recomendacin a tener en cuenta para hacer una adecuada abstraccin, tiene
que ver con el acto o resultado de eliminar diferencias entre los conceptos, es decir, que se
puedan ver los aspectos comunes y no comunes. Por ejemplo, en el modelado de un problema
relacionado con un entorno universitario, es casi seguro que como resultado de la abstraccin
del problema se identifiquen los conceptos de profesor y estudiante. Al observar estos dos
conceptos, es notorio el hecho que hay varios aspectos comunes: un nombre, un documento
de identidad, un sexo, nacer, vivir y morir. Tambin es claro que hay diferencias, como por
ejemplo el hecho que un profesor tiene un rango acadmico mientras que un estudiante tiene un
nmero de crditos inscritos. Ahora bien, es correcto el haber decidido en tener los conceptos
de profesor y estudiante, no hacer sin embargo nada en relacin a los aspectos comunes es
un error. Ntese que lo que profesor y estudiante tienen en comn es que ambos son tipos
particulares de persona. Es decir, la aparicin de un tercer concepto (persona) permite abordar
este hecho de la existencia de aspectos comunes entre los dos conceptos previos (profesor
y estudiante). Al modelar un problema como el antes ejemplificado, en posteriores anlisis y
aplicando otros principios, como por ejemplo el de Jerarqua, para casos como este es posible
determinar las relaciones entre profesor y persona y entre estudiante y persona.
Hacer slo nfasis sobre los detalles importantes relativos al contexto que se est modelando
y dejar por alto los aspectos no relevantes, es otro criterio a tener en cuenta cuando se hace
abstraccin. Por ejemplo, si el contexto a tratar es el vehculo automotor y se ha identificado el
motor como un concepto propio de este problema tratado, no se requiere identificar al pistn del
motor como un concepto ya que no tiene relevancia para el vehculo automotor. Sin embargo,
si ahora el contexto a modelar es el motor entonces un pistn s tiene relevancia.
Nota: La abstraccin se implementa mediante la definicin de clases.
El Encapsulamiento. Encapsular significa encerrar, proteger, esconder. El objetivo con este
principio es buscar no hacer visible a los usuarios finales de los objetos, todos los detalles
correspondientes que no contribuyen al entendimiento de las caractersticas esenciales de
esos objetos. Por ejemplo, imaginemos que un televisor o cualquier otro aparato electrnico,
estuviera sin la carcasa que protege la electrnica y circuitos del aparato. Cmo se puede
garantizar que el usuario utilice correctamente el aparato electrnico de esta manera? Est
claro que el aparato se construye tomando en cuenta lo que un usuario final del mismo puede
29
VOLVER A MEN
y no puede ver y tocar. La misma situacin ocurre con la definicin de los conceptos en OO.
El principio de encapsulamiento se refiere entonces a la capacidad para determinar qu
informacin debe estar escondida y cul no debe de estarlo. Se refiere a incluir dentro de un
objeto todo lo que ste necesita y hacerlo de forma tal que ningn otro objeto vea su estructura
interna. Ntese que, de la misma manera que ocurre con el televisor en el ejemplo antes descrito,
llevar este enfoque a la programacin permite proteger los datos para que stos no sean
usados de manera arbitraria. Esto, adems, tiene una influencia positiva en el mantenimiento
de los programas, ya que al encapsular informacin, los cambios a los programas pueden
ser realizados con menos esfuerzo comparado con los enfoques tradicionales (no OO) de
programacin.
Respetar este principio tiene que ver con el hecho de no hacer visible (pblico) algo que
debe estar escondido (privado / protegido) y viceversa. Ntese que los dos extremos son
completamente indeseables. Es decir, tener todos los elementos pblicos es hacer lo mismo
que se haca antes de la llegada de la OO (es decir, caos como fue descrito en el Captulo
1); tener todos los elementos privados es como comprar una caja negra que no tiene ninguna
interaccin con el usuario (imagnese comprar un televisor que no tenga un botn para
encenderlo). En trminos de la OO, la visibilidad de los elementos de los objetos se denomina
interfaz del objeto o interfaz de los elementos de la clase.
No existe una frmula que pueda ser usada para determinar cunta de la informacin de un
objeto debe ser pblica y/o saber qu informacin debe ser pblica y cul debe ser privada.
Esto depende en gran medida del concepto relacionado con el objeto. Hay que tomar en
cuenta que, muy poca informacin y comportamiento pblico permite que el objeto sea simple
de usar pero puede limitar la flexibilidad y funcionalidad que se le quiera dar al objeto. Por el
contrario, mucha informacin o comportamiento pblico aumenta la complejidad de uso del
objeto, as como tambin la flexibilidad y uso del mismo. Por ejemplo, considere un televisor
donde la nica interfaz con el usuario sean tres botones: un botn para encender y apagar
el televisor, un botn para subir y bajar el volumen y un ltimo botn para cambiar de canal.
Ntese que un televisor con estas caractersticas es simple de usar, pero no es posible hacer
otras operaciones como por ejemplo la configuracin de la imagen, subir y bajar el volumen de
manera indistinta, cambiar de canal hacia arriba o hacia abajo del canal actual. Por el contrario,
imagnese ahora un televisor que contiene centenares de botones que le permiten hacer lo que
usted quiera con l. Es evidente que en este ltimo caso usar el equipo es ms complejo.
Una recomendacin es hacer un anlisis cerrado de cada concepto por separado y determinar
30
VOLVER A MEN
la sensatez o no de tener cierto dato u operacin pblico o privado en el contexto del problema
tratado. Por ejemplo, supngase se tiene un concepto para representar una persona y uno de
los datos asociados a la persona es el nombre; es de suponerse que cuando un objeto que
representa a una persona es creado, ste debe tener obligatoriamente un nombre asociado; la
pregunta a hacerse entonces es, puede el nombre de una persona ser cambiado luego que a
esta persona se le haya asignado un nombre en el momento de su creacin?
La Modularidad. La modularidad o resolucin de un problema basado en mdulos trata,
en esencia, de la descomposicin de un problema o sistema en un conjunto de unidades
discretas. Tiene mucho que ver con las ya conocidas programacin modular y programacin
estructurada. En conjunto con la abstraccin, que permite identificar las clases necesarias para
modelar el problema, la modularidad permite visualizar qu unidades indivisibles o mdulos
son requeridos para satisfacer las necesidades del problema. Estas unidades discretas son
los objetos. Esta relacin de creacin de objetos basado en clases se conoce con el nombre
de instanciacin de objetos.
De la referencia (Meyer, 1998) es posible extraer cinco criterios, cinco reglas y cinco principios
asociados a la modularidad que se resumen a continuacin.
Criterio 1 - Descomposicin modular: tiene que ver con la descomposicin del problema
de software en un pequeo nmero de sub-problemas menos complejos. Todas las partes se
interconectan mediante una estructura sencilla y suficientemente independientes para permitir
que el programa pueda seguir creciendo con facilidad (sin padecer problemas de dependencia
con los elementos existentes). Un ejemplo de ello lo representa el diseo top-down (desde
la visin macro a las visiones micros del problema); como contraejemplo se puede citar la
inicializacin global, ya que sta provoca una dependencia obligatoria entre el punto de
declaracin y el uso de las declaraciones.
Criterio 2 - Composicin modular: Favorece la produccin de elementos que se pueden
combinar libremente unos con otros para producir nuevos elementos, posiblemente en un
entorno bastante diferente de aqul en que fueron desarrollados inicialmente. Como ejemplo
se tiene la biblioteca de subprogramas y un contraejemplo es el uso de preprocesadores
(sentencias que se requieren ejecutar antes que se realice la compilacin y ejecucin de los
programas).
31
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
El uso de jerarquas no slo permite organizar los conceptos que resultan de la abstraccin
sino que adems, permite simplificar el entendimiento del problema.
Los Tipos. Mediante los tipos es posible agrupar o formar un conjunto de objetos con
caractersticas o comportamientos similares. La declaracin de variables de un tipo especfico
(entero, carcter, booleano) es una analoga de lo que establece este principio. Usar
correctamente este principio implica tener en cuenta que dos cosas que tienen la misma forma
abstracta son anlogas y, por lo tanto, son del mismo tipo.
Hay dos maneras en las cuales es posible no respetar este principio. En primer lugar, considerar
un concepto no como un tipo sino como un objeto. Por ejemplo, decir que persona es un
objeto que tiene una informacin asociada en lugar de decir que se trata de un tipo (una
clase) que permite instanciar tantos objetos como se desee. Supngase que en un problema
particular se requieren representar a dos personas A y B; si no existe un tipo asociado a
persona no se podrn considerar A y B como dos objetos diferentes del mismo tipo, la clase
que representa a persona en este caso. Irse por este camino implicara necesariamente definir
dos conceptos en lugar de uno, es decir, se requieren los conceptos persona-A y persona-B
que, muy probablemente tendrn una misma definicin.
La segunda manera en la cual es posible no respetar este principio tiene que ver con confundir
o creer que los datos que forman parte de un concepto o tipo es otro concepto diferente.
Dependiendo del contexto del problema que se est tratando, el nombre de una persona, por
ejemplo, es un dato asociado a la persona y no otro concepto.
34
VOLVER A MEN
La Concurrencia. Es la propiedad que distingue un objeto activo de uno que no lo es. Permite
a diferentes objetos actuar al mismo tiempo y asumir el hecho que cada uno de ellos tiene su
propia autonoma. Usar correctamente este principio tiene que ver con el hecho de asumir que
los objetos pueden ser instanciados a medida que stos sean requeridos.
35
VOLVER A MEN
VOLVER A MEN
Ahora bien, lo anterior es slo una manera de hacer polimorfismo. Supongamos el siguiente
otro ejemplo; se desea implementar un nmero Complejo y, en esta implementacin, se desea
contar con la operacin de suma. Haciendo uso del paradigma no OO, la manera de implementar
la operacin de suma es definiendo una funcin del tipo C3 = Sumar(C1, C2), siendo C1, C2 y
C3 del tipo Complejo y Sumar la operacin para implementar la suma. Esto no tiene problema
alguno, sin embargo, cul es el smbolo que todo usuario reconoce como una suma? Est
claro que la respuesta es +. Ntese que sera muy deseable que la implementacin anterior
pudiera hacerse utilizando el smbolo +, es decir, C3 = C1 + C2. La buena noticia es que en
la OO esto s es posible haciendo uso de un tipo particular de polimorfismo conocido como
sobrecarga de operadores.
En general, existen cuatro maneras diferentes de hacer polimorfismo:
1) Especfico: Relativo a smbolos conocidos:
1.1) Coaccin: una abstraccin simple sirve como diferentes tipos mediante una
conversin de tipos implcitas.
2.1) Sobrecarga: Un identificador simple denota muchas abstracciones.
2) Universal: Relativo a operaciones con identificadores propios:
1.1)
2.1) Por parmetro: Una abstraccin opera uniformemente a travs de diferentes tipos.
3.1) Por inclusin: Una abstraccin opera a travs de una relacin de inclusin.
El polimorfismo especfico de coaccin es lo que ocurre, por ejemplo, en varios lenguajes de
programacin de alto nivel en la cual un mismo smbolo, como por ejemplo +, -, *, puede
ser usado por tipos de datos diferentes predefinidos en el lenguaje: entero, real, carcter,
booleano, cadena de caracteres, entre otros. El polimorfismo especfico por sobrecarga es
el que permite hacer lo ejemplificado anteriormente con Complejo. El polimorfismo universal
por parmetro es aqul que permite hacer lo relativo al ejemplo del Robot. Finalmente, el
polimorfismo universal por inclusin se da en una relacin de herencia de clases y va a ser
explicado ms adelante en este captulo.
37
VOLVER A MEN
VOLVER A MEN
Nota: Desde muy temprana edad el ser humano aprende mediante el reconocimiento
de objetos. Por lo tanto, la OO es una manera ms natural de describir y entender
un problema.
Desde la perspectiva de un programa, los objetos son mdulos que contienen datos (atributos)
y las instrucciones u operaciones (mtodos) que operan sobre esos datos y trabajan juntos
para proveer funcionalidad. Conceptualmente hablando, los objetos tienen las siguientes tres
caractersticas: estado, identidad y comportamiento.
El estado de un objeto es aqul que contiene todas las propiedades del objeto dadas estas por
sus atributos (definidos usualmente de manera esttica), adems de los valores actuales de
estas propiedades (dados usualmente de manera dinmica). Esta combinacin de atributos y
valores hace que cada objeto sea nico y, adicionalmente, la respuesta que un objeto puede
dar en cualquier instante luego de su creacin y posteriormente de la llamada de un mensaje,
depende de este estado actual que el objeto tenga.
39
VOLVER A MEN
Nota: Esta caracterstica del objeto determina cmo son los nodos en un diagrama
de transicin de estados del objeto (ver UML en Captulo 3).
Algunos ejemplos de posibles atributos para un objeto son: color, peso, edad, nmero de tems,
profesin. Posibles valores respectivos que estos atributos pueden tener son: rojo, 75.4 Kg, 24
aos, 190, arquitecto. Luego, un estado posible de un objeto cualquiera con las caractersticas
(atributos) antes mencionadas es aqul en la cual: color = rojo, peso = 75.4, edad = 24, nmero
de tems = 90 y profesin = arquitecto.
Nota: El estado de un objeto est ntimamente relacionado con el principio de
persistencia.
La identidad de un objeto es aquella que permite distinguir un objeto del resto. Es completamente
no dependiente del estado en el sentido que, aun y cuando se realicen cambios de estado, la
identidad se conserva durante toda la vida del objeto. Por otro lado, la identidad o identificador
del objeto es la base para construir o armar un mensaje hacia el objeto correspondiente (ms
detalles aparecen a continuacin). X1, X2, MiVentana y Mauricio_Paletta son ejemplos de
posibles identidades para objetos.
Nota: La identidad de un objeto est ntimamente relacionada con el principio de
concurrencia.
Nota: La identidad de un objeto es una propiedad muy importante para las Bases
de Datos Orientadas a Objetos (OODB de sus siglas en ingls Object-Oriented
DataBase) (Atwood, 1985) (Derrett et al, 1985) (Maier et al, 1985).
VOLVER A MEN
Por otro lado, el Mensaje es el canal de comunicacin que usan los objetos para ejecutar
acciones. Por lo tanto, slo cuando se recibe un mensaje, el objeto ejecuta una accin (un
mtodo). En este sentido, todo proceso es activado por mensajes entre objetos. La identidad
del objeto permite direccionar el mensaje al objeto especfico deseado.
A fin de garantizar la proteccin de los elementos privados de los objetos, es decir, respetar el
principio de encapsulamiento, es muy comn observar en la literatura un par de mtodos para
leer o cambiar el estado del objeto (es decir, sus atributos). Por lo general estos mtodos son
identificados como Obtener o Get para leer el estado y Asignar o Set para cambiar el estado
(ver Figura 2.3).
41
VOLVER A MEN
Tal como se puede observar en la Figura 2.3, un objeto suele representarse como una fortaleza
(encapsulamiento) que rodea y protege principalmente a la data (atributos), y slo los mtodos
son las llaves para abrir las puertas de entrada / salida de la fortaleza. Luego, para poder entrar
a la fortaleza haciendo uso de alguno de los canales de entrada o llaves representados por los
mtodos, se requiere un mensaje correspondiente.
Nota: El comportamiento de un objeto est ntimamente relacionado con los principios
de encapsulamiento y polimorfismo.
Nota: Dado la analoga que se le da a los mensajes entre objetos con los sistemas de
comunicacin, se define el protocolo de un objeto como el conjunto de mensajes a los
cuales un objeto responde o puede responder. Ntese que esto no necesariamente
es igual al conjunto de mtodos del objeto (producto del encapsulamiento en la cual
pueden existir mtodos no pblicos y el polimorfismo en el cual pueden existir varios
mtodos que se denominan igual pero para efectos de los mensajes que se pueden
enviar, es uno solo).
La Clase. En la OO, la clase es la que define la estructura y el comportamiento de una forma
abstracta o concepto para darle vida a los objetos. Es trminos bsicos y generales, se trata
de un patrn (plantilla) que define los atributos y mtodos a ser incluidos en un tipo particular
de objeto. En la literatura asociada a la OO, esta relacin entre clase y objeto se suele llamar
instancia: se dice que un objeto es una instancia particular de una clase.
Desde el punto de vista de estructura de datos, la clase consta de dos partes: una de
declaracin y una de implementacin. La parte de declaracin contiene la lista de elementos
que pertenecen a la clase, es decir, identifica los atributos y mtodos que son miembros de la
42
VOLVER A MEN
clase. La implementacin tiene que ver con la definicin del cuerpo de los mtodos de la clase.
Nota: El concepto de clase tiene relacin directa con los principios de abstraccin,
jerarqua, modularidad y tipos.
Por otro lado y, para soportar el principio de encapsulamiento, a cada uno de los elementos
que se definen en una clase se les debe indicar el nivel de visibilidad y/o proteccin que tiene
el elemento. A esta caracterstica se le llama interfaz de la clase. En este sentido, existen tres
posibles usuarios para acceder a los elementos de una clase:
1) Los elementos de la misma clase.
2) Los elementos de otras clases que tienen alguna relacin con la clase que se est
definiendo (basado en el principio de jerarqua).
3) Cualquier otro elemento externo a la clase.
Cabe mencionar que no existe un estndar relativo a lo que se considera el segundo tipo de
usuario antes mencionado; es decir, la manera en la cual se relacionan las clases puede variar
entre un contexto de implementacin y otro. Por ejemplo, en el lenguaje de programacin C++,
la relacin entre clases se establece con la herencia y, en el lenguaje de programacin Java
esta relacin se establece en clases que pertenecen al mismo paquete.
As como hay tres tipos de usuarios de los elementos de una clase se tienen entonces tres
niveles de interfaz que determinan el nivel de visibilidad de estos elementos (ver Tabla 2.1):
privado, protegido y pblico.
43
VOLVER A MEN
Privada
Protegida
Pblica
Nota: Una clase con todos sus elementos privados no sirve para nada ya que no hay
manera de interactuar con los objetos correspondientes (se trata de una caja negra).
Una clase con todos sus elementos pblicos viola completamente el principio de
encapsulamiento y es lo mismo que hacer modelado no OO.
En otro orden de ideas, basado en el principio de jerarqua, para la definicin de una clase
nueva se pueden usar clases existentes, ya sea incorporando un objeto como atributo de la
clase (agregacin) o haciendo una especializacin de la clase mediante el establecimiento de
una generalizacin (herencia).
Supongamos se tienen las clases A y B; se dice que A es una agregacin de B si y slo si A
forma parte de B. Es decir, B contiene un objeto de A como atributo. Disco duro forma parte de
computador personal es un ejemplo de agregacin. Por otro lado, se dice que A hereda de B
si y slo si A es un caso particular de B; es decir, B es una generalizacin de A. Memoria RAM
es un caso particular de memoria es un ejemplo de este tipo de relacin entre clases.
La Figura 2.4 muestra un ejemplo de un diagrama de clases escrito en UML en la cual se
aprecian las siguientes relaciones de generalizacin: Avin, Avioneta y Helicptero son casos
particulares de Aeronave. Tambin se representan las siguientes relaciones de agregacin:
Torre, Puerta, Plataforma, Hangar y Pista forman parte de Aeropuerto. Ntese la sintaxis UML
utilizada para representar ambos tipos de relacin. El Captulo 3 aborda la temtica relativa a
UML.
44
VOLVER A MEN
La Herencia. Se trata de una de los dos tipos de relacin que fueron descritas anteriormente.
La herencia permite crear clases nuevas a partir de clases ya existentes, estableciendo niveles
de jerarqua y programando slo las diferencias. Adicionalmente, la herencia permite refinar las
estructuras sin necesidad de duplicar informacin. Esta definicin de clases nuevas partiendo
de clases existentes se puede realizar de dos maneras:
1) Especializar una clase existente. Por ejemplo, se tiene una clase para representar a una
Persona y se desea una clase para representar un Trabajador.
2) Generalizar en un concepto aspectos comunes de una o ms clases existentes. Por
ejemplo, se tienen las clases Equipo-Audio y Equipo-Video y se quiere tener la clase
ms general Equipo que contenga los aspectos comunes de las dos primeras.
La clase que est en la jerarqua inferior (ms especializada) es conocida como subclase o
clase derivada y la clase de mayor nivel (ms genrica) se denomina superclase o clase base.
Por otro lado, la especializacin de un concepto puede involucrar ms de una clase base.
Por ejemplo, un Equipo-Audiovisual combina las caractersticas de un Equipo-Audio con un
Equipo-Video. En este sentido, segn el nmero de clases base involucradas en la relacin, la
herencia puede ser de dos tipos: simple (cuando hay una sola clase base) y mltiple (cuando
hay ms de una clase base). El ejemplo de la Figura 2.5 muestra otro diagrama de clases UML
en la cual tienen las siguientes herencias simples: Ventana con desplazamiento es un caso
particular de Ventana, Lienzo es un caso particular de Ventana, Panel es un caso particular
de Ventana, Ventana de texto es un caso particular de Ventana con desplazamiento, Item
45
VOLVER A MEN
46
VOLVER A MEN
Es importante tener en cuenta que la relacin de herencia hace que la clase derivada contenga
el total de elementos que forman parte de las clases base del cual sta hereda. Mientras
ms clases base haya ms elementos se agregan a la clase derivada. Adicionalmente, la
clase derivada puede o no tener otros elementos nuevos que permiten especializar esta clase.
Ntese que en una herencia simple no tiene sentido que la clase derivada no contenga nuevos
elementos ya que las dos clases seran exactamente igual.
Nota: Una clase derivada que hereda de una sola clase base (herencia simple) y no
agrega nuevos elementos no tiene sentido ya que la subclase y la superclase seran
exactamente iguales.
Nota: Cuando un objeto recibe un mensaje que contiene un mtodo que no est
definido directamente en la clase correspondiente, se busca automticamente hacia
arriba en su jerarqua de clases. Igual ocurre al acceder a un atributo del objeto.
47
VOLVER A MEN
En ocasiones es posible que se tenga la necesidad de definir clases con niveles de generalizacin
tan altos que no es posible implementar algunas operaciones. Por ejemplo, supongamos
que se quiere representar con una clase el concepto Figura y en ella, la operacin (mtodo)
dibujar. Ntese que no es posible dibujar una figura si antes no se sabe qu tipo de figura
es: crculo, rectngulo, cuadrado, etc. En estos casos y, dado el hecho que la clase no est
definida completamente, no tiene sentido la instanciacin de objetos. Este tipo de clases cuya
descripcin es incompleta se denominan clases abstractas. Las clases abstractas slo sirven
para ser usadas como clases base en una relacin de herencia y, por ende, para especializar
otras clases que permitan completar lo que falta indicar en la clase abstracta base. Aquellos
mtodos que forman parte de una clase abstracta y no han sido implementados an, reciben
el nombre de mtodos virtuales.
En trminos de diseo, las clases abstractas son tiles para permitir a un usuario refinar o
particularizar un concepto. Por lo general contienen uno o ms mtodos virtuales, aunque
no es obligatorio. Los mtodos virtuales deben ser obligatoriamente definidos en las clases
derivadas; de no hacerse, entonces la clase derivada tambin pasa a ser una clase abstracta.
En algunos casos, los mtodos virtuales contenidos en una clase A pueden tener implementacin.
Una subclase B que hereda de A puede luego hacer una redefinicin del mtodo virtual. Un
mtodo virtual que no tiene implementacin y su definicin es obligatoria en las clases derivadas
recibe el nombre de mtodo virtual puro. Por el contrario, un mtodo virtual que si tiene una
implementacin pero que puede ser redefinida en las subclases recibe el nombre de mtodo
virtual no puro.
Nota: Un mtodo no virtual de una clase base y otro similar (polimrfico) de la clase
derivada ocupan ambos espacios de memoria independientes. En un mtodo virtual
slo se tiene el espacio de memoria ocupado por la redefinicin que se realiza en la
clase derivada.
La Figura 2.6 presenta un modelo de clases UML con un ejemplo de la clase abstracta Motores.
Dado el hecho que no es posible saberlo sin antes conocer el tipo especfico de motor del cual
se est instanciando un objeto, Encender y Apagar el motor son dos posibles ejemplos de
mtodos virtuales puros asociados a esta clase.
48
VOLVER A MEN
Por otro lado, en la herencia de clases tambin est involucrado el trmino de interfaz de los
elementos de la clase. En este caso se denomina interfaz de la herencia y permite determinar
qu criterio de interfaz (pblico, privado o protegido) se va a usar para los usuarios de la clase
derivada en relacin a los elementos pblicos de la clase base. Supongamos por ejemplo que
una clase A tiene un elemento pblico A.p por lo cual, cualquier usuario puede tener acceso
a este elemento; supongamos tambin que se tiene la herencia B es un caso particular de A;
la interfaz de herencia permite indicar cmo se desea manejar o, mejor dicho, qu nivel de
visibilidad se le quiere dar al elemento A.p, que ahora est incluido tambin en B (ver Figura
2.7).
49
VOLVER A MEN
En este sentido y dado que existen tres niveles de interfaz (pblico, privado y protegido), la
interfaz de herencia puede estar asociada a cada uno de estos tres posibles niveles. El pblico
hace que los elementos pblicos de la clase base sean tratados igualmente como pblicos en
la clase derivada (es el escenario ms comn); el privado hace que los elementos pblicos de
la clase base sean tratados como privados en la clase derivada; y el protegido hace que los
elementos pblicos de la clase base sean tratados como protegidos en la clase derivada.
Nota: No todos los lenguajes de programacin manejan los tres niveles de interfaz
de herencia. C++ maneja los tres casos; Java y C# asumen siempre el caso de
interfaz pblica.
2.5 Ejercicios
1) Identifique y explique 4 principios de la OO.
2) En qu consisten el estado, la identidad y el comportamiento de un objeto?
3) Explique la diferencia entre las interfaces pblica, protegida y privada de una clase.
4) En qu consisten los principios OO de Abstraccin, Encapsulamiento, Persistencia y
Polimorfismo?
5) A qu se conoce como el Protocolo del Objeto?
6) Explique los conceptos de clase abstracta y mtodo virtual.
7) Identifique y explique las caractersticas o elementos que forman parte de un objeto.
8) Explique la diferencia entre los siguientes conceptos
a) Mtodo y mensaje.
b) Herencia simple y herencia mltiple.
c) Clase y objeto.
d) Interfaz pblica e interfaz privada de una clase.
9) Enumere y defina los tres conceptos bsicos de la OO?
10) Escriba un ejemplo de herencia simple y otro de herencia mltiple.
11) El encapsulamiento est asociado a: ?
a) Permitir que los datos puedan ser vistos y usados.
b) Permitir que los datos no puedan ser vistos ni usados.
c) Permitir que algunos datos puedan ser vistos y usados y otros no.
d) Ninguna de las anteriores.
50
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
Herencia
Tipos Interfaz
Persistencia Constructor
Polimorfismo
Sobrecarga de operadores
53
VOLVER A MEN
Captulo 3
VOLVER A MEN
pruebas finales del producto. En el Captulo 4 se propone una metodologa para la resolucin
de problemas que requieren un componente de software.
Nota: UML es un lenguaje y como tal tiene una sintaxis y una semntica. La mayora
de la sintaxis est representada por smbolos grficos.
3.2 Componentes
UML est estructurado en cuatro componentes o elementos. Desde un punto de vista macro
a uno ms detallado, estos componentes son: las Vistas, los Diagramas, los elementos del
modelo y los mecanismos generales.
Las Vistas muestran diferentes aspectos del sistema que se est modelando. Su objetivo
es representar una abstraccin que consiste en un nmero determinado de Diagramas. Las
Vistas permiten, adems, enlazar el modelo al proceso escogido para el desarrollo, es decir,
acoplarse a la metodologa que se est usando para realizar el proceso. No existe un nmero
especfico de Vistas que se tienen para agrupar los Diagramas. Puede variar entre un autor
y otro, por lo general en un mnimo de tres y un mximo de cinco Vistas. Las cinco posibles
Vistas que se pueden tener son las siguientes:
1) Vista de Casos de Uso: muestra la funcionalidad del sistema tal como es percibida por
los actores externos. Tiene que ver con la representacin de los requerimientos del
sistema que se va a modelar. Puede estar asociado a las etapas de levantamiento de
informacin y anlisis de requerimientos propias de la metodologa utilizada.
55
VOLVER A MEN
2) Vista lgica: muestra cmo est diseada dentro del sistema la funcionalidad en trminos
de las estructuras estticas y el comportamiento dinmico. Representa la parte conceptual
del modelo. Est asociado a las etapas de anlisis y diseo de la metodologa utilizada.
3) Vista de componentes: muestra la organizacin de los componentes de cdigo para
construir un sistema de software. Tambin puede asociarse a la etapa de diseo de la
metodologa utilizada.
4) Vista de concurrencia: muestra la concurrencia (comunicacin y sincronizacin) en
el sistema. Representa la parte dinmica o de comportamiento del modelo. Permite
demostrar la satisfaccin de los requerimientos previamente obtenidos. Pudiera estar
asociado a las posibles etapas de pruebas que bien pueda tener la metodologa utilizada.
5) Vista de despliegue: muestra el despliegue o distribucin del sistema en la arquitectura
fsica (computadoras y otros dispositivos). Pudiera ser usado como parte de la etapa de
diseo en la metodologa utilizada.
Los Diagramas son los componentes principales de UML. Son elementos grficos que describen
el contenido de una Vista. En la versin 2.0 de UML se reconocen los siguientes 9 tipos de
diagramas que sern descritos en detalle ms adelante:
1) Diagrama de Casos de Uso.
2) Diagrama de Actividades.
3) Diagrama de Clases.
4) Diagrama de Objetos.
5) Diagramas de Estados.
6) Diagrama de Colaboracin.
7) Diagrama de Secuencias.
8) Diagrama de Componentes.
9) Diagrama de Distribucin.
Los elementos del modelo son los que representan la sintaxis de UML y, por lo tanto, estn
asociados a los conceptos usados en los Diagramas, comnmente a conceptos de la OO:
clase, objeto, interfaz, mensaje, etc.
Nota: Un smbolo sintctico o elemento del modelo siempre tiene el mismo significado
en cualquiera de los Diagramas donde ste es utilizado.
56
VOLVER A MEN
3.3 Diagramas
A continuacin un detalle de los nueve Diagramas que forman parte de la versin 2.0 de UML.
Diagrama de casos de uso. Forma parte de la Vista de Casos de Uso y permite describir
lo que un nuevo sistema debe hacer o lo que un sistema existente hace en trmino de los
requerimientos y funcionalidades. Es una estructura que ayuda a los analistas a trabajar con
los usuarios para determinar la forma en que se usar el sistema a modelar. Adicionalmente,
es una excelente herramienta para estimular a que los usuarios potenciales hablen del sistema
desde sus propios puntos de vista.
En trminos generales el diagrama de casos de uso permite describir el sistema como una
caja negra que provee casos de uso o funcionalidades. El objetivo es que el sistema sea visto
por el usuario desde un punto de vista de interaccin y no los detalles internos del mismo.
Desde el punto de vista sintctico, estos diagramas estn constituidos por tres elementos:
1) Actor: representa un tipo o categora de usuario o cualquier elemento que interacta con
el sistema. Define, adems, los papeles diferentes que un usuario puede desempear:
operador, administrador, gerente, etc. El conjunto de actores, en general, representa
a todo aquello que necesita intercambiar informacin con el software que se est
analizando: usuarios, base de datos, otros sistemas, hardware especializado, entre
otros. La notacin o smbolo sintctico utilizado es el que se muestra en la Figura 3.1.
Nota: Actor no necesariamente est relacionado con usuario (persona humana) sino
con cualquier elemento que interacta con el sistema y que no forma parte de la
solucin.
57
VOLVER A MEN
3) Relaciones: permiten identificar la comunicacin entre actores entre s, entre los casos
de uso y los actores y entre casos de uso entre s. En este sentido, hay cinco tipos de
relacin:
3.1) Relacin de generalizacin entre actores: permite organizar los actores en una
descripcin abstracta del actor haciendo uso de una relacin caso particular de.
En el ejemplo de la Figura 3.3, los actores Persona y Empleado estn relacionados
tomando en cuenta la siguiente lectura semntica: Empleado es un caso particular
de Persona. Ntese que el actor Persona es ms genrico que el actor Empleado.
Nota: En UML la flecha cerrada como la que se usa en la Figura 3.3 representa
generalizacin y, en cualquier diagrama siempre se lee caso particular de.
3.2) Relacin de generalizacin entre casos de uso: identifica que un caso de uso
VOLVER A MEN
3.3) Relacin de extensin entre casos de uso (extend / extensin): permite factorizar
las variantes sobre la secuencia bsica de un caso de uso en nuevos casos de
uso que extienden los flujos principales. La idea es presentar funcionalidades
alternas que un actor puede (opcionalmente) realizar como consecuencia de la
funcionalidad base. En el ejemplo de la Figura 3.5, la funcionalidad Alquilar un
vehculo puede opcionalmente extenderse a la funcionalidad Alquilar un chofer.
Sin embargo, no es posible Alquilar un chofer si no se realiza el Alquilar un
vehculo. Esto se representa mediante la asociacin directa utilizando la flecha
abierta y la dependencia representada por la lnea no slida. Adicionalmente, el
ejemplo de la Figura 3.5 tambin tiene la siguiente lectura semntica: Alquilar
un chofer depende de Alquilar un vehculo. Ntese que la asociacin o relacin
de extensin es un estereotipo previamente definido en el estndar UML. Los
estereotipos o categoras de conceptos se identifican porque se encuentran
encerrados entre corchetes angulados << y >>.
Nota: En UML la flecha abierta como la que se usa en la Figura 3.5 representa
asociacin directa; una lnea no slida representa dependencia.
3.4) Relacin de inclusin entre casos de uso (include / inclusin): permite sealar que
un caso de uso incorpora (obligatoriamente) el comportamiento de otro caso de
uso como parte de su propio comportamiento. En el ejemplo de la Figura 3.6,
una lectura semntica es: Acceder a un sistema depende que primero se haga
Revisar datos del usuario. Ntese el uso de la lnea no slida para representar
dependencia y el sentido de la asociacin (indicado por la flecha) en concordancia
con el sentido de la lectura semntica.
59
VOLVER A MEN
VOLVER A MEN
61
VOLVER A MEN
Diagrama de Actividad. Se trata de un diagrama muy parecido a los diagramas de flujo utilizados
para representar algoritmos. Por lo tanto, este tipo de diagramas permiten representar la
dinmica del sistema, es decir, muestran el flujo de control entre actividades del sistema, cules
actividades se pueden hacer en paralelo y caminos alternativos del flujo. Hay dos posibles
contextos en los cuales se pueden usar estos diagramas:
1) Como parte de la Vista de Casos de Uso utilizados para mostrar el flujo de las actividades
que detallan la secuencia de un caso de uso particular.
2) Como parte de la Vista Lgica para representar los algoritmos asociados a los mtodos
de las clases.
Los elementos que forman parte de este tipo de diagrama y cuyos smbolos correspondientes
se pueden observar en la Figura 3.10, son los siguientes:
Actividad: representa el desempeo o accin de algn comportamiento en el diagrama de
flujo.
Actividades inicial y final: smbolos especiales usados para iniciar y finalizar el diagrama
de flujo. Slo es posible tener un inicio por diagrama y cualquier nmero de finales.
Transicin: muestran el paso del flujo de control de una actividad a otra.
Cajas de decisin: muestran rutas alternativas del flujo de control basado en una condicin.
Barras de sincronizacin: permite representar actividades que se pueden ejecutar de
62
VOLVER A MEN
forma concurrente (una transicin de entrada y varias de salida) o diversos flujos que,
una vez culminados, convergen en un punto (varias transiciones de entrada y una de
salida). En este sentido, se tienen correspondientemente barras de concurrencia y barras
de convergencia.
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
extremos indica que la dependencia es mutua (en ambos sentidos). El ejemplo de la Figura
3.13 permite representar en UML el concepto de clases amigas propio del lenguaje de
programacin C++. Se lee semnticamente Clase A es amiga y depende de la Clase B.
Ntese, adems, que en este caso se est haciendo uso de un estereotipo (ver Seccin
3.4) para la asociacin (por el uso de los doble corchetes angulados << y >>).
Otro ejemplo del uso de dependencia ocurre con la relacin entre los conceptos de metaclase y
clase instanciada del entorno OO Smalltalk. Las metaclases son clases cuyas instancias no son
objetos sino otras clases, es decir, es una clase para crear otras clases. Son tiles en sistemas
donde se requiere la creacin de clases de forma dinmica. Las clases instanciadas son
instancias de metaclases. Esta relacin de instanciacin se hace mediante una dependencia,
tal como se muestra en la Figura 3.14.
Refinamiento: se trata de una relacin especfica entre dos descripciones del mismo tipo
pero en niveles diferentes de abstraccin. Por ejemplo, entre un tipo de dato y una clase;
entre una clase en tiempo de anlisis y la misma clase en tiempo de diseo, etc. Ntese
que puede confundirse con la generalizacin, la diferencia es que en este caso se trata
de conceptos del mismo tipo. Sintcticamente se representa mediante una lnea no slida
(similar a la dependencia) con una flecha cerrada dirigida al elemento de nivel ms alto
de abstraccin (como la utilizada en la generalizacin). Semnticamente hablando un
refinamiento se puede tambin leer como una dependencia generalizable. La Figura 3.15
presenta un ejemplo.
66
VOLVER A MEN
Nota: Aunque es posible hacerlo, hay que evitar dejar asociaciones sin nombre o
etiquetas ya que no permite clarificar la lectura semntica correspondiente. En los
ejemplos anteriores, imagine que las etiquetas Propietario y Usa no estuvieran
en el segmento de diagrama, cmo se podran interpretar entonces las respectivas
asociaciones? Cuando una asociacin no contiene nombre entonces sta debera
leerse como est asociado a para el caso en que haya una flecha que
determina el sentido de la asociacin y, estn asociados para el caso en la
cual la asociacin sea bidireccional.
Recursiva: representa la conexin de una clase consigo misma. Por lo tanto, los objetos que
estn conectados semnticamente son de la misma clase. La lectura del ejemplo de la izquierda
de la Figura 3.17 es 0 o ms Nodos se Conectan con otros 0 o ms Nodos. Basado en el uso
de roles, el segmento de diagrama de la parte derecha se lee Persona en el rol de esposa se
67
VOLVER A MEN
casa con otra Persona en el rol de esposo. Ntese que si se hubiera colocado adicionalmente
la multiplicidad 1 a ambos lados de la asociacin, una mejor lectura sera una Persona en el rol
de esposa se casa con una Persona en el rol de esposo.
Disyuntiva (or): representa una restriccin (ver Seccin 3.4) entre dos o ms asociaciones.
Indica que los objetos de una clase pueden participar en, a lo sumo, una de las asociaciones
a la vez. En general, las asociaciones tambin pueden contener restricciones para indicar
que la asociacin debe seguir cierta regla para su cumplimiento. Ntese el uso de la
restriccin {Or} en el ejemplo de la parte superior de la Figura 3.19. Por otro lado, en el
ejemplo de la Figura 3.20, 1 Compaa de Seguros est asociada a 0 o muchas Pliza
de Seguros que tienen que ver con 1 o varias Personas o con 1 o varias Compaas.
Este ejemplo muestra la restriccin {Ordenado} la cual permite leer que 0 o varias
Pliza de Seguros que deben estar ordenadas, ests asociadas a 1 o varios Clientes.
68
VOLVER A MEN
Ternaria: representa una asociacin en la cual estn involucradas tres clases. Para
ello se hace uso de un smbolo sintctico representado con un diamante (ver Figura
3.21). Las asociaciones calificadas y la agregacin no estn permitidos en este tipo
de asociacin. Su uso no es muy comn y se recomienda no usar, ya que aumenta la
complejidad de interpretacin o lectura del modelo. Su uso puede ser evitado ya que
una asociacin ternaria se puede escribir de manera homloga con dos asociaciones
normales (binarias) (ver Figura 3.22). En el ejemplo de la Figura 3.21, la lectura es como
sigue: 0 o ms Pliza de Seguros, asociado a una Compaa de Seguros, tiene que
ver con 1 o ms instancias de Persona y 0 o ms Clausula.
69
VOLVER A MEN
Agregacin: es un caso especial y muy utilizado de asociacin que indica que la relacin
entre las clases es del tipo forma parte de (ver principio de Jerarqua en Seccin 2.2).
Se representa sintcticamente mediante un diamante como se muestra en la Figura
3.23. Los ejemplos representados en la Figura 3.23 tienen la siguiente lectura: Varios
Barco de Guerra forman parte de una Naval, Varios Texto, Botn y Men forman parte
de Ventana. La diferencia entre el diamante relleno y el que no lo est radica en el nivel
de composicin de la relacin. Cuando el diamante est relleno se quiere representar
que el objeto agregado (el que est en el extremo opuesto al diamante) existe porque
el objeto de la clase que agrega (que corresponde a la clase donde est el diamante)
existe. Es decir, la creacin y destruccin del objeto agregado depende del objeto que
agrega. Por el contrario, si no existe esta dependencia en la creacin y destruccin del
objeto agregado entonces se representa mediante un diamante sin rellenar. En este
caso, el objeto que agrega no tiene realmente un objeto como tal sino una referencia del
objeto agregado. En el ejemplo de la Figura 3.23, la destruccin de un objeto de la clase
Naval no implica la destruccin de los objetos de Barco de Guerra asociados; pero,
los textos, botones y mens que forman parte de una ventana, son destruidos cuando la
ventana es destruida.
70
VOLVER A MEN
Interfaz: Un paquete, componente o clase que tiene una interfaz conectada a l, se dice
que implementa o soporta la interfaz especfica dado que soporta el comportamiento
definido en esa interfaz. Se pueden ver como contratos de colaboracin entre los
diferentes elementos del modelo y slo se describen como operaciones abstractas.
Se representan mediante pequeos crculos asociados (lnea slida) al elemento del
modelo (uno a uno); una clase que usa la interfaz se conecta mediante una relacin de
dependencia (ver un ejemplo en la Figura 3.24).
71
VOLVER A MEN
La sintaxis de UML contiene, adicionalmente al rectngulo que representa una clase, una serie
de otros smbolos grficos para representar clases especializadas, alguna de las cuales son
utilizadas en lenguajes de programacin especficos. Se trata de los siguientes casos:
Parametrizada: permiten representar lo que en el entorno de programacin se conocen
como Templates (usados para generalizar la definicin de una clase o definir grupos
de clases para que, mediante los parmetros, se puedan crear luego las clases reales).
La Figura 3.26 muestra el smbolo utilizado para este tipo de clases.
De utilidad: es la respuesta que tiene UML para representar todos aquellos elementos
que estn fuera del contexto de OO y que por lo tanto, no pueden ser representados
bajo ninguna otra forma. El ejemplo ms comn es lo que ocurre con el lenguaje de
programacin C++ y las variables globales y funciones. La clase de utilidad permite
agrupar todos estos elementos y conjugarlo en una clase representados como atributos
y mtodos respectivamente. La idea es darle una connotacin ms formal de OO y no
dejar elementos dispersos que queden fuera de algn objeto. La Figura 3.27 muestra el
smbolo utilizado.
Por otro lado, en UML los paquetes o agrupaciones de clases se representan haciendo uso
de la sintaxis que se muestra en la Figura 3.28; se trata de un smbolo grfico parecido a una
carpeta. Tal como se muestra en la Figura 3.28, los paquetes se pueden tambin relacionar
entre s por generalizacin y dependencia.
72
VOLVER A MEN
Una clase representada en UML de manera completa est formada por tres partes que, de
arriba hacia abajo son: 1) la identificacin, 2) los atributos y 3) los mtodos. Cada una de estas
partes se separa de la anterior con una lnea slida horizontal que divide el rectngulo en
segmentos. Por otro lado, los atributos y mtodos pueden adicionalmente contener informacin
detallada del elemento como por ejemplo, su interfaz, el tipo de dato del atributo, el tipo de
dato de retorno del mtodo y los posibles parmetros del mtodo (ms adelante se muestra
un ejemplo).
Nota: Mientras ms detalle se coloque en la clase en tiempo de diseo (UML) ms
simple ser el paso a la programacin.
La Figura 3.29 muestra un ejemplo de un diagrama de clases (no completo) relacionado
con el contexto de un plan y los controles grficos requeridos para manejarlo. Ntese el uso
de varias de las relaciones y asociaciones que se explicaron anteriormente. Por ejemplo:
VentanaResumenPlan es un caso particular de Ventana, Banner forma parte de ListaBanner
y PlanMaestro est asociado a CrearVentanaPlan. Ntese tambin que las clases Ventana,
Botn, Lista y Conjunto no slo estn categorizadas o estereotipadas como Referencia
sino que adems son clases abstractas (se diferencian porque el nombre est escrito con
estilo cursiva). Se puede observar tambin la manera en la cual algunas clases tienen definido
parte de los detalles (atributos y mtodos). Ntese el uso del smbolo + para indicar que
el elemento (mtodos por lo general) son de interfaz pblica y el smbolo - para indicar
que el elemento (atributo por lo general) son de interfaz privada. Algunos ejemplos son: El
mtodo pblico ObtCosto de la clase CostoIntervaloTiempo el cual retorna un Real y
no tiene parmetros; el mtodo pblico LiberarPlan de la clase PlanSemanal el cual tiene
un parmetro identificado como ListaBanner; el atributo privado HoraInicio de la clase
CuartoHora el cual es de tipo Integer.
73
VOLVER A MEN
Nota: No existe una sintaxis especfica en UML para representar clases abstractas;
depende de la herramienta grfica que se use.
Nota: No existe una sintaxis especfica en UML para representar la interfaz de los
elementos de una clase. Comnmente se utiliza + para elementos pblicos, - para
elementos privados y # o * para elementos protegidos.
Figura 3.29. Ejemplo de un diagrama de clases relacionado con el problema de controles grficos.
VOLVER A MEN
nica manera de diferenciar una clase de un objeto genrico de la clase (ver Figura 3.30 con
un ejemplo).
Otra diferencia existente entre la manera en la cual se representa una clase detallada
(identificador, atributos y mtodos) y un objeto, es que el objeto slo consta de dos y
no tres partes. Adems del identificador del objeto, la segunda parte se refiere al estado
actual del objeto que, segn se mencion en la Seccin 2.4, viene dado por los
atributos y valores actuales correspondientes.
Los diagramas de objetos, los cuales forman parte de la Vista Lgica, no son muy comunes
en los modelos pero se pueden usar para ejemplificar un diagrama de clases con instancias
explcitas. Tambin se pueden usar como parte de los diagramas de colaboracin en el modelo
dinmico (ver ms adelante).
Ntese en el ejemplo de la Figura 3.30 que hay tres instancias de la clase CuartoHora
identificados como QH1, QH2 y QH3 cada uno de los cuales con su estado especfico
dado por el valor del atributo HoraInicio; tres objetos de la clase Banner identificados como
Ad1, Ad2 y Ad3 cada uno de los cuales con el estado dado por los valores de los atributos
HoraInicio y HoraFin; una instancia genrica de la clase PlanSemanal y otra de la clase
ListaBanner. Las asociaciones entre los objetos permiten indicar el momento (dado por el
estado de los objetos) en el cual se da el intercambio de mensajes entre ellos.
VOLVER A MEN
cual se encuentran los objetos de una clase especfica y el cambio de estos estados provocado
por la ejecucin de un mtodo. Se indican qu acciones se ejecutan en cada estado y cul
es el nuevo estado al que se llega luego de un determinado evento (mensaje). Los estados
representan condiciones que son vlidas en el objeto en un momento dado; los eventos
representan la causa que origina el cambio desde un estado a otro.
Nota: Por lo general se hace un diagrama de estados por cada una de las clases que
forman parte del modelo.
La sintaxis UML necesaria para realizar un diagrama de estados se muestra en la Figura 3.31.
Ntese que un estado se representa mediante un rectngulo con los bordes curvos excepto
los casos especficos inicial y final. Slo se permite un estado inicial por diagrama y cualquier
cantidad de estados finales. El estado inicial y el estado final estn asociados respectivamente
a la construccin y destruccin del objeto.
La Figura 3.32 muestra el diagrama de estado de la clase detallada Vlvula que se muestra
en la parte izquierda del ejemplo. Ntese que el nico atributo de la clase es el Estado que
determina la manera en la cual la Vlvula est en un momento dado (abierta o cerrada). Los
mtodos Abrir y Cerrar permiten cambiar el estado de una Vlvula. Del diagrama de estados
de la parte derecha del ejemplo se puede leer lo siguiente:
1) El estado inicial del objeto en tiempo de construccin es la vlvula cerrada.
2) Estando la vlvula cerrada y se manda un mensaje de Cerrar, sta permanece cerrada.
3) Estando la vlvula cerrada y se manda un mensaje de Abrir, sta cambia de estado a
vlvula abierta.
4) Estando la vlvula abierta y se manda un mensaje de Abrir, sta permanece abierta.
76
VOLVER A MEN
Diagrama de Componentes: Para casos especficos de sistemas de software que deben ser
modelados, este diagrama que forma parte de la Vista de Componentes, permite modelar la
estructura del software, es decir, la manera en la cual el software est construido o estructurado
en componentes, incluyendo dependencias entre componentes en cdigo fuente, componentes
en cdigo binario y componentes ejecutables.
Un componente es visto como un grupo de clases que trabajan estrechamente y que se pueden
clasificar segn su existencia (ver detalles a continuacin) en: tiempo de compilacin, tiempo
de enlace y tiempo de ejecucin.
El diagrama permite, adems, establecer relaciones de dependencia entre componentes y/o
paquetes de componentes. Una dependencia indica que un elemento del modelo (fuente)
depende de otro (objeto), de manera que un cambio en el elemento objeto puede significar
cambiar el elemento fuente.
77
VOLVER A MEN
Desde un punto de vista terico, UML reconoce los siguientes tipos de componentes:
Componentes para trabajar en el producto: tambin llamados componentes fuente,
son tpicamente archivos de cdigo fuente usados para implementar una o ms clases
(archivos de base de datos, cdigo fuente, recursos grficos, entre otros).
Componentes de distribucin: tambin llamados componentes binarios, conforman el
fundamento de los sistemas ejecutables y son tpicamente archivos de cdigo objeto
que se generan a partir de los componentes anteriores (ejecutables, DLL, controles
ActiveX, entre otros).
Componentes de ejecucin: son los creados como resultado de un sistema en ejecucin
(archivos temporales, ndices de bsqueda, entre otros).
Como se muestra en el ejemplo de la Figura 3.33, el smbolo sintctico UML usado para
representar un componente es el rectngulo con las dos barras horizontales colocadas en su
lado izquierdo. Para diferenciar un tipo de componente de otro se usan los estereotipos (ver
Seccin 3.4 para detalles de este mecanismo general de UML).
VOLVER A MEN
La Figura 3.34 presenta un diagrama de colaboracin que inicia con el actor Ingeniero
planificacin que muestra la manera en la cual se hace ComputarBeneficios mediante el
intercambio de mensajes entre un objeto de la clase PlanSemanal, un objeto de la clase
CuartoHora y una instancia de la clase CostoIntervaloTiempo. Ntese la forma como se
indica el orden de ejecucin de los mensajes; tambin la indicacin de retorno en los eventos
o mensajes 2 y 3. Tambin se puede observar que el evento 4 se ejecuta internamente en
el objeto de CuartoHora. Para la lectura de los mensajes que aparecen en el diagrama,
por ejemplo en el caso del mensaje 2, hay que tomar en cuenta que el mtodo identificado
como ObtenerTotalQH pertenece a la clase CuartoHora y el objeto que realiza la llamada
es la instancia de la clase PlanSemanal (esto se determina por el sentido de la flecha de la
colaboracin que va de la clase PlanSemanal a la clase CuartoHora).
VOLVER A MEN
izquierda a derecha y de arriba abajo y, al igual como ocurre con el diagrama de colaboracin,
debe iniciar con un actor que por lo tanto, debe estar en la parte ms izquierda del diagrama.
La Figura 3.35 muestra la sintaxis UML utilizada en este tipo de diagramas. Tanto el actor
como los objetos se organizan en lneas de tiempo que se colocan verticalmente debajo de
cada elemento correspondiente. Debido a esta manera de organizar los elementos y si estn
involucrados muchos objetos en la interaccin, estos diagramas pueden ser excesivamente
grandes, horizontalmente hablando. A diferencia de los diagramas de colaboracin en la cual
los objetos pueden ser colocados en cualquier parte del diagrama.
Figura 3.36. Ejemplo del diagrama de secuencia equivalente al diagrama de colaboracin de la Figura 3.34.
80
VOLVER A MEN
Diagrama de Distribucin: Es el ltimo de los nueve diagramas que contiene la versin 2.0 de
UML. Forma parte de la Vista de Despliegue y modela la distribucin en tiempo de ejecucin de
los elementos de procesamiento y componentes de software, procesos y objetos asociados.
Tiene que ver con la arquitectura fsica del sistema: dnde estn localizados fsicamente
los programas que implementan las clases y objetos?, en cules computadoras se ejecutan
estos procesos? y cmo se conectan las diferentes computadoras que requiere el sistema
para funcionar?.
El objetivo es modelar los nodos (objetos fsicos o dispositivos) y la comunicacin entre
ellos. Tal como se muestra en la Figura 3.37, los nodos se representan mediante un cubo.
Adicionalmente, cada nodo puede contener instancias de componentes.
81
VOLVER A MEN
VOLVER A MEN
Por lo general, los estereotipos son meta-clases para ser asociados a clases o
importaciones para las relaciones de dependencia entre paquetes. Al igual que ocurre
con los mecanismos generales anteriores, pueden existir estereotipos predefinidos
dependiendo de la herramienta automatizada que se utilice. Tambin es posible
definir estereotipos propios. La sintaxis para su representacin es utilizando un
nombre encerrado entre doble corchete angulado << y >>, que por lo general
se coloca delante del identificador del elemento asociado.
Un ejemplo muy comn que aparece en la literatura es el uso de tres tipos particulares
de estereotipos aplicado a las clases: Control, Lmite y Entidad. Estos elementos
estn basados en el concepto model-view-controller (Burbeck, 1987) donde
Entidad es el modelo, Control es el controlador y Lmite es la vista. La notacin
utilizada es la que aparece en la Figura 3.39.
Figura 3.40. Ejemplo de un diagrama de clases expresado en la notacin control, lmite y entidad.
83
VOLVER A MEN
84
VOLVER A MEN
Semntica
Diagramas
Casos de uso.
Actividad y estados.
Actividad y estados.
Actividad: Uno de los pasos del proceso algortmico que describe una secuencia.
Actividad.
Actividad y estados.
Actividad.
Estados.
Distribucin.
Componentes y distribucin.
Todos.
Semntica
Asociacin: Describe una conexin entre dos tems que se lee en ambas
direcciones.
Asociacin directa: Describe una conexin entre dos tems que se lee en
el sentido de la flecha.
Dependencia: Indica que el tem que est en el extremo sin flecha depende del otro tem que est en el extremo con flecha.
Generalizacin: El tem del extremo sin la flecha es un caso particular del
tem que est en el extremo con la flecha.
Realizacin: El tem del extremo sin la flecha se implementa haciendo
uso del tem que est en el extremo con la flecha.
Agregacin: El tem del extremo sin el diamante forma parte del tem
que est en el extremo con el diamante. Los tems son independientes.
Composicin: El tem del extremo sin el diamante forma parte del tem
que est en el extremo con el diamante. La existencia del primero depende de la existencia del segundo.
Mensaje: El tem del extremo sin flecha est enviando un evento / mensaje al tem del extremo con flecha.
85
VOLVER A MEN
3.6 Ejercicios
1) Para los siguientes casos que se mencionan a continuacin, realice un modelo conceptual
(diagrama de clases no detallado) que permita representar cada caso.
a) Un punto se representa por un par de coordenadas X, Y. Se requiere un cierto nmero
mnimo de puntos para construir un polgono.
b) Una constante, una variable y una expresin son trminos para construir expresiones
binarias (dos operandos) o unarias (un operando). Los operandos de una expresin
tambin son trminos.
c) En un sistema de transporte areo podemos encontrar los siguientes nombres: ciudad,
aeropuerto, aerolnea, piloto, vuelo, avin, pasajero, puerta de embarque, asiento,
terminal.
d) En un sistema de almacenamiento de informacin se tienen los siguientes elementos:
sistema de archivos, archivo, directorio, nombre del archivo, archivo ASCII, archivo
ejecutable, disco, track, sector, capacidad.
2) Realice el diagrama de casos de uso y el diagrama de clases con tanto nivel de detalle
como sea posible, para los siguientes casos que se mencionan a continuacin.
a) Suponga un programa de computacin para la realizacin de artculos para un peridico.
El software maneja varias pginas que pueden contener, entre otras cosas, columnas
de texto. El usuario puede editar el ancho y alto de una columna de texto, mover una
columna en una pgina o mover una columna entre pginas diferentes. Porciones de
una misma columna pueden aparecer en ms de una pgina.
b) Suponga un sistema para llevar el control de la planificacin y puntuacin de unas
competiciones deportivas como el atletismo. Hay varios eventos y competencias.
Cada competidor puede participar en ms de un evento y cada evento tiene varios
competidores. Cada evento tiene varios jueces que emiten su puntuacin sobre el
desenvolvimiento de los competidores en cada evento. Un mismo juez evala a todos
los competidores de un evento especfico y, en algunas ocasiones, un juez puede estar
asignado a ms de un evento.
c) Representacin de un motor de combustin interna. La fuerza del motor es dada por la
combustin generada por la mezcla de aire y gasolina contra un pistn. El pistn est
pegado a un cigeal por medio de una vara de conexin y se mueve hacia arriba y
hacia abajo dentro de un cilindro haciendo girar un eje. Cuando los pistones se mueven
hacia abajo, unas vlvulas de entrada se abren, permitiendo al pistn tener contacto
con una mezcla de combustible y aire dentro del cilindro. Al llegar al fondo del cilindro,
las vlvulas se cierran. Cuando el pistn se mueve hacia arriba, comprime y calienta la
mezcla. Anillos alrededor del pistn frotan contra las paredes del cilindro proveyendo un
86
VOLVER A MEN
sello necesario para la compresin y lubricacin requeridas. En el tope del cilindro, una
chispa elctrica proveniente de una buja, detona la mezcla que da el poder necesario
para enviar el pistn nuevamente hacia abajo. Una vez en el fondo, una vlvula de
evacuacin es abierta y en el prximo viaje hacia arriba del pistn, los gases de la
detonacin anterior son expulsados. La mezcla del combustible y el aire son hechas en
un carburador. El polvo y suciedad en el aire son removidos mediante un filtro. Unas
vlvulas de admisin controlan la cantidad de mezcla adecuada a ser inducida a los
cilindros. La energa elctrica requerida por la buja es suministrada por un magneto,
una bobina, un condensador.
d) Las Torres de Hanoi es un problema frecuentemente usado para la enseanza de
tcnicas recursivas de programacin. El objeto es mover una pila de discos de una de
las tres clavijas o torres que existen a otra, usando la tercera como ayuda. Cada disco
tiene un tamao diferente. Los discos pueden ser movidos, uno a la vez, desde el tope
de una clavija al tope de otra clavija. Un disco nunca es colocado sobre otro disco menor.
e) Para un editor de texto, un folio es una coleccin de enlaces y cajas. Un enlace es una
secuencia de segmentos que conectan dos cajas. Cada segmento es especificado por
dos puntos. Un punto puede ser compartido por un segmento vertical y un segmento
horizontal en el mismo enlace. Una seleccin es una coleccin de enlaces y cajas que
han sido marcados anticipadamente durante una operacin de edicin. Un buffer es una
coleccin de enlaces y cajas que han sido cortados o copiados del folio.
f) Un sistema de reserva de vuelos permite a un usuario hacer consulta y reserva de
vuelos, adems de poder comprar los boletos areos de forma remota, sin la necesidad
de recurrir a una agencia de viajes. El sistema tiene actualmente un Terminal de
Servicio de Reserva (formado por un ratn Genios, teclado IBM y monitor Sony) en
donde se presenta un mensaje de bienvenida describiendo los servicios ofrecidos junto
con la opcin para registrarse por primera vez, o si ya se est registrado, poder usar el
sistema de reserva de vuelos. Este acceso se da por medio de la insercin de un login
previamente especificado (direccin de correo electrnico del usuario) y una contrasea
previamente escogida y que debe validarse. Una vez registrado el usuario, y despus
de haberse validado el registro y contrasea del usuario, se pueden seleccionar las
siguientes actividades: consulta de vuelo, reserva de vuelo y compra de boletos. La
consulta de vuelos se puede hacer de tres maneras diferentes segn: horarios, tarifas e
informacin de vuelos. La consulta segn horarios muestra los horarios de las diferentes
aerolneas que dan servicio entre dos ciudades. La consulta segn tarifas muestra los
diferentes vuelos entre dos ciudades ordenados por su costo. La informacin de vuelos
se utiliza principalmente para consultar el estado de algn vuelo, incluyendo informacin
de si existen asientos disponibles y, en el caso de un vuelo para el mismo da, si ste est
en hora. Se pueden incluir preferencias en la bsqueda, como fecha y horario deseado,
87
VOLVER A MEN
g) Una red bancaria computarizada incluye tanto cajeros humanos como automticos
(ATM), stos ltimos compartidos por un consorcio de bancos. Cada banco provee su
propia computadora para mantener sus propias cuentas y procesar las transacciones
contra ellas. Las estaciones de los cajeros son propias de cada banco y se comunican
directamente con la computadora propia del banco. Los cajeros humanos introducen
datos de cuentas y transaccin. Los ATM se comunican con un computador central el
cual transfiere las transacciones con los bancos apropiados. Un ATM acepta una tarjeta
de dbito, interacta con el usuario, se comunica con el sistema central para llevar
a cabo la transaccin, dispensa efectivo e imprime un recibo. El sistema requiere de
mecanismos de seguridad y auditoria adecuados. El sistema puede manejar acceso
concurrente a la misma cuenta. Los bancos proveen su propio software para sus propias
computadoras. El costo del sistema compartido es distribuido por los bancos segn el
nmero de clientes con tarjetas de dbito.
h) Un gestor de servicios de comunicacin Cliente-Servidor debe satisfacer los siguientes
requerimientos: - un equipo al cual llamamos Servidor ejecuta un proceso que
inicialmente escucha un canal de comunicacin segn un puerto especfico; - otro equipo
al que llamamos Cliente abre el canal de comunicacin con el Servidor conociendo el
puerto correspondiente y la direccin IP del Servidor; - una vez establecido el canal
de comunicacin entre el Cliente y el Servidor, ambos procesos pueden optar por los
siguientes Servicios: 1) Servicio de Correo: Cualquiera de los procesos puede enviar/
recibir un mensaje de texto al otro. Cada mensaje viene acompaado por la fecha y
hora de emisin y un pequeo texto descriptivo o asunto. Para administrar los mensajes
salientes y entrantes se requieren un par de buzones: mensajes no enviados y mensajes
recibidos. Se deben implementar las siguientes funciones: - crear mensaje: introducir un
nuevo texto y guardarlo en el buzn de mensajes no enviados; - borrar mensaje: suprimir
88
VOLVER A MEN
uno de los tems del buzn de mensajes no enviados; - enviar mensajes: hacer el envo
de todos los mensajes que se encuentran en el buzn de mensajes no enviados; - leer
mensaje: mostrar el texto de uno de los mensajes recibidos que se encuentran en el
buzn de mensajes recibidos; - borrar mensaje: suprimir uno de los tems del buzn
de mensajes recibidos. 2) Servicio de Envo/Recepcin de archivos: Cualquiera de los
procesos puede enviar/recibir archivos al otro. Se puede enviar cualquier tipo de archivo.
El receptor escoge la ubicacin y el nombre que va a tener en el destino. 3) Servicio de
Conversacin: Cuando uno de los procesos desea entrar en este modo y el otro proceso
acepta, las transcripciones de texto realizadas en cualquiera de los dos equipos se
visualizarn en ambos procesos, de forma tal de establecer una comunicacin en lnea
entre los usuarios de los equipos correspondientes.
3) Basado en el diagrama de clases realizado para cada caso del ejercicio anterior, realice un
diagrama de cambios de estado de cada una de las clases que aparece en cada uno de
los diagramas.
4) Basado en el diagrama de casos de uso y el diagrama de clases de cada uno de los
escenarios del ejercicio 2, realice un diagrama de colaboracin y/o secuencia para cada
uno de los casos de uso directamente asociado con algn actor.
89
VOLVER A MEN
Captulo 4
90
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
Nota: Es recomendable hacer inline todos aquellos mtodos cuyo cuerpo sea simple,
como por ejemplo el retorno de una expresin y la inicializacin de atributos. Aquellos
mtodos cuyo desarrollo sea ms complejo, que contengan ciclos o condicionales
mltiples por ejemplo, es recomendable desarrollarlos outline.
Esta lentitud es realmente imperceptible con los avances que existen actualmente en relacin a las velocidades de
procesamiento.
93
VOLVER A MEN
94
VOLVER A MEN
Otra diferencia existente entre C++ y la pareja Java, C# es que en estos ltimos no es posible
la instanciacin de objetos al final de la declaracin de la clase; por lo tanto, no se requiere
colocar el smbolo de terminacin de sentencia ;.
Tanto en Java como en C# las declarativas de interfaz pueden aparecer ms de una vez y en
cualquier orden. En Java, si no se indica nada se asume una interfaz entre privada y protegida.
Privada porque no permite la visibilidad del elemento para las clases derivadas; protegida
porque permite la visibilidad en todas las clases que se hayan definido en el mismo paquete.
En C#, si no se indica nada, la declarativa de interfaz que se asume es privada.
Por otro lado, C# maneja adicionalmente un concepto especial de atributo que se define como
una combinacin entre atributo y mtodo. En este sentido, un atributo en C# permite esconder
el manejo de los mtodos de lectura (get) y asignacin (set) de cualquier atributo de la clase.
En el ejemplo de la Figura 4.5, el atributo ParteReal contiene el mtodo get que permite
retornar el valor correspondiente asociado al atributo de la clase Real. En el caso del set, el
95
VOLVER A MEN
valor que proviene de la asignacin que realice el usuario se obtiene mediante el uso de la
palabra reservada value.
96
VOLVER A MEN
VOLVER A MEN
Figura 4.8. Ejemplo del acceso de los elementos de una clase en C++.
La Figura 4.9 muestra el ejemplo de la llamada del mensaje o acceso al mtodo ObtReal
haciendo uso del objeto C en los lenguajes de programacin Java y C#. En el ejemplo de la
Figura 4.10 se observa el acceso al atributo ParteReal usando la instanciacin C de la clase
Complejo.
98
VOLVER A MEN
Figura 4.9. Ejemplo del acceso de los elementos de una clase en Java / C#.
4.5 Constructor
Basado en el principio de persistencia, el constructor es un mtodo particular que es ejecutado
automticamente durante la instanciacin del objeto, tanto esttica como dinmicamente. Es
til para definir el estado inicial del objeto y realizar otras inicializaciones necesarias. Como
mtodo tiene las siguientes caractersticas:
Es opcional.
Debe ser obligatoriamente pblico.
Su identificador coincide con el nombre de la clase.
No se le especifica tipo de retorno.
Puede tener cualquier nmero de parmetros.
99
VOLVER A MEN
100
VOLVER A MEN
4.6 Polimorfismo
Como ya se mencion en la Seccin 2.2, el polimorfismo, que est basado en el principio que
lleva el mismo nombre, se refiere a definir dos o ms mtodos con el mismo nombre, tipo de
retorno e interfaz, pero diferente contexto el cual es dado por la descripcin de los parmetros
(cantidad y/o tipo de los mismos).
No hay lmite sobre la cantidad de mtodos que se pueden definir de forma polimrfica. Es
importante tener en cuenta que no se trata de una redefinicin ya que cada mtodo existe y se
trata de forma independiente (declaracin, definicin y llamada).
Dado que el constructor tambin es un mtodo, un caso particular muy comn de hacer
polimorfismo es sobre el constructor. Esto permite dar al usuario diferentes formas de
inicializar un objeto durante la instanciacin del mismo. La Figura 4.13 presenta un ejemplo
de polimorfismo en el constructor de la clase Complejo. Ntese que hay dos constructores
(mtodos que se identifican igual que la clase): el primero de ellos sin parmetros y el segundo
con dos parmetros (R y I). Ntese tambin la manera en la cual los objetos son instanciados
y asociados a los constructores; en este caso y por no tener ningn parmetro, la instanciacin
del objeto C1 est asociada al primer constructor, mientras que la instanciacin del objeto
C2 est asociada al segundo constructor (ya que hay dos argumentos de tipo double).
101
VOLVER A MEN
De manera similar, la Figura 4.14 presenta el mismo ejemplo pero esta vez haciendo uso de
los lenguajes Java y C# (es similar para ambos casos). Ntese la manera en la cual se hace la
instanciacin de los objetos C1 y C2 haciendo uso del operador new.
Nota: No es posible hacer polimorfismo cambiando tan solo el tipo de dato de retorno
del mtodo. Es necesario o bien cambiar la cantidad de argumentos, o cambiar el
tipo de dato de al menos un argumento.
102
VOLVER A MEN
103
VOLVER A MEN
104
VOLVER A MEN
4.8 Destructor
Basado, al igual que el constructor, en el principio de persistencia, se trata de un mtodo
particular que es ejecutado automticamente durante la destruccin o prdida de alcance del
objeto (tanto esttica como dinmicamente). Es til para realizar cdigo necesario cuando el
objeto ya no va a ser ms utilizado, como por ejemplo la liberacin o recuperacin de espacios
de memoria.
Como mtodo u operacin, el destructor tiene las siguientes caractersticas:
Es opcional.
Debe ser pblico.
No se le especifica tipo de retorno.
No tiene parmetros.
La sintaxis C++ para declarar el destructor es anteponiendo al nombre del mtodo, que debe
ser el mismo de la clase, el caracter ~ (ver el ejemplo de la Figura 4.18).
VOLVER A MEN
En C# ocurre algo similar a Java con el mtodo de finalizacin, el cual puede ser sintcticamente
representado de dos maneras distintas como se muestra en la Figura 4.20. Ntese que una de
las dos opciones es equivalente a la sintaxis de C++ con el uso del caracter ~ antepuesto a
un mtodo que se identifica de la misma manera que la clase.
Nota: Es importante no confundir el concepto de destructor de C++ del mtodo de
finalizacin de Java o C#. Si bien tienen en comn que son ejecutados de manera
automtica, el momento en el cual se hace la llamada es diferente. En el caso de C++
ocurre cuando el objeto pierde alcance o es destruido; en Java y C# ocurre cuando
el mecanismo de recuperacin de memoria libera la memoria del objeto involucrado.
VOLVER A MEN
Un ejemplo tpico de Java y C# es el caso particular del mtodo que representa el programa
principal (identificado como main en Java y Main en C#), el cual debe ser esttico porque
no tiene sentido dos instancias de objetos cada uno de los cuales con un programa principal
de ejecucin. Es decir, no tiene sentido que hayan dos mtodos principales para ejecutar el
mismo programa; luego, todas las instancias asociadas al programa principal comparten este
mtodo.
Cuando este concepto se usa para el caso de los atributos, es muy til para compartir informacin
entre objetos de una misma clase. Un ejemplo lo representa el que se quiera llevar un control
sobre la cantidad de objetos instanciados de una misma clase y que ese control se haga
dentro de la clase correspondiente. La nica manera posible de hacer esto es utilizando un
atributo declarado de forma esttica. El ejemplo de la Figura 4.21 presenta un caso particular
de lo antes mencionado escrito en C++. Se est definiendo la clase File para el manejo de
archivos y el atributo NumAbiertos es utilizado para contar la cantidad de archivos abiertos
en un momento dado.
Ntese en el ejemplo de la Figura 4.21 la manera en la cual sintcticamente se dice que
el atributo NumAbiertos es esttico, anteponiendo a la declaracin la palabra reservada y
declarativa static. Ntese adems que el mtodo Abiertos tambin es un elemento esttico
en la clase y esto se debe a que hay una restriccin en el uso de los atributos estticos:
cualquier mtodo que haga uso de un elemento esttico (ya sea atributo o mtodo) debe
tambin ser esttico a excepcin del constructor y el destructor. En el mismo ejemplo tambin
puede verse la diferencia entre la declaracin y la declaracin de una clase. En este caso
String est siendo declarada y File est siendo definida (lo cual tambin implica que se est
declarando). Est claro que la definicin de la clase String debe estar en algn otro lado del
programa.
107
VOLVER A MEN
Nota: C++, Java y C# son lenguajes de referencia hacia adelante, lo que significa
que cualquier elemento que se utilice en alguna sentencia debe haber sido declarado
antes de su uso. En varios de los elementos incluidos en C++, es posible hacer una
declaracin del elemento en un contexto separado de su definicin. Este es el caso
del ejemplo de la Figura 4.21. La posibilidad de hacer mtodos outline tambin es
otro ejemplo.
La Figura 4.22 complementa el desarrollo de la Figura 4.21. Ntese que el sitio idneo para
incrementar Abiertos es en el constructor y el sitio idneo para decrementar el atributo es el
destructor. Ahora bien, dado que en C++ no es posible inicializar los atributos en el momento
de su declaracin y dado tambin que el constructor no es el sitio adecuado para hacer una
inicializacin de un atributo esttico ya que cualquier objeto que se instancie y, por ende,
haga que se ejecute el constructor, provocara que el elemento esttico tendra siempre este
valor inicial asignado, hubo que implementar un mecanismo para hacer la inicializacin de los
atributos estticos. Este mecanismo consiste en hacer lo que se muestra en la parte superior
del cdigo de la Figura 4.22. Es como si se estuviera declarando de nuevo el atributo (de all
la colocacin del tipo de dato int), se asocia el atributo con la clase haciendo uso del operador
:: y se coloca el operador de asignacin = con el valor inicial (0 en este caso).
La Figura 4.23 muestra un ejemplo en Java en la cual se usa el atributo esttico NumInstancias,
el cual se puede inicializar en el momento de su declaracin ya que este lenguaje lo permite.
Ntese tambin en el ejemplo la declaracin del mtodo principal main que permite la ejecucin
del programa y que, como se explic anteriormente, debe ser esttico.
108
VOLVER A MEN
El cdigo de la Figura 4.24 es el equivalente al que se muestra en la Figura 4.23 pero en este
caso escrito en C#. La nica diferencia es que en C# el mtodo principal se identifica como
Main.
109
VOLVER A MEN
110
VOLVER A MEN
111
VOLVER A MEN
VOLVER A MEN
debe retornar un elemento del mismo tipo que sus operandos, >= debe retornar un valor
booleano, new debe retornar un apuntador o direccin de memoria).
VOLVER A MEN
es la razn por la cual la sobrecarga del operador de suma en el ejemplo de la Figura 4.27
retorna un objeto Complejo (el uso de los & en el ejemplo, tanto para el retorno como para
el parmetro formal, corresponde a la sintaxis de pasaje de parmetro por referencia y no es
obligatorio en este caso particular de la sobrecarga de operadores). En general esta regla
relativa a lo que debe retornar el mtodo debe ser as para cualquier operador asociativo que
se est sobrecargando. Escrito en trminos de acceso de los elementos del objeto mediante el
operador ., C1 + C2 + C3 es equivalente a hacer (C1.+(C2)).+(C3).
Nota: La sobrecarga de cualquier operador que es semnticamente asociativo,
implica necesariamente que el mtodo correspondiente debe retornar un objeto
equivalente a la clase en la cual se est agregando la sobrecarga del operador.
El ejemplo de la Figura 4.28 muestra la sobrecarga del operador unario de conversin explcita
de tipo (casting), en este caso para el tipo de dato double. Ntese el uso del operador en
la llamada del mensaje (al final del cdigo mostrado en el ejemplo). Ntese tambin que al
ser un operador unario, como se mencion anteriormente, el mtodo no tiene argumentos.
Adicionalmente y respetando la semntica de uso del operador, el tipo de retorno en este caso
no se coloca porque ya se asume por el identificador del operador que se est sobrecargando
(double). En este caso, el equivalente de hacer (double)C es hacer C.double().
Figura 4.28. Ejemplo de la sobrecarga del operador unario de conversin explcita double en C++.
114
VOLVER A MEN
VOLVER A MEN
Figura 4.31. Ejemplo de la sobrecarga de los operadores de conversin implcita y explcita en C#.
VOLVER A MEN
117
VOLVER A MEN
En la Figura 4.34 se muestra un ejemplo del uso de this en C#. En este caso su uso es
opcional ya que da lo mismo acceder a los elementos de la clase dentro de la clase con o sin
el uso de this.
4.13 Herencia
El mecanismo de herencia o especializacin de una clase a partir de otras se realiza
sintcticamente en C++ como se muestra en el ejemplo de la Figura 4.34. En este caso la
clase base o superclase es Carro y la clase derivada o subclase es Carga. Ntese que la
relacin de herencia se establece con el operador : luego de lo cual se debe indicar la interfaz
de la herencia (ver Seccin 2.4). Hay que tener en cuenta que, como ocurre en el ejemplo de
la Figura 4.35 con la clase Carro, cuando alguna de las clases base tiene un constructor
obligatorio (con argumentos), la clase derivada debe tambin poseer un constructor (con o sin
argumentos) que haga la llamada del constructor de la clase base. Ntese la manera como lo
anterior se realiza en la parte final del cdigo del ejemplo haciendo uso del operador :.
118
VOLVER A MEN
La Figura 4.36 presenta un ejemplo en la cual se realiza una herencia con interfaz
privada entre la clase derivada B y la clase base A. La tabla que aparece en la
derecha de la Figura 4.36 muestra los seis elementos que forman parte de B,
tres de los cuales (A1, A2 y A3) resultan como consecuencia de la herencia y
los otros tres (B1, B2 y B3) se definen propiamente dentro de B; se incluye
en la tabla si es posible (indicado con la marca de chequeo ) o no (indicado con
una ) tener acceso a esos elementos dentro de la clase B, en clases derivadas de
B o fuera de B. Ntese que A1 no puede accederse dentro de B porque es
privado para A y por lo tanto slo puede ser accedido dentro de A. Ntese tambin que
la herencia con interfaz privada no permite que el elemento pblico en A (identificado
como A3) pueda ser accedido fuera de B de la misma manera que lo hace el
elemento pblico definido en B (identificado como B3).
De la misma manera que en el caso anterior, el ejemplo de la Figura 4.37 muestra la herencia
con interfaz protegida. Ntese que la nica diferencia entre la tabla que aparece en este caso
comparada con la tabla de la Figura 4.36 es la posibilidad de que A3 pueda ser accedido por
las clases derivadas de C.
119
VOLVER A MEN
120
VOLVER A MEN
Figura 4.40. Ejemplo de cmo resolver ambigedades en una herencia mltiple en C++.
121
VOLVER A MEN
Sea el siguiente caso que se presenta a continuacin. Se tiene la clase Equipo que contiene
el atributo serial; se tienen las clases derivadas EquipoAudio y EquipoVideo que, por
herencia simple, son especializaciones de Equipo y que por lo tanto poseen un serial. Se
hace adicionalmente una nueva clase derivada EquipoAudiovisual que combina mediante
una herencia mltiple las caractersticas de EquipoAudio y EquipoVideo. Ntese que
como consecuencia de la herencia mltiple, EquipoAudiovisual va a tener no uno sino dos
atributos serial (ver parte superior del ejemplo de la Figura 4.41), lo cual es incorrecto para
este contexto. Para lidiar con esta situacin, C++ puede realizar una suerte de herencia virtual
indicado con la palabra reservada virtual y siguiendo la sintaxis que se muestra en la parte
inferior del ejemplo de la Figura 4.41. En este caso elementos que se identifican de la misma
manera y que pueden provenir de clases base diferentes son tratados como un solo elemento.
Es decir, un EquipoAudiovisual va a tener un nico atributo identificado como serial.
Figura 4.41. Ejemplo de cmo resolver redundancias en una herencia mltiple en C++.
122
VOLVER A MEN
En el caso de elementos que se identifiquen igual tanto en la clase base como en la clase
derivada, la manera de diferenciarlos en Java es utilizando el nombre de la clase y el operador
de acceso a los elementos .. En la Figura 4.43 se presenta un ejemplo con la clase base A,
la clase derivada B y el atributo comn I. Ntese la manera en la cual se hace referencia
a la I de A dentro de B mediante la operacin A.I. En el caso de los elementos pblicos
que se identifican igual, como la I en el ejemplo de la Figura 4.43, dado que A.I tambin es
pblico en B, no hay posibilidad fuera de B de diferenciar el acceso entre los dos elementos
que se identifican igual. Se asume siempre que es la I definida localmente en B.
Java no soporta la herencia mltiple; sin embargo, hace uso del concepto de interface para
especializar comportamientos en clases derivadas. A esta especializacin se le denomina
implementacin de la interface. Para ello se hace uso de la sintaxis que aparece en el
ejemplo de la Figura 4.44. La palabra reservada interface se usa para definir la interface y
123
VOLVER A MEN
Los creadores de Java aseguran que la herencia mltiple se puede implementar mediante
la herencia simple y la implementacin de una o ms interfaces. La Figura 4.45 presenta un
ejemplo en la cual la clase Subclase hereda de la clase Superclase e implementa de las
interfaces Interface1 e Interface2.
Figura 4.45. Ejemplo del uso combinado de la herencia y la implementacin de interfaces en Java.
Nota: El concepto de interface de Java no es una clase sino ms bien una plantilla
de comportamiento. Por lo tanto no es correcto hablar de herencia en este caso; es
por ello que se habla de implementacin de la interface.
VOLVER A MEN
ya que, al igual que Java, siempre se asume una interfaz de herencia pblica. Para hacer la
llamada del constructor de la clase base durante la construccin de la clase derivada se hace
uso del operador : (similar a C++) y se utiliza la palabra reservada base. Dado que C# al
igual que Java no soportan la herencia mltiple, no se requiere diferenciar una clase base de
otra ya que slo es posible tener una sola.
125
VOLVER A MEN
Como alternativa para emular una posible herencia mltiple, C# mantiene el mismo concepto
de implementacin de interfaces de Java. El concepto es completamente similar al definido por
Java con algunas diferencias menores. Como se puede ver en el ejemplo de la Figura 4.48 se
hace uso tambin de la palabra reservada interface para definir la interface y se mantiene
la sintaxis de la herencia : para implementar la interface. Por otro lado, dado que C# soporta
el concepto de atributos con las operaciones get y set, stos tambin estn sujetos a ser
incluidos en una interface para ser implementados. Un ejemplo de lo anterior lo representa el
atributo Frames y el mtodo get que aparecen en la Figura 4.48.
La Figura 4.49 muestra un ejemplo en la cual la clase Subclase hereda de la clase Superclase
e implementa de las interfaces Interface1 e Interface2.
Figura 4.49. Ejemplo del uso combinado de la herencia y la implementacin de interfaces en C#.
126
VOLVER A MEN
Figura 4.50. Ejemplo de la definicin de una clase abstracta y un mtodo virtual en C++.
En Java se utiliza la palabra reservada abstract para indicar explcitamente que una clase
es abstracta, como se muestra en el ejemplo de la Figura 4.51. Ntese que esta misma palabra
reservada es la que se utiliza tambin para indicar que un mtodo es virtual puro.
Figura 4.51. Ejemplo de la definicin de una clase abstracta y un mtodo virtual en Java.
C# mantiene la misma interface de Java con la palabra reservada abstract para indicar
que una clase es abstracta y un mtodo es virtual puro. A diferencia de Java, los mtodos
virtuales pueden o no ser redefinidos en clases derivadas al indicarlo explcitamente con las
palabras reservadas override y new respectivamente. La Figura 4.52 presenta el ejemplo
correspondiente a C#.
127
VOLVER A MEN
Figura 4.52. Ejemplo de la definicin de una clase abstracta y un mtodo virtual en C#.
Al igual que ocurre en C++, en C# hay manera de diferenciar un mtodo virtual puro de uno
que no lo es y para ello se hace uso tambin de la palabra reservada virtual. El ejemplo de
la Figura 4.53 muestra los mtodos virtuales no puros F1, F2 y F3 (ntese que hay una
definicin o cuerpo asociado a ellos) definidos en la clase base A. En la clase derivada B
se tiene una redefinicin de F1, una nueva versin de F2 (se tiene as un polimorfismo por
inclusin de F2) y una nueva versin de F3 que adems es virtual y que por lo tanto puede
ser redefinido o no en las posibles clases derivadas de B.
4.15 Paquetes
Los paquetes o agrupacin de elementos (clases por lo general) se manejan en C++ haciendo
uso del concepto de espacio de nombres. La palabra reservada para declarar y definir un
espacio de nombres es namespace (ver ejemplo en la Figura 4.54). Todo lo que se defina
dentro del inicio y fin (dado por los smbolos { y }) del espacio de nombres forma parte de
ese espacio de nombre o paquete. Como se muestra al final del ejemplo de la Figura 4.54,
para acceder a cualquier elemento definido dentro del paquete se hace uso del operador ::.
128
VOLVER A MEN
Por comodidad y a fin de evitar escribir tanto el nombre del paquete y el operador :: antes
de cada ocurrencia de los elementos correspondientes en el cdigo, se puede hacer uso de
la sintaxis que se muestra en la Figura 4.55 con la palabra reservada using namespace.
Quiere decir que desde este punto hasta que finaliza el bloque donde esta sentencia aparezca,
cualquier elemento que no puede ser ubicado en el contexto actual del cdigo, puede ser
buscado en el paquete indicado por el using namespace (identificado como Nuevo en el
ejemplo). Ntese tambin en el comienzo del ejemplo de la Figura 4.55 que es posible declarar
un espacio de nombres haciendo uso de otro identificador con el cual se haya declarado
previamente. En el caso especfico del ejemplo, Nuevo es un paquete que puede ser usado
tambin como nombre alternativo para el paquete MiPaquete.
VOLVER A MEN
Es importante tener en cuenta que en Java no slo los archivos de cdigo fuente (uno por cada
clase definida) se identifican de la misma manera que el nombre dado a las clases sino que
adems, el identificador del paquete coincide con el nombre del directorio donde se encuentran
todas las clases asociadas a ese paquete.
La Figura 4.56 muestra un ejemplo del uso de las palabras reservadas package e import
de Java. Para acceder a los elementos o clases del paquete haciendo uso del identificador
del paquete se utiliza el operador . (en el ejemplo se observa cuando se accede a la clase
MiClase que se supone ha sido definida y asociada al paquete MiPaquete). Ahora bien,
ntese que se muestran dos maneras diferentes de usar el import. En el caso de import
MiPaquete.Miclase se est indicando que se va a hacer uso de la clase especfica Miclase
que se supone est asociada al paquete MiPaquete. En el caso import MiPaquete.* se est
indicando que se puede hacer uso de cualquiera de las clases que estn asociadas al paquete
MiPaquete.
130
VOLVER A MEN
131
VOLVER A MEN
En el ejemplo de la Figura 4.59 se observa la razn de ser de la funcin amiga. Ntese cmo
en la funcin gtime se puede acceder al atributo secs definido como privado en la clase
Time haciendo uso del objeto x. Si gtime no fuera declarada como amiga en Time esto
sera un error de acceso no vlido de un elemento privado fuera de la clase.
VOLVER A MEN
En el ejemplo de la Figura 4.60 se est definiendo una plantilla para la funcin GetMax en la
cual se generaliza el tipo de dato del retorno y el tipo de dato de los parmetros. Ntese el uso
de T para representar el tipo de dato genrico. Ntese tambin el uso de los caracteres <
y > en la sintaxis. Se puede observar tambin la llamada de la funcin en dos ocasiones, la
primera haciendo uso de dos argumentos de tipo int y la segunda llamada haciendo uso de
parmetros del tipo long.
La Figura 4.61 contiene por otro lado, un ejemplo de una plantilla utilizada en la clase Par
para definir los atributos v1 y v2 y el tipo de dato de retorno del mtodo GetMax. Ntese
al final del ejemplo la manera en la cual se hace una instanciacin del objeto MiObjeto de la
clase Par indicando que la plantilla T corresponde al tipo de dato int.
Figura 4.61. Ejemplo del uso de plantillas en C++ para la generalizacin de una clase.
El concepto de plantillas en clases tambin puede ser usado para especializar clases nuevas.
En el ejemplo de la Figura 4.62 se puede observar cmo la clase Par y el uso de la plantilla
T se especializan en la clase Par <int> que se refiere a una versin de la clase Par en la
cual T se asocia al tipo de dato int.
133
VOLVER A MEN
Figura 4.62. Ejemplo del uso de plantillas en C++ para la especializacin de una clase.
Nota: Las plantillas en C++ son compiladas por demanda, es decir, el cdigo de las
plantillas de funciones no se compila hasta que no se tenga una instancia vlida y el
compilador conozca el tipo de dato que corresponde a esa instancia.
VOLVER A MEN
La Figura 4.65 muestra la sintaxis y uso del operador static_cast que permite ejecutar cualquier
conversin que puede ser realizada implcitamente de la misma forma que la conversin
inversa (an si no est permitida de forma implcita). Ntese en la Figura 4.65 que lo que se
est tratando de hacer es asignar el apuntador a relativo a una clase base A a un apuntador
relativo a una clase B derivada de A. Implcitamente es posible hacer una conversin de
una clase base a una clase derivada, ya que el espacio de memoria relativo a la clase derivada
incluye ya los elementos relativos a la clase base, ms la inversa no es posible hacerlo de
manera implcita y es por ello que se requiere el operador de conversin para hacerlo de
manera explcita.
VOLVER A MEN
Finalmente, se tiene el operador typeid que permite revisar el tipo resultante de una expresin.
Es til para hacer verificaciones antes de hacer una asignacin que pudiera no ser vlida.
VOLVER A MEN
definido en C3 est declarado como final y por lotanto cuando se intenta dar una
nueva definicin de este mtodo en la clase derivada C4, se genera un error de
compilacin.
Ntese que tanto para las clases finales como para los mtodos finales se usa la
declarativa o palabra reservada final.
VOLVER A MEN
Desde el punto de vista funcional las clases internas pueden acceder a todos los miembros
de la clase ms externa, incluyendo los elementos privados. Las clases internas pueden
hacerse pblicas o privadas dependiendo si se desea o no permitir la instanciacin de objetos
correspondientes fuera del contexto de la clase externa que contiene sus definiciones. Tal
como se observa en la Figura 4.70, el concepto de anidamiento tambin aplica a enumerados
(enum) al igual que con las interfaces (interface).
138
VOLVER A MEN
139
VOLVER A MEN
4.16.3.3 Indexadores
Este concepto de C# permite representar la sobrecarga de un operador para indexar un
conjunto de atributos de la clase. Se define como una mezcla entre el manejo de atributos y la
manera como se indexan los arreglos.
Como se puede ver en el ejemplo de la Figura 4.73, adems de la declarativa de interfaz y
el tipo de dato, se usa la palabra reservada this con una indicacin del tipo de dato que
va a representar el ndice con la cual se va a acceder a los elementos, ste encerrado entre
corchetes [ y ] (similar a la forma como de declaran los arreglos). Al igual que ocurre con
el concepto de atributo de C#, a los indexadores se le pueden definir las operaciones get y
set correspondientes.
140
VOLVER A MEN
141
VOLVER A MEN
VOLVER A MEN
4.16.3.7 Atributos
Ese concepto de C#, que no se refiere ni al concepto de atributo de una clase, ni al concepto
particular de atributo que contiene C# con las operaciones get y set, permite incluir directivas
en las clases y en sus miembros para mejorar su declaracin mediante informacin que es
interpretada por otras clases en tiempo real.
Se pueden usar tanto los atributos predefinidos en el lenguaje como tambin aquellos que
son personalizados por el programador. Desde el punto de vista sintctico, los atributos se
escriben entre corchetes [ y ] y deben aparecer inmediatamente antes de la declaracin en
la cual se desea se aplique el atributo (por ejemplo, [MiAtributo]). Los atributos pueden ser
aplicados en cualquier declaracin vlida en C#: clases, miembros de la clase, estructuras,
interfaces, miembros de la interfaz, enumerados, miembros de los enumerados y delegados.
Adicionalmente, al atributo se le puede anteponer un modificador que defina el elemento
al que se aplica el atributo, tambin llamado enlazador de un atributo. Para estos casos el
modificador y el atributo se enlazan con el caracter : ([MiEnlace:MiAtributo] por ejemplo).
Finalmente, algunos atributos tambin tienen la posibilidad de aceptar parmetros (por ejemplo,
[MiAtributo(Parmetros)]).
Como se mencion anteriormente, existe la posibilidad de definir atributos personalizados.
Para ello es necesario escribir clases de atributos propias como resultado de hacer una
derivacin de la clase predefinida Attribute, perteneciente al espacio de nombres System.
La Figura 4.78 muestra un ejemplo donde se est presentando la definicin de la clase de
atributo CodeAuthorAttribute. Ms abajo en el mismo ejemplo aparecen las dos maneras en
las cuales se usa el mismo atributo; ntese que el sufijo Attribute es opcional.
143
VOLVER A MEN
4.17 Ejercicios
1) Se desea implementar una clase para la representacin y manejo de un reloj. Un objeto
reloj puede ser creado con una hora militar inicial vlida cualquiera expresada con los tres
valores: hora (entre 0 y 23), minuto (entre 0 y 59) y segundo (entre 0 y 59). En caso de no
dar una hora inicial en tiempo de instanciacin del objeto, el reloj tendr una hora inicial
equivalente a 0 horas, 0 minutos y 0 segundos. Adems de retornar los componentes
de la hora actual, el reloj tiene el mtodo tick() que permite aumentar la hora en un
segundo. Tambin est el mtodo cambiar(h, m, s) para modificar la hora actual segn
los parmetros dados.
2) Se desea implementar una clase para la representacin y manejo de una fecha. Un objeto
fecha puede ser creado con una fecha inicial vlida cualquiera expresada con los tres
valores: da (entre 1 y 31), mes (entre 1 y 11) y ao (mayor que 1800). En caso de no dar
una fecha inicial en tiempo de instanciacin del objeto, el objeto tendr una fecha inicial
144
VOLVER A MEN
VOLVER A MEN
6) Escriba una clase Esfera que contenga un dato que represente el dimetro de una
esfera. Agregue un constructor para que reciba el valor inicial del dimetro. Incluya tambin
mtodos para consultar y cambiar el dimetro, as como tambin un mtodo que calcule
y retorne el volumen del rea superficial de la esfera (4r2). Incluya tambin el mtodo
toString que retorna una descripcin de la esfera (indicada por su dimetro) como cadena
de caracteres.
7) Escriba una clase Caja que contenga los datos para representar el alto, ancho y profundidad
de una caja. Incluya tambin un atributo de tipo booleano que indique si la caja est o
no llena. El constructor asociado a una caja debe inicializar los datos de altura, ancho y
profundidad e indicar que la caja est vaca. Incluya mtodos para consulta y modificacin
de los datos, as como tambin los mtodos para llenar y vaciar la caja. Agregue tambin
un mtodo para calcular y retornar el volumen de la caja (alto x ancho x profundidad).
8) Defina de forma completa (estructura y cuerpo de los mtodos) la clase Integer25 que
permita representar nmeros enteros grandes de a lo sumo 25 dgitos y las operaciones de
suma, resta, divisin y multiplicacin representada por los smbolos +, -, / y * respectivamente.
9) Escriba las estructuras de una clase para la representacin y manejo de rboles binarios
cuyos nodos contengan objetos del tipo Integer25.
10) Escriba el enunciado de una clase abstracta para la creacin y manejo de elementos
grficos. Un elemento grfico debe tener una posicin (izquierda, superior) en pantalla y
las dimensiones (ancho y alto) en pxeles. Tambin debe tener un nombre que lo identifique
y la referencia a un padre que lo contiene que es tambin un elemento grfico y que debe
ser dado en tiempo de creacin del objeto. La dimensin, tamao y nombre del elemento
se puedan dar opcionalmente en la construccin del objeto, en caso contrario se asumen
valores por defecto. Cada elemento grfico contiene tambin una lista de los elementos hijos
asociados. El comportamiento de un elemento grfico debe ser tal que permita modificar
la posicin y dimensiones del objeto, adems de agregar, suprimir y buscar elementos
hijos de su lista de descendientes a partir del nombre del elemento. El refrescamiento o
visualizacin del objeto depende del tipo de elemento que se defina.
11) Haciendo uso de la definicin anterior, escriba el enunciado de una clase que permita
146
VOLVER A MEN
definir elementos grficos del tipo lista de cadenas de caracteres con el comportamiento
grfico y el correspondiente para el manejo de su lista de textos.
12) A continuacin se ilustra el comportamiento de un objeto para el manejo de nmeros
en notacin romana (usando C++). Defina de forma completa en C++ la clase Romano
para tener el manejo de objetos antes ilustrado. Asuma que existen las funciones char
*IntToRom(int) e int RomToInt(char *) para hacer la conversin entre nmeros enteros y
nmeros romanos. Por defecto se asume un valor igual a 1 (I) para los nmeros romanos.
Romano R1, R2(X), R3 = R2, R4(10), *R5 = (Romano *)new Romano(MMI);
int I = (int)R3;
R1 = R4 + R2 + R3++;
if (R1
if (R1
if (R1
if (R1
if (R1
if (R1
delete
== R2)
> R2)
>= R2)
< R2)
<= R2)
!= R2)
R5;
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
Iguales;
Mayor que;
Mayor o igual;
Menor que;
Meyor o igual;
Diferentes;
13) Implemente el mismo ejercicio anterior pero esta vez haciendo uso de Java y/o C#.
14) Defina de forma completa (estructura y cuerpo de los mtodos) la clase Boolean que permita
representar nmeros booleanos con las operaciones And, Or, Xor y Not representado por
los smbolos &, |, ^ y ! respectivamente.
15) Escriba una clase para el manejo de un diccionario de datos. Consiste en una estructura
que permite almacenar palabras o conceptos y sus respectivas definiciones, recuperar
las definiciones una vez dada la palabra, eliminar palabras y modificar definiciones de
una palabra dada. Con el fin de agilizar la bsqueda, las palabras se deben organizar
en conjuntos segn su letra inicial, de manera que todas las palabras que comienzan
con la letra A estarn en un mismo conjunto, las que comienzan con la letra B en otro
conjunto y as sucesivamente. La clase debe ser desarrollada completamente, incluyendo
los mtodos.
147
VOLVER A MEN
Captulo 5
148
VOLVER A MEN
Como se observa en la parte izquierda de la Figura 5.1, el proceso metodolgico sugerido para
construir un software OO sigue el mismo conjunto de pasos que comnmente se observan en
una metodologa de desarrollo de software en general. Se tienen las siguientes etapas:
1) Anlisis OO: Tiene que ver con la revisin de los requerimientos del problema y el modelo
conceptual de la solucin. Ver detalles en la Seccin 5.2.
2) Diseo OO: Corresponde a la especificacin de los detalles del modelo y la preparacin
para realizar la codificacin de la solucin. Ver detalles en la Seccin 5.3.
3) Codificacin OO: Se trata de la programacin OO basado en el diseo realizado haciendo
uso de un lenguaje OO (ver Captulo 4).
4) Prueba: Tiene que ver con la verificacin del desarrollo realizado y est basado en la
satisfaccin de los requerimientos del problema.
5) Modificacin: Corresponde al mantenimiento que se debe realizar al desarrollo para
permitir la durabilidad del software realizado.
Ntese que el proceso metodolgico contempla el regreso a las fases anteriores cuando esto
es necesario. Por ejemplo, si una prueba no es satisfecha puede implicar tanto regresar a
149
VOLVER A MEN
5.2 Anlisis OO
Dicho de una manera muy sintetizada, el anlisis OO corresponde a la descomposicin de un
problema en sus partes. El propsito es modelar un problema basado en conceptos del mundo
real de forma tal que ste se pueda entender y que satisfaga el conjunto de requerimientos
definidos. Lo que se busca como resultado es un problema entendido como una preparacin
para ir al diseo.
Como se mencion anteriormente, el anlisis OO se preocupa ms por identificar los tipos de
objetos que por detallar o identificar los objetos individuales. Adicionalmente, es la primera
oportunidad para identificar la reutilizacin de componentes existentes. Por otro lado, esta
etapa del proceso requiere de la realizacin de dos partes:
1) El anlisis de requerimientos.
2) El anlisis de estructuras o modelado de objetos.
El anlisis de requerimientos tiene que ver con decidir lo que tiene y lo que no tiene que hacer
el sistema por un lado y asegurar que el sistema satisfaga las necesidades de sus usuarios;
para ello es necesario definir los criterios de aceptacin. El principal producto relacionado con
150
VOLVER A MEN
esta parte del anlisis est basado con la identificacin y prueba de los requerimientos lo cual
viene dado principalmente por los diagramas de casos de uso de UML.
El anlisis de estructuras tiene que ver con la descomposicin del problema en sus partes. El
principal producto relacionado con esta parte del anlisis est basado con el modelo de clases
del problema lo cual viene dado principalmente por el diagrama de clases de UML.
Desde el punto de vista de la metodologa presentada en este captulo, el anlisis OO requiere
de cuatro pasos:
1)
2)
3)
4)
Figura 5.2. Ejemplo de mapa mental realizado en XMind 2012, versin 3.3.0.
151
VOLVER A MEN
152
VOLVER A MEN
El segundo objetivo de este paso es identificar las relaciones o asociaciones entre los conceptos
y/o clases seleccionados. Para ello tambin es recomendable aplicar criterios para saber si las
asociaciones son o no correctas (ver detalles a continuacin).
La lista de clases y asociaciones permite luego que sean representadas en un diagrama de
clases sin niveles de detalle de UML. Sin nivel de detalle quiere decir que no se especifican
los elementos (atributos y mtodos) de las clases. Es recomendable que las relaciones entre
clases incluyan tambin los posibles roles (breve descripcin de su objetivo) y la multiplicidad
(nmero de elementos involucrados en la relacin).
VOLVER A MEN
atributos de la clase estudiante. Si, por otro lado, el contexto del problema es el sistema de
correo entonces direccin debera ser tratado como una clase por su importancia conceptual
en este problema.
Clase u operacin: el objetivo de este criterio es no hacer una clase con un nombre que describe
una operacin (mtodo) que es aplicada a objetos o instancias de las clases ya identificadas
o por identificar. Sin embargo, una operacin que tiene caractersticas propias relevantes para
el contexto del problema tratado debe ser modelada como una clase. Por ejemplo, cuando el
contexto del problema es el telfono, la llamada telefnica es un mtodo de la clase telfono
pero, si el contexto del problema es la facturacin telefnica, llamada telefnica debe ser
una clase porque tiene la riqueza conceptual necesaria para ello como por ejemplo atributos
necesarios para representar la duracin de la llamada, la tarifa aplicada, entre otros y tambin
mtodos para iniciar la llamada, culminar la llamada, entre otros.
Clase o asociacin: este criterio establece que el nombre de una clase debe reflejar su
naturaleza intrnseca y no un role que otras posibles clases juegan en una asociacin. En el
contexto de un problema de produccin de carros por ejemplo, propietario no es una clase
sino la asociacin que se da entre las clases persona y carro.
Uso de implementaciones: tiene que ver con implementaciones externas al problema tratado
(seguramente pertenecientes a una biblioteca de clases, basado en la reutilizacin de
elementos). Si bien estos casos son importantes para el modelo del problema, no se deben
agregar en el proceso de anlisis con el objeto de simplificar el modelo en estas primeras
etapas de su elaboracin. Probablemente se requieran agregar luego al modelo en la etapa de
diseo. Algunos ejemplos son: CPU, subrutina, proceso, algoritmo, interrupcin, lista
enlazada, arreglo, rbol, conjunto, tabla y los elementos de interfaz como ventana,
botn, entre otros.
VOLVER A MEN
que el banco presta a sus clientes. En otro ejemplo asociado al mismo problema,
la asociacin ATM tiene impresora entre las clases ATM e impresora, tiene que
ver con la implementacin del ATM y por ende es irrelevante para el anlisis.
Acciones: el objetivo de este criterio es establecer una diferenciacin entre una
asociacin y un evento o accin; una asociacin debe describir una propiedad
estructural del dominio del sistema a modelar y no un evento representado como
el envo de un mensaje entre objetos. En este sentido, un requerimiento expresado
como una accin puede implicar una relacin estructural y debe ser rescrito
acordemente. Por ejemplo, ATM acepta tarjetas de dbito describe parte de un
ciclo de interaccin entre las clases ATM y cliente probablemente representado
con un mensaje que un objeto de la clase cliente enva haciendo uso de un
mtodo de la clase ATM; no debe ser tratado como una relacin entre ATM y
tarjeta de dbito. En otro ejemplo, computador central transfiere transaccin
con banco describe una accin implcita en la asociacin computador central se
comunica con el banco.
Asociaciones ternarias: muchas asociaciones entre tres o ms clases se pueden
descomponer en asociaciones binarias o rescritas como asociaciones cualificadas. En
este ltimo caso, si un trmino en una asociacin ternaria es puramente descriptivo
y no tiene caractersticas propias, entonces este trmino es un atributo que puede
ser utilizado como enlace en una asociacin binaria cualificada. Por ejemplo,
en la asociacin cajeros introducen transacciones de cuentas en la cual estn
involucradas las clases cajero, transaccin y cuenta, se puede romper en las
siguientes dos asociaciones: cajeros introducen transacciones y transacciones
tienen que ver con cuentas. En un segundo ejemplo, la asociacin compaa
emplea personas con un sueldo que involucra las clases compaa, persona y
sueldo, se puede escribir mediante el siguiente par de asociaciones: compaa
emplea personas y persona tiene que ver con un sueldo.
Asociaciones derivadas: aquellas asociaciones que pueden ser definidas en trminos
de otras asociaciones deben ser omitidas ya que son redundantes. Por ejemplo,
abuelo de puede ser definido usando un par de relaciones del tipo padre de.
Por otro lado, tambin hay que omitir las asociaciones definidas por condiciones
en los atributos. Por ejemplo, ms joven que expresa una condicin en la edad de dos
personas (siendo edad un atributo de la clase persona), no es informacin
adicional al modelo.
155
VOLVER A MEN
Nota: Tanto como sea posible, las clases, los atributos y las asociaciones deben
representar informacin independiente. Muchos caminos entre clases a veces
indican asociaciones derivadas que estn compuestas por asociaciones primitivas.
Por ejemplo, consorcio comparte ATM es una composicin de consorcio tiene
computador central y computador central se comunica con los ATM.
Nota: Hay que tener cuidado porque no todas las asociaciones que forman mltiples
caminos entre clases indican redundancia. Algunas veces la existencia de una
asociacin puede ser derivada de dos o ms asociaciones primitivas. Aunque las
asociaciones derivadas no agregan informacin, son tiles para el diseo.
5.2.4.3 Ejemplos.
Ejemplo 1: Una compaa emplea a muchas personas y es propietaria de muchas computadoras;
a cada empleado se le puede asignar alguna de estas computadoras para su uso personal.
Se identifican los siguientes nombres: compaa, persona, computadora y empleado. Luego de
aplicar los criterios para identificar clases incorrectas o innecesarias, se observa que persona
y empleado son conceptos redundantes siendo empleado el concepto ms adecuado
de utilizar en este contexto de problema especfico. Por lo tanto, un modelo conceptual
OO del enunciado del problema presenta las siguientes clases: compaa, empleado y
computadora.
Por otro lado, se observan las siguientes asociaciones: compaa emplea empleado,
compaa posee computadora y computadora es asignada a empleado. Se obtiene por lo
tanto el diagrama de clases que se muestra en la Figura 5.3. Ntese el uso de las multiplicidades
en las asociaciones.
156
VOLVER A MEN
Ejemplo 2 (Rumbaugh et al, 1990): Una red bancaria computarizada incluye tanto cajeros
humanos como automticos (ATM), stos ltimos compartidos por un consorcio de bancos.
Cada banco provee su propia computadora para mantener sus propias cuentas y procesar
las transacciones contra ellas. Las estaciones de los cajeros son propias de cada banco
y se comunican directamente con la computadora propia del banco. Los cajeros humanos
introducen datos de cuentas y transaccin. Los ATM se comunican con un computador central
el cual transfiere las transacciones con los bancos apropiados. Un ATM acepta una tarjeta
de dbito, interacta con el usuario, se comunica con el sistema central para llevar a cabo la
transaccin, dispensa efectivo e imprime un recibo. El sistema requiere de mecanismos de
seguridad y auditoria adecuados. El sistema puede manejar acceso concurrente a la misma
cuenta. Los bancos proveen su propio software para sus propias computadoras. El costo del
sistema compartido es distribuido por los bancos segn el nmero de clientes con tarjetas de
dbito.
Se identifican los siguientes nombres: red bancaria, cajero, ATM, consorcio, banco,
computadora-banco, cuenta, transaccin, estacin-cajero, datos-cuenta, datos-transaccin,
computador-central, tarjeta-dbito, usuario, sistema, efectivo, recibo, mecanismos-seguridad,
mecanismos-auditoria, acceso, software, costo y cliente.
Al aplicar los criterios para identificar clases incorrectas o innecesarias, se tiene lo siguiente:
Clases vagas: sistema, mecanismos-seguridad, mecanismos-auditoria y red-bancaria
Atributos: datos-cuenta, datos-transaccin, recibo y efectivo.
Clases irrelevantes: costo.
Clases redundantes: usuario con cliente.
Implementaciones: acceso y software.
Luego de la aplicacin de los criterios se identifican los siguientes conceptos o clases definitivas:
cuenta, ATM, banco, computadora-banco, tarjeta-dbito, cajero, estacin-cajero, computadorcentral. Como consecuencia y luego de avanzar en el anlisis y algunas etapas del diseo, se
tiene una versin del diagrama de clases incompleto que se muestra en la Figura 5.4. Ntese
el uso de las asociaciones. Se incluyen tambin algunos atributos.
157
VOLVER A MEN
5.3 Diseo OO
Tiene que ver con la especificacin de todos los detalles necesarios que deben ser incluidos
en el modelo y que no se hicieron en el anlisis teniendo en cuenta la visin global del
problema. El detalle ms relevante a considerar est dado por las definiciones completas de
las clases y asociaciones incluyendo los algoritmos de los mtodos usados para implementar
las operaciones. El propsito principal es agregar los detalles faltantes y tomar decisiones de
implementacin. El resultado es un producto intermedio entre anlisis y programacin para
facilitar el trabajo de implementacin.
Usualmente el diseo se deriva directamente del anlisis pero a veces es necesario agregar
nuevas clases y/o atributos para mejorar el modelo. Los principales productos asociados a esta
fase del proceso metodolgico estn relacionados con el modelo detallado de clases (modelo
esttico) y los flujos de estados e intercambio de mensajes entre elementos para satisfacer los
requerimientos del problema (modelo dinmico).
Desde el punto de vista de la metodologa presentada en este captulo el diseo OO requiere
de seis pasos:
1) Definir la arquitectura de la solucin.
2) Detallar las clases.
3) Desarrollar los modelos de estado.
158
VOLVER A MEN
159
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
5.4 Resumen
La Tabla 5.1 muestra un resumen del proceso metodolgico con los cuatro pasos del anlisis
y los seis pasos del diseo indicando en cada caso los productos parciales correspondientes.
Tabla 5.1. Resumen del proceso metodolgico.
Anlisis
Paso
Descripcin
Producto
Lista de nombres
Paso
Descripcin
Producto
Arquitectura
Informe de pruebas
Diseo
162
VOLVER A MEN
5.5 Ejemplo
Un reloj digital consta de dos paneles digitales (pantallas), uno para mostrar la hora y el otro
para mostrar los minutos actuales. El primero, por lo tanto, muestra valores entre 0 y 23 y
el segundo entre 0 y 59. Un usuario del reloj debe poder inicializar el reloj (colocar un valor
igual a 0 en cada panel); debe poder incrementar el reloj tanto por minutos como por horas;
poder poner en hora el reloj a un valor cualquiera y observar del reloj el valor u hora actual en
todo momento. La Figura 5.6 muestra una representacin grfica de un reloj digital como se
describe anteriormente.
5.4.1 Anlisis
Paso 1. Identificar la idea y objetivos bsicos del sistema. El enunciado del ejercicio ya es lo
suficientemente explcito para cubrir este paso. Sin embargo, es posible extraer las siguientes
oraciones:
El reloj tiene dos paneles: hora y minuto.
Los paneles son digitales, es decir, muestran dgitos.
La interaccin con el reloj la realiza un usuario.
El usuario puede inicializar el reloj, cambiar la hora y ver en todo momento la hora actual.
Paso 2. Identificar actores / nombres. Al analizar las oraciones del paso anterior se pueden
identificar directamente los siguientes nombres: usuario, reloj y panel. Por otro lado, se menciona
que los paneles son digitales por lo tanto se hace alusin al nombre dgito y si se quiere ser
ms especfico, al observar cada dgito que se presenta en la Figura 5.6, se nota la presencia
de segmentos (en la Figura 5.6 se observan seis segmentos para representar el dgito 0; sin
embargo se requieren siete segmentos en total para representar todos los dgitos, siendo el 8
el que requiere tener los siete segmentos encendidos).
Paso 3. Identificar procesos / requerimientos. Los requerimientos de este problema estn muy
claros. El usuario debe poder: 1) inicializar el reloj; 2) incrementar los minutos; 3) incrementar
las horas; 4) asignar una hora cualquiera y 5) ver la hora actual en todo momento. En este
163
VOLVER A MEN
sentido, se tiene el diagrama de casos de uso que se muestra en la Figura 5.7. Ntese que
los cinco requerimientos antes mencionados tienen interaccin directa con el actor Usuario;
ntese tambin la manera en la cual el sentido de la asociacin entre el actor y estos casos
de uso corresponde con la semntica de interpretacin del requerimiento. Se incluyen tambin
algunos casos de uso que se deben realizar obligatoriamente (asociacin del tipo include)
para realizar los anteriores.
164
VOLVER A MEN
5.4.2 Diseo
Paso 1. Definir la arquitectura de la solucin. En este caso el problema tiene un bajo nivel
de complejidad y por lo tanto la arquitectura no contempla muchos elementos de interaccin
como por ejemplo bases de datos y otros sistemas. Se tiene tan solo un formulario de interfaz
que permita la interaccin del usuario con la instancia de un reloj, similar por ejemplo a la
representacin grfica de la Figura 5.6.
Paso 2. Detallar las clases. La Figura 5.9 presenta el diagrama detallado de clases relativo a
este problema con la incorporacin de los atributos y mtodos necesarios para completar el
modelo y satisfacer las necesidades requeridas. Ntese que el reloj tiene la interfaz necesaria
para satisfacer los requerimientos representados en el diagrama de casos de uso. Ntese
tambin las dos restricciones asociados al reloj. Observe que todos los atributos son privados
y todos los mtodos son pblicos.
Paso 3. Desarrollar los modelos de estado. La Figura 5.10 muestra el diagrama de estados
asociado a la clase Segmento. Se tienen dos estados: el segmento apagado (Estado = Falso)
y el segmento encendido (Estado = Verdadero); el mtodo Apagar() lleva el objeto al estado
Apagado y el mtodo Encender() lleva el objeto al estado Encendido. Ntese tambin
que el objeto inicia o se construye con el estado Apagado y puede ser destruido estando en
cualquiera de los dos estados.
165
VOLVER A MEN
VOLVER A MEN
Figura 5.13. Diagrama de colaboracin y secuencia asociado al caso de uso inicializar el reloj.
167
VOLVER A MEN
Figura 5.14. Diagrama de colaboracin y secuencia asociado al caso de uso incrementar hora del reloj.
Los diagramas de colaboracin y secuencia relativos al caso de uso Asignar valor al reloj se
muestran en la Figura 5.15. Finalmente, la Figura 5.16 muestra los diagramas de colaboracin
y secuencia del caso de uso Mostrar hora actual del reloj. Ntese en este ltimo caso, el
retorno representado entre el objeto de la clase Reloj y el Usuario (actor) respetando as
el sentido de la interaccin entre el caso de uso y el actor que se muestra en el diagrama de
casos de uso de la Figura 5.7.
168
VOLVER A MEN
Figura 5.15. Diagrama de colaboracin y secuencia asociado al caso de uso Asignar valor al reloj.
Figura 5.16. Diagrama de colaboracin y secuencia asociado al caso de uso Mostrar hora actual del reloj.
169
VOLVER A MEN
Paso 5. Identificar componentes del dominio. Este paso tiene que ver con la manera en la cual
se desarrolla el modelo y los elementos de software que se originan al respecto. Asumiendo un
desarrollo en Java se tienen cuatro componentes cada uno de los cuales corresponde a cada
clase del modelo, todas ellas asociadas al paquete RelojDigital. La Figura 5.17 muestra el
diagrama de componentes correspondiente.
Por otro lado, para la ejecucin del software que resulta de este modelo se tiene el elemento
de software Reloj.class que resulta luego de la compilacin de Reloj.java; este elemento
debe ser ejecutado en un nodo que tenga la mquina virtual de Java. Esto se puede reflejar en
el diagrama de distribucin que se muestra en la Figura 5.18.
170
VOLVER A MEN
5.6 Ejercicios
1) Cul es la diferencia entre modelo esttico y modelo dinmico? Qu diagramas UML
corresponden a cada uno de estos modelos?
2) Por qu es necesario para el proceso metodolgico hacer un diagrama de estados por
cada clase identificada en el diagrama de clases?
3) Por qu es necesario para el proceso metodolgico hacer un diagrama de colaboracin
o secuencia por cada caso de uso con asociacin directa a un actor definidos en los
diagramas de casos de uso?
4) Para los ejercicios que se encuentran en la Seccin 3.6, complemente el modelo siguiendo
el proceso metodolgico tal como se mostr en el ejemplo de la Seccin 5.5.
171
VOLVER A MEN
Captulo 6
VOLVER A MEN
protocols.netlab.uky.edu/~xiwei/cs215_fall2011/qt-sdk-win -opensource-2010.02.1.exe).
4) La programacin Java fue realizada en la plataforma de desarrollo NetBeans IDE 7.3
(http://netbeans.org/) haciendo uso del kit de desarrollo JavaTM SE Development Kit 7u17
(http://www. oracle.com/technetwork/java/javase/downloads/index.html).
5) La programacin en C# fue realizada en la plataforma de desarrollo SharpDevelop versin
4.2.1 (http://www.icsharpcode.net/Open Source/SD/).
Cabe mencionar que, si bien los casos prcticos fueron resueltos haciendo uso de la metodologa
presentada en el Captulo 5, en algunos casos se obvian alguno de los pasos y/o no se realiza
la totalidad de los diagramas UML que se deben hacer. En el caso particular del paso 5 del
diseo referido a los componentes del dominio, dado que tiene una dependencia directa del
lenguaje de programacin utilizado para una implementacin especfica, estos se realizan slo
asumiendo alguno de los tres posibles lenguajes (C++, Java y C#). Adicionalmente, no se
agrega en ninguno de los casos el paso 6 del diseo referido a la prueba de componentes y
clases.
173
Descripcin
VOLVER A MEN
Operacin
Operandos
Suma o adicin
Resta o sustraccin
Producto o multiplicacin
Divisin entera
Cambio de signo
&
<
>
VOLVER A MEN
6.2.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): Luego de hacer una revisin del
texto del enunciado se tiene un mapa mental equivalente al que se muestra en la Figura 6.1.
175
VOLVER A MEN
VOLVER A MEN
6.2.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): Se trata de un problema cuya implementacin
requiere de un programa sin interaccin con ningn otro elemento de software. Se sabe que
la interfaz es modo texto.
Paso 2 (Detallar las clases): Al agregar los atributos y mtodos a las clases de la Figura 6.3,
resulta el diagrama de clases detallado de la Figura 6.4. Ntese el tipo de dato de los atributos
(a la derecha, despus de :); el tipo de dato de retorno de los mtodos expresados como un
estereotipo (encerrados entre << y >>); el uso de parmetros en los mtodos (encerrados
entre ( y )), si aplica, y los valores iniciales de alguno de los atributos (a la derecha luego del
smbolo de igualdad =).
Paso 3 (Desarrollar los modelos de estado): Sabiendo que los modelos de estados se
determinan revisando el cambio de los atributos de cada una de las clases originado por la
ejecucin de los mensajes correspondientes, es de notar que en la clase Calculadora los
177
VOLVER A MEN
178
VOLVER A MEN
Paso 5 (Identificar componentes del dominio): Asumiendo el uso de C++ para la implementacin
de este caso prctico, el diagrama de componentes correspondiente al problema se presenta
en la Figura 6.7. Ntese que, dado la simplicidad del ejercicio, solo se contempla un archivo
de cdigo fuente (Calculadora.cpp) con el archivo encabezado asociado (Calculadora.hpp),
cuya compilacin origina el programa (Calculadora.Exe).
6.2.4 Programacin
A continuacin el cdigo fuente escrito en C++ relativo al problema de la calculadora. Se
muestra primero el archivo encabezado Calculadora.hpp en el cual se encuentran las
declaraciones de las clases identificadas en el diseo (ntese la analoga entre lo previamente
diseado y lo programado). Se utiliz el concepto de plantillas (template) para generalizar la
implementacin de la computadora a un tipo de dato numrico mayor no necesariamente igual
a 1 byte.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.2
* Calculadora.hpp
* Mauricio Paletta
*/
179
VOLVER A MEN
#ifndef CALCULADORA_HPP
#define CALCULADORA_HPP
#include TrimString.hpp
// Tipos posibles de operaciones
//
enum TipoOperacion {
Ayuda, Binario, Decimal, Hexa, Salir, MemoriaActual, BaseActual,
Suma, Resta, Multiplicacion, Division, Signo, Modulo,
Conjuncion, Disyuncion, Exclusivo, Complemento, Izquierda, Derecha
};
// Tipos posibles de base de representacin
//
enum TipoBase {
Base2 = 2, Base10 = 10, Base16 = 16
};
// Representa la memoria de la calculadora
//
template <class TByte>
class Memoria {
private:
TByte Valor;
public:
Memoria() { Valor = 0; }
TByte ObtValor() { return Valor; }
void AsgValor(TByte V) { Valor = V; }
};
// Representa un Comando
//
180
VOLVER A MEN
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.2
* Calculadora.cpp
* Mauricio Paletta
*/
#include <iostream>
182
VOLVER A MEN
#include <cstdlib>
#include <math.h>
#include <stdio.h>
#include Calculadora.hpp
using namespace std;
/ Mtodos de la clase Operacion
//
// Convierte una cadena de caracteres que se supone est en binario
// a su equivalente en nmero decimal
//
template <class TByte>
TByte Operacion<TByte>::BinADec(TrimString B) {
TByte N = 0, P = 0, S = 1, T = 0;
if (B.length() == 8 * sizeof(TByte) && B[0] == 1) {
S = -1;
T = 1;
}
for (int i=B.length()-1; i >= T; i--) {
switch (B[i]) {
case 1:
N += (int)pow(2, P);
case 0:
break;
default:
return 0;
}
P++;
}
183
VOLVER A MEN
return S * N;
}
// Convierte un nmero decimal en la cadena de caracteres
// equivalente en binario
//
template <class TByte>
TrimString Operacion<TByte>::DecABin(TByte D) {
char Aux[120];
TrimString S;
S = TrimString(ltoa((long)D, Aux, 2));
if (S.length() > 8 * sizeof(TByte)) S = S.substr(S.length() - (8 * sizeof(TByte)), 8 * sizeof(TByte));
return S;
}
// Convierte una cadena de caracteres que se supone est en hexadecimal
// a su equivalente en nmero decimal
//
template <class TByte>
TByte Operacion<TByte>::HexADec(TrimString H) {
TByte N = 0, P = 0, B, S = 1;
for (int i=H.length()-1; i >= 0; i--) {
switch (H[i]) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
184
VOLVER A MEN
case 9:
B = H[i] - 0;
break;
case A:
case B:
case C:
case D:
case E:
case F:
B = 10 + (H[i] - A);
break;
case a:
case b:
case c:
case d:
case e:
case f:
B = 10 + (H[i] - a);
break;
default:
return 0;
}
if (H.length() == 2 * sizeof(TByte) && i == 0 && B >= 8) {
S = -1;
B -= 8;
}
N += B * (TByte)pow(16, P++);
}
return S * N;
}
185
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
S = DecABin(N);
if (S.length() > 8 * sizeof(TByte)) S = S.substr(S.length() - (8 * sizeof(TByte)), 8 *
sizeof(TByte));
break;
case Base10:
S = TrimString(ltoa((long)N, Aux, 10));
break;
case Base16:
S = DecAHex(N);
if (S.length() > 2 * sizeof(TByte)) S = S.substr(S.length() - (2 * sizeof(TByte)), 2 *
sizeof(TByte));
break;
}
return S;
}
// Mtodos de la clase Calculadora
//
template <class TByte>
Calculadora<TByte>::Calculadora(TrimString I, int N) {
Indicador = I; NumBytes = N; Base = Base10;
T = new Memoria<TByte>();
}
template <class TByte>
Calculadora<TByte>::~Calculadora() {
delete T;
}
template <class TByte>
void Calculadora<TByte>::AsgNumBytes(int N) {
delete T;
switch (N) {
189
VOLVER A MEN
case 1:
T = new Memoria<char>();
break;
case 2:
T = new Memoria<short>();
break;
case 4:
T = new Memoria<int>();
break;
default:
N = 8;
T = new Memoria<long>();
break;
}
NumBytes = N;
}
template <class TByte>
void Calculadora<TByte>::IntroducirComandos() {
TrimString S, strO, strP1, strP2;
TipoOperacion tOp = Ayuda;
bool Fin = false;
int Aux;
Operacion<TByte> *C;
char Buffer[80];
// Ciclo de lectura y ejecucin de comandos
//
do {
// Primero se muestra el indicador
//
cout << Indicador;
190
VOLVER A MEN
VOLVER A MEN
else
if (strO == V) tOp = BaseActual;
else
if (strO == +) tOp = Suma;
else
if (strO == -) tOp = Resta;
else
if (strO == *) tOp = Multiplicacion;
else
if (strO == /) tOp = Division;
else
if (strO == %) tOp = Modulo;
else
if (strO == &) tOp = Conjuncion;
else
if (strO == |) tOp = Disyuncion;
else
if (strO == !) tOp = Complemento;
else
if (strO == <) tOp = Izquierda;
else
if (strO == >) tOp = Derecha;
else {
// Debe ser un literal vlido
// Se asume una suma a 0
//
tOp = Suma;
strP1 = S;
strP2 = 0;
}
// Verificar si estn los operandos
//
192
VOLVER A MEN
VOLVER A MEN
}
else {
// Una operacin que requiere operandos y no hay operandos no puede ser
//
if (strP1 == && tOp >= Suma && tOp <= Derecha) tOp = Ayuda;
}
// Se instancia el objecto Comando / Operacin
//
C = new Operacion<TByte>(tOp);
// Se agregan los operandos; pueden ser T
//
if (strP1 != ) {
if (strP1 == T) strP1 = C->Convertir(T->ObtValor(), Base);
C->AsgOperando1(strP1, Base);
if (strP2 != ) {
if (strP2 == T) strP2 = C->Convertir(T->ObtValor(), Base);
C->AsgOperando2(strP2, Base);
}
}
// Se ejecuta el comando / operacin
//
switch (tOp) {
case Binario:
AsgBase(Base2);
break;
case Decimal:
AsgBase(Base10);
break;
case Hexa:
AsgBase(Base16);
194
VOLVER A MEN
break;
case MemoriaActual:
cout << C->Convertir(T->ObtValor(), ObtBase()) << \n;
break;
case BaseActual:
cout << ObtBase() << : ;
switch (ObtBase()) {
case Base2:
cout << { 0, 1 } << \n;
break;
case Base10:
cout << { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } << \n;
break;
case Base16:
cout << { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F } << \n;
break;
}
break;
case Suma:
case Resta:
case Multiplicacion:
case Division:
case Signo:
case Modulo:
case Conjuncion:
case Disyuncion:
case Exclusivo:
case Complemento:
case Izquierda:
case Derecha:
T->AsgValor(C->Ejecutar());
cout << C->Convertir(T->ObtValor(), ObtBase()) << \n;
break;
195
VOLVER A MEN
case Salir:
Fin = true;
break;
default:
cout << ?\tMuestra la lista de opciones\n;
cout << B\tCambia a modalidad de representacin base 2 o binaria\n;
cout << D\tCambia a modalidad de representacin base 10 o decimal\n;
cout << H\tCambia a modalidad de representacin base 16 o hexadecimal\n;
cout << S\tFinalizar la ejecucin del programa\n;
cout << T\tMuestra el valor actual de la memoria temporal\n;
cout << V\tMuestra el estado actual de la base de representacin\n;
break;
}
// Se libera el espacio ocupado por el comando
//
delete C;
} while (!Fin);
}
// Programa principal
//
int main(int argc, char** argv) {
Calculadora<char> Calc(Calcular> , 1);
Calc.IntroducirComandos();
return 0;
}
Ntese que en el ejercicio se utiliza la clase TrimString. A continuacin los archivos TrimString.
hpp y TrimString.cpp relativos a esa clase.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
196
VOLVER A MEN
197
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.2
* TrimString.cpp
* Mauricio Paletta
*/
#include TrimString.hpp
El mismo programa escrito en Java se puede ver a continuacin. Ntese las diferencias
entre lenguajes para resolver el mismo problema. El archivo fuente Calculadora.java que
define a la clase Calculadora est asociado al paquete que lleva el mismo nombre, es decir,
calculadora.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.2
* Calculadora.java
* Mauricio Paletta
*/
package calculadora;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Calculadora<TByte extends Number> {
// Tipos posibles de operaciones
//
public enum TipoOperacion {
Ayuda, Binario, Decimal, Hexa, Salir, MemoriaActual, BaseActual,
Suma, Resta, Multiplicacion, Division, Signo, Modulo,
198
VOLVER A MEN
199
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
Operando2 = (TByte)(Number)Long.parseLong(O);
break;
case Base16:
Operando2 = HexADec(O);
break;
}
}
@Override
public TByte Ejecutar() {
long Oper1 = 0, Oper2 = 0;
if (Operando1 != null) Oper1 = Operando1.longValue();
if (Operando2 != null) Oper2 = Operando2.longValue();
// Depende de la operacin y del nmero de bytes usados
//
switch (ObtOperacion()) {
case Suma:
return (TByte)(Number)(Oper1 + Oper2);
case Resta:
return (TByte)(Number)(Oper1 - Oper2);
case Multiplicacion:
return (TByte)(Number)(Oper1 * Oper2);
case Division:
return (TByte)(Number)(Oper1 / Oper2);
case Signo:
return (TByte)(Number)(-Oper1);
case Modulo:
return (TByte)(Number)(Oper1 % Oper2);
case Conjuncion:
return (TByte)(Number)(Oper1 & Oper2);
case Disyuncion:
202
VOLVER A MEN
VOLVER A MEN
break;
}
return S;
}
}
// Atributos de Calculadora
//
private Memoria<TByte> T;
private String Indicador;
private TipoBase Base;
private int NumBytes;
// Mtodos de la clase Calculadora
//
Calculadora(String I, int N) {
Indicador = I; NumBytes = N; Base = TipoBase.Base10;
T = new Memoria();
}
public<TByte extends Number> void AsgNumBytes() {
TByte Aux = (TByte)(Number)0;
if (Aux.getClass() == Byte.TYPE) NumBytes = 1;
else
if (Aux.getClass() == Short.TYPE) NumBytes = 2;
else
if (Aux.getClass() == Integer.TYPE) NumBytes = 4;
else
if (Aux.getClass() == Long.TYPE) NumBytes = 8;
T = new Memoria();
}
204
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
case Binario:
case Decimal:
case Hexa:
case MemoriaActual:
case BaseActual:
case Signo:
case Complemento:
case Salir:
tOp = TipoOperacion.Ayuda;
break;
}
}
else {
// Hay un slo operando; si la operacin requiere dos no puede ser
//
if (tOp == TipoOperacion.Resta) tOp = TipoOperacion.Signo;
if (tOp != TipoOperacion.Signo || tOp != TipoOperacion.Complemento)
tOp = TipoOperacion.Ayuda;
}
}
else {
// Hay un slo operando; si la operacin requiere dos no puede ser
//
if (tOp == TipoOperacion.Resta) tOp = TipoOperacion.Signo;
if (tOp != TipoOperacion.Signo && tOp != TipoOperacion.Complemento)
tOp = TipoOperacion.Ayuda;
}
}
else {
// Una operacin que requiere operandos y no hay operandos no puede ser
//
if (strP1.compareTo() == 0 &&
(tOp == TipoOperacion.Suma || tOp == TipoOperacion.Resta ||
208
VOLVER A MEN
VOLVER A MEN
AsgBase(TipoBase.Base16);
break;
case MemoriaActual:
System.out.println(C.Convertir(T.ObtValor(), ObtBase()));
break;
case BaseActual:
System.out.print(ObtBase());
System.out.print(: );
switch (ObtBase()) {
case Base2:
System.out.println({ 0, 1 });
break;
case Base10:
System.out.println({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
break;
case Base16:
System.out.println({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F });
break;
}
break;
case Suma:
case Resta:
case Multiplicacion:
case Division:
case Signo:
case Modulo:
case Conjuncion:
case Disyuncion:
case Exclusivo:
case Complemento:
case Izquierda:
case Derecha:
T.AsgValor(C.Ejecutar());
210
VOLVER A MEN
System.out.println(C.Convertir(T.ObtValor(), ObtBase()));
break;
case Salir:
Fin = true;
break;
default:
System.out.println(?\tMuestra la lista de opciones);
System.out.println(B\tCambia a modalidad de representacin base 2 o binaria);
System.out.println(D\tCambia a modalidad de representacin base 10 o decimal);
System.out.println(H\tCambia a modalidad de representacin base 16 o hexadecimal);
System.out.println(S\tFinalizar la ejecucin del programa);
System.out.println(T\tMuestra el valor actual de la memoria temporal);
System.out.println(V\tMuestra el estado actual de la base de representacin);
break;
}
} while (!Fin);
}
public static void main(String[] args) throws IOException {
Calculadora<Byte> Calc = new Calculadora<>(Calcular> , 1);
Calc.IntroducirComandos();
}
}
Finalmente, el mismo programa pero esta vez escrito en C# es como sigue a continuacin.
Ntese la similitud con Java aunque hay ciertas diferencias. Se tiene el archivo fuente
Calculadora.cs y el paquete se representa con el espacio de nombres ProyectoCalculadora.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C#; caso prctico Seccin 6.2
* Calculadora.cs
* Mauricio Paletta
*/
211
VOLVER A MEN
usingSystem;
usingSystem.IO;
namespaceProyectoCalculadora
{
publicclassCalculadora<TByte>
{
// Tipos posibles de operaciones
//
publicenumTipoOperacion{
Ayuda,Binario,Decimal,Hexa,Salir,MemoriaActual,BaseActual,
Suma,Resta,Multiplicacion,Division,Signo,Modulo,
Conjuncion,Disyuncion,Exclusivo,Complemento,Izquierda,Derecha
}
// Tipos posibles de base de representacin
//
publicenumTipoBase{
Base2,Base10,Base16
}
// Representa la memoria de la calculadora
//
publicclassMemoria{
privateTByte Valor;
publicTByteObtValor(){returnValor;}
publicvoidAsgValor(TByte V){Valor = V;}
}
// Representa un Comando
//
publicabstractclassComando{
protectedTipoOperacion Op;
privateTByteBinADec(String B){
intS =1;
if(B.Length ==8*NumBytes&&B[0]==1){
S =-1;
212
VOLVER A MEN
B = B.Substring(1);
}
return(TByte)Convert.ChangeType((S*System.Convert.ToInt64(B,2)),typeof(TByte));
}
privateStringDecABin(TByte D){
String S = System.Convert.ToString((long)Convert.ChangeType(D,typeof(long)),2);
if(S.Length>8*NumBytes)
S = S.Substring(S.Length-(8*NumBytes));
returnS;
}
privateTByteHexADec(String H){
longR = System.Convert.ToInt64(H,16);
intS =1,N =0;
charC;
if(H.Length ==2*NumBytes){
S =-1;
C = H[0];
if(C>=0&&C<=9)N = C-0;
if(C>=A&&C<=F)N = C-A+10;
if(C>=a&&C<=f)N = C-a+10;
if(N>=8){
R-=(N*(int)Math.Pow(16,2*NumBytes-1));
R+=((N-8)*(int)Math.Pow(16,2*NumBytes-1));
}
}
return(TByte)Convert.ChangeType(S*R,typeof(TByte));
}
privateStringDecAHex(TByte D){
String S = Convert.ToString((long)Convert.ChangeType(D,typeof(long)),16);
if(S.Length>2*NumBytes)
S = S.Substring(S.Length-(2*NumBytes));
returnS;
}
publicOperacion(TipoOperacion O):base(O){}
publicvoidAsgOperando1(TByte O){Operando1 = O;}
publicvoidAsgOperando1(String O,TipoBase B){
switch(B){
caseTipoBase.Base2:
Operando1 =BinADec(O);
break;
caseTipoBase.Base10:
Operando1 =(TByte)Convert.ChangeType(O,typeof(TByte));
break;
caseTipoBase.Base16:
Operando1 =HexADec(O);
break;
}
}
publicvoidAsgOperando2(TByte O){Operando2 = O;}
213
VOLVER A MEN
publicoverrideTByteEjecutar(){
longOper1 =0,Oper2 =0;
if(Operando1!=null)Oper1 =(long)Convert.ChangeType(Operando1,typeof(long));
if(Operando2!=null)Oper2 =(long)Convert.ChangeType(Operando2,typeof(long));
publicStringEjecutar(TipoBase B){
TByte R =Ejecutar();
returnConvertir(R,B);
}
publicStringConvertir(TByte N,TipoBase B){
String S =;
switch(B){
214
VOLVER A MEN
caseTipoBase.Base2:
S =DecABin(N);
if(S.Length>8*NumBytes)S = S.Substring(S.Length-(8*NumBytes));
break;
caseTipoBase.Base10:
S = System.Convert.ToString((long)Convert.ChangeType(N,typeof(long)));
break;
caseTipoBase.Base16:
S =DecAHex(N);
if(S.Length>2*NumBytes)S = S.Substring(S.Length-(2*NumBytes),S.
Length-1);
break;
}
returnS;
}
}
// Atributos de Calculadora
//
privateMemoria T;
privateString Indicador;
privateTipoBase Base;
staticprotectedintNumBytes;
// Mtodos de la clase Calculadora
//
publicCalculadora(String I,intN){
Indicador = I;NumBytes = N;Base = TipoBase.Base10;
T =newMemoria();
}
publicvoidAsgNumBytes(){
TByte Aux =default(TByte);
byteunByte =0;
shortunShort =0;
intunInt =0;
longunLong =0;
if(unByte.Equals(Aux.GetType()))NumBytes =1;
else
if(unShort.Equals(Aux.GetType()))NumBytes =2;
else
if(unInt.Equals(Aux.GetType()))NumBytes =4;
else
if(unLong.Equals(Aux.GetType()))NumBytes =8;
T =newMemoria();
}
publicvoidAsgIndicador(String I){if(I!=)Indicador = I;}
publicvoidAsgBase(TipoBase B){Base = B;}
publicTByteObtMemoria(){returnT.ObtValor();}
publicTipoBaseObtBase(){returnBase;}
publicvoidIntroducirComandos(){
String S,strO,strP1,strP2;
TipoOperacion tOp;
boolFin =false;
intAux;
Operacion C;
215
VOLVER A MEN
VOLVER A MEN
//
tOp = TipoOperacion.Suma;
strP1 = S;
strP2 =0;
}
// Verificar si estn los operandos
//
if(strP1 ==&&Aux>=0){
S = S.Substring(Aux+1);
S.Trim();
Aux = S.IndexOf( ,0);
if(Aux<0)
strP1 = S;
else
strP1 = S.Substring(0,Aux);
if(Aux>0){
S = S.Substring(Aux+1);
S.Trim();
if(S.Length>0){
strP2 = S;
// La operacin debe ser vlida para dos operandos
//
switch(tOp){
caseTipoOperacion.Binario:
caseTipoOperacion.Decimal:
caseTipoOperacion.Hexa:
caseTipoOperacion.MemoriaActual:
caseTipoOperacion.BaseActual:
caseTipoOperacion.Signo:
caseTipoOperacion.Complemento:
caseTipoOperacion.Salir:
tOp = TipoOperacion.Ayuda;
break;
}
}
else{
// Hay un slo operando; si la operacin requiere dos no puede ser
//
if(tOp == TipoOperacion.Resta)tOp = TipoOperacion.Signo;
if(tOp!= TipoOperacion.Signo||tOp!= TipoOperacion.Complemento)
tOp = TipoOperacion.Ayuda;
}
}
else{
// Hay un slo operando; si la operacin requiere dos no puede ser
//
if(tOp == TipoOperacion.Resta)tOp = TipoOperacion.Signo;
if(tOp!= TipoOperacion.Signo&&tOp!= TipoOperacion.Complemento)
tOp = TipoOperacion.Ayuda;
}
}
else{
// Una operacin que requiere operandos y no hay operandos no puede ser
//
217
VOLVER A MEN
if(strP1 ==&&
(tOp == TipoOperacion.Suma||tOp == TipoOperacion.Resta||
tOp == TipoOperacion.Multiplicacion|| tOp == TipoOperacion.Division||
tOp == TipoOperacion.Signo||tOp == TipoOperacion.Modulo||
tOp == TipoOperacion.Conjuncion||tOp == TipoOperacion.Disyuncion||
tOp == TipoOperacion.Exclusivo|| tOp == TipoOperacion.Complemento||
tOp == TipoOperacion.Izquierda||tOp == TipoOperacion.Derecha))
tOp = TipoOperacion.Ayuda;
}
VOLVER A MEN
break;
caseTipoOperacion.Suma:
caseTipoOperacion.Resta:
caseTipoOperacion.Multiplicacion:
caseTipoOperacion.Division:
caseTipoOperacion.Signo:
caseTipoOperacion.Modulo:
caseTipoOperacion.Conjuncion:
caseTipoOperacion.Disyuncion:
caseTipoOperacion.Exclusivo:
caseTipoOperacion.Complemento:
caseTipoOperacion.Izquierda:
caseTipoOperacion.Derecha:
T.AsgValor(C.Ejecutar());
Console.WriteLine(C.Convertir(T.ObtValor(),ObtBase()));
break;
caseTipoOperacion.Salir:
Fin =true;
break;
default:
Console.WriteLine(?\tMuestra la lista de opciones);
Console.WriteLine(B\tCambia a modalidad de representacin base 2 o binaria);
Console.WriteLine(D\tCambia a modalidad de representacin base 10 o decimal);
Console.WriteLine(H\tCambia a modalidad de representacin base 16 o
hexadecimal);
Console.WriteLine(S\tFinalizar la ejecucin del programa);
Console.WriteLine(T\tMuestra el valor actual de la memoria temporal);
Console.WriteLine(V\tMuestra el estado actual de la base de representacin);
break;
}
}while(!Fin);
}
}
classProgram
{
publicstaticvoidMain(string[]args)
{
Calculadora<byte>Calc =newCalculadora<byte>(Calcular> ,1);
Calc.IntroducirComandos();
}
}
}
VOLVER A MEN
InicializarAC( )
// Estado inicial del AC en t = 0
t 31
Repetir hasta (criterio terminacin)
Para todos los autmatas si del AC
v = ObtenerVecindad(si)
NuevoEdo = AplicarTransicin(v, si)
ActualizarAC( )
// El AC pasa de t a t+1 con los nuevos estados
t 4 t + 1
// Una nueva iteracin de tiempo
Estado Final del AC
Para el caso especfico de este problema y la simulacin del modelo de trfico, el reticulado
es de dimensin 1 y el alfabeto de los posibles valores discretos de cada autmata es binario,
donde el 0 representa la va sin vehculo y el 1 representa un vehculo circulando en la direccin
derecha a izquierda (se puede tambin abordar el problema en la otra direccin). Las reglas
de transicin del autmata celular entre un estado en tiempo t y el nuevo estado en tiempo
t+1 para este problema, toman en cuenta un vecino a la izquierda y un vecino a la derecha del
autmata al cual se le desea obtener su nuevo estado. Las reglas son como sigue:
Avance: * 0 1 1
01*0
Estable: * 0 0 0
220
11*1
VOLVER A MEN
El estado inicial del autmata celular se debe obtener de forma aleatoria basado en un porcentaje
de trfico o nmero de vehculos representados en ese estado inicial, donde 0% indica que la
va est completamente libre (todos los autmatas tienen el valor 0) y 100% indica que hay un
trfico pesado en la cual todas las celdas estn ocupadas por un vehculo (todos los autmatas
tienen el valor 1). Adems del nmero de autmatas que se desea tenga la simulacin, en
base a un mnimo y un mximo previamente establecidos, el porcentaje de trfico debe ser
tambin dado antes de iniciar la simulacin. La simulacin debe terminar (condicin de parada
de la dinmica del autmata celular) cuando se llega a un punto fijo, es decir, los estados
del autmata en tiempo t y t+1 son exactamente iguales (ntese que este mismo estado se
mantendr fijo a lo largo de tiempos sucesivos).
221
VOLVER A MEN
Se desea adems que cuente el nmero de vehculos que se representaron en el estado inicial
del autmata y el nmero de vehculos que, siguiendo su recorrido de derecha a izquierda,
salen por el extremo izquierdo del autmata celular. Al final de la simulacin se debe mostrar
un balance sobre la cantidad de vehculos que estaban inicialmente menos la cantidad de
vehculos que salieron. Si la simulacin y el conteo se hicieron correctamente entonces este
balance debe dar cero.
6.3.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): Luego de hacer una revisin del
texto del enunciado se tiene un mapa mental equivalente al que se muestra en la Figura 6.9.
222
VOLVER A MEN
6.3.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): Se trata de un problema cuya implementacin
requiere de un programa sin interaccin con ningn otro elemento de software. Se puede
hacer una implementacin tanto en interfaz modo texto como modo grfico. En el caso de una
interfaz modo texto se puede buscar una representacin para el vehculo y otra para la va libre
como por ejemplo <- y __ respectivamente. La interfaz grfica se puede realizar con un par
de imgenes como las que se muestran en la Figura 6.8.
223
VOLVER A MEN
Paso 2 (Detallar las clases): Al agregar los atributos y mtodos a las clases de la Figura 6.11
resulta el diagrama de clases detallado de la Figura 6.12. Ntese el tipo de dato de los atributos
(a la derecha, despus de :); el tipo de dato de retorno de los mtodos expresados como un
estereotipo (encerrados entre << y >>); el uso de parmetros en los mtodos (encerrados
entre ( y )), si aplica.
Paso 3 (Desarrollar los modelos de estado): Ntese que la clase Simulador Trfico no posee
ningn atributo por lo tanto no es susceptible de sufrir cambios de estado y, en consecuencia,
no tiene un diagrama de cambios de estado asociado. La Figura 6.13 muestra los diagramas
de estado de las otras dos clases presentes en el modelo.
Paso 4 (Elaborar los modelos de colaboracin): Los casos de uso Inicializar y Configurar
que aparecen en el diagrama de la Figura 6.10 se realizan en un mismo proceso (mtodo). En
este sentido, la Figura 6.14 muestra el diagrama de secuencias que permite probar la manera
en la cual el modelo conceptual satisface estos requerimientos. La lectura es como sigue: el
Usuario ejecuta el mensaje Iniciar() utilizando una instancia cualquiera de Simulador; lo
siguiente es Inicializar() el Autmata Celular el cual provoca una serie de llamadas del
mensaje AsgEstado(Edo) del arreglo de objetos CeldasAct de la clase Autmata; se sigue
224
VOLVER A MEN
con Mostrar() el Autmata Celular el cual requiere Mostrar() los Autmata de CeldasAct.
Se contina con la Transicion() del Autmata Celular cuya ejecucin requiere una serie de
llamadas al mensaje AsgEstado(Edo) de los objetos del arreglo CeldasAnt y luego de los
objetos del arreglo CeldasAct. Cada transicin se muestra al usuario (representado en el
diagrama con el paso 9).
Paso 5 (Identificar componentes del dominio): Asumiendo el uso de Java para la implementacin
de este caso prctico, el diagrama de componentes correspondiente al problema se presenta
en la Figura 6.15. Se tienen dos paquetes Automata y SimulacionTrafico, cada uno de
los cuales con un archivo cdigo fuente de java AutomataCelular.java y Simulador.java
respectivamente.
6.3.4 Programacin
La implementacin de este problema haciendo uso de C++ es como sigue. Se realizaron
dos archivos de cdigo fuente, AutomataCelular.cpp y SimulacionTrafico.cpp con sus
respectivos archivos encabezados correspondientes. A continuacin el contenido del archivo
225
VOLVER A MEN
AutomataCelular .hpp.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.3
* AutomataCelular.hpp
* Mauricio Paletta
*/
#ifndef AUTOMATACELULAR_HPP
#define AUTOMATACELULAR_HPP
// Representa un autmata alfabeta binario
//
class Automata {
private:
bool Estado;
public:
Automata() { Estado = false; }
bool ObtEstado() { return Estado; }
void AsgEstado(bool Edo) { Estado = Edo; }
void Mostrar();
};
// Representa un autmata celular
//
class AutomataCelular {
private:
Automata *CeldasAct, *CeldasAnt;
int NumAutomatas;
bool PuntoFijo;
226
VOLVER A MEN
public:
AutomataCelular(int N);
~AutomataCelular();
void Inicializar();
void Inicializar(double P);
bool HayPuntoFijo() { return PuntoFijo; }
void Mostrar();
bool Transicion();
};
#endif /* AUTOMATACELULAR_HPP */
VOLVER A MEN
AutomataCelular::AutomataCelular(int N) {
if (N <= 0) N = 1;
CeldasAct = new Automata[N];
CeldasAnt = new Automata[N];
NumAutomatas = N;
PuntoFijo = false;
}
AutomataCelular::~AutomataCelular() {
if (CeldasAct) delete[] CeldasAct;
if (CeldasAnt) delete[] CeldasAnt;
}
void AutomataCelular::Inicializar() {
// Inicializacin aleatoria distribuida uniformemente
//
Inicializar(50.0);
}
void AutomataCelular::Inicializar(double P) {
// Inicializacin aleatoria segn una distribucin basada en la
// probabilidad P de estados activados
//
Random R(time(NULL));
for (int c=0; c < NumAutomatas; c++) {
CeldasAct[c].AsgEstado(R.uniform() * 100.0 <= P);
}
PuntoFijo = false;
}
// Se muestra el autmata celular en base a cada autmata
//
228
VOLVER A MEN
void AutomataCelular::Mostrar() {
for (int c=0; c < NumAutomatas; c++) {
CeldasAct[c].Mostrar();
}
std::cout << std::endl;
}
bool AutomataCelular::Transicion() {
bool Ret = false, Val;
bool VecIzq, VecDer;
int Cambios = 0;
for (int c=0; c < NumAutomatas; c++) {
Val = CeldasAct[c].ObtEstado();
if (!c && Val) Ret = true;
VecIzq = (c > 0 ? CeldasAct[c-1].ObtEstado() : false);
VecDer = (c < NumAutomatas - 1 ? CeldasAct[c+1].ObtEstado() : false);
// Reglas de transicin; dependen del problema
//
if (!Val && VecDer)
Val = true;
else
if (!VecIzq && Val)
Val = false;
CeldasAnt[c].AsgEstado(Val);
}
// Se actualiza el estado del autmata celular en base a las transiciones
// Hay que simular la transicin sincrnica de cada uno de los autmatas
//
for (int c=0; c < NumAutomatas; c++) {
if (CeldasAct[c].ObtEstado() != CeldasAnt[c].ObtEstado()) {
229
VOLVER A MEN
CeldasAct[c].AsgEstado(CeldasAnt[c].ObtEstado());
Cambios++;
}
}
// Al menos un cambio determina que no hay punto fijo
//
PuntoFijo = Cambios == 0;
return Ret;
}
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.3
* SimulacionTrafico.cpp
* Mauricio Paletta
*/
#include <cstdlib>
#include <iostream>
#include SimulacionTrafico.hpp
#include AutomataCelular.hpp
using namespace std;
// Mtodos de la clase Simulador
//
Simulador::Simulador(int Min, int Max) {
MinCeldas = Min >= 0 ? Min : 0;
MaxCeldas = Max > Min ? Max : Max + 1;
}
void Simulador::Iniciar() {
AutomataCelular *AC;
int N, NumVehiculos, t = 0;
double P;
char O;
cout << Modelado y programacin Orientado a Objetos: Un enfoque prctico.\n;
cout << Simulador de trfico un canal de circulacin, un sentido.\n << endl;
do {
cout << Nmero de autmatas ( << MinCeldas << y << MaxCeldas << ): ;
cin >> N;
} while (N < MinCeldas || N > MaxCeldas);
231
VOLVER A MEN
do {
cout << Indique porcentaje de trfico (entre 0 y 100): ;
cin >> P;
} while (P < 0.0 || P > 100.0);
// Se prepara el autmata celular para la simulacin
//
AC = new AutomataCelular(N);
do {
// Inicializar el autmata celular
//
AC->Inicializar(P);
NumVehiculos = 0;
// Mostrar el estado actual y hacer la transicin mientras no haya un punto fijo
//
while (!AC->HayPuntoFijo()) {
cout << t = << t++ << endl;
AC->Mostrar();
if (AC->Transicion())
NumVehiculos++;
cout << endl;
}
// Si se quiere correr de nuevo la simulacin
//
cout << endl << Se ha llegado a un punto fijo.\n ;
cout << Nmero de vehculos que salieron: << NumVehiculos << .\n ;
cout << endl << Desea ejecutar nuevamente (S/N)? ;
cin >> O;
} while (O == S || O == s);
232
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
CeldasAnt[c].AsgEstado(Val);
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.3
* Simulador.java
* Mauricio Paletta
*/
package SimulacionTrafico;
import Automata.AutomataCelular;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Simulador {
private int MinCeldas, MaxCeldas;
public Simulador(int Min, int Max) {
MinCeldas = Min >= 0 ? Min : 0;
MaxCeldas = Max > Min ? Max : Max + 1;
}
public void Iniciar() throws IOException {
AutomataCelular AC;
int N, NumVehiculos, t = 0;
double P;
char O;
InputStreamReader Entrada = new InputStreamReader(System.in);
BufferedReader Buffer = new BufferedReader(Entrada);
String Lectura;
235
VOLVER A MEN
} while (O == S || O == s);
}
236
S.Iniciar();
} catch (IOException ex) {
Logger.getLogger(Simulador.class.getName()).log(Level.SEVERE, null, ex);
}
VOLVER A MEN
VOLVER A MEN
//
Random R = new Random();
CeldasAnt[c].AsgEstado(Val);
}
238
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C#; caso prctico Seccin 6.3
* Simulador.cs
* Mauricio Paletta
*/
using System;
using Automata;
namespace SimulacionTrafico
{
public class Simulador
{
private int MinCeldas, MaxCeldas;
public Simulador(int Min, int Max)
{
MinCeldas = Min >= 0 ? Min : 0;
MaxCeldas = Max > Min ? Max : Max + 1;
}
public void Iniciar()
{
AutomataCelular AC;
int N, NumVehiculos, t = 0;
double P;
char O;
string Lectura;
239
VOLVER A MEN
S.Iniciar();
VOLVER A MEN
Indicar si un elemento pertenece o no a un conjunto. Para ello se debe dar el nmero entero positivo a buscar y el identificador del conjunto donde se desea hacer la bsqueda.
Realizar las operaciones de Unin, Interseccin y Diferencia de dos conjuntos existentes
del ambiente, guardando el resultado en un tercer conjunto existente en el ambiente.
Se debe indicar el identificador de los tres conjuntos involucrados en la operacin. En el
conjunto que recibe el resultado se perder cualquier informacin previa que ste pueda
contener.
Determinar si un conjunto est o no vaco.
Mostrar la informacin o contenido de un conjunto del ambiente luego de dar su identificador.
Los elementos deben aparecer en orden usando su valor como clave de ordenamiento.
Mostrar la informacin que se encuentra actualmente en el ambiente, indicando todos
sus conjuntos y los contenidos de stos. La lista de conjuntos se debe mostrar de forma
ordenada usando el identificador de los conjuntos como clave de ordenamiento. Los
elementos de cada conjunto deben aparecer de forma ordenada usando su valor como
clave de ordenamiento.
Guardar el estado o informacin actual del ambiente en un archivo cuyo nombre debe ser
dado. Si el archivo ya existe se deber advertir al usuario si desea o no sustituirlo. Luego
de la operacin el ambiente seguir trabajando normalmente.
Recuperar de un archivo la informacin que debe ser usada en la operacin actual del
ambiente. Cualquier informacin actualmente existente en el ambiente se perder y ser
reemplazada por lo que contenga el archivo.
Ejecutar archivo de comandos. En esta opcin el programa deber, a partir de un archivo
texto, leer e interpretar una serie de comandos de los descritos anteriormente segn la
sintaxis que se presenta en la Tabla 6.3 de manera tal de realizar de forma automtica
estas acciones. Como parte de la sintaxis, los corchetes angulados < y > indican que
en ese lugar debe ir algo vlido segn lo descrito que est encerrado entre ellos. Si por
alguna razn no se puede ejecutar alguno de los comandos, se pasa al siguiente hasta
completar el contenido del archivo.
Finalizar la ejecucin actual del ambiente.
241
VOLVER A MEN
Descripcin
N <C>
C <C>
A <N> <C>
D <N> <C>
S <A>
L <A>
Adicionalmente, se debe guardar un archivo texto de eventos Logger que registre en detalle
(operacin ms parmetros) todas las acciones que el usuario del programa ha realizado desde
el inicio hasta el cierre de una cesin de trabajo. Cada evento ocupar una lnea diferente del
archivo y debe de ir acompaado de la fecha y hora de ocurrencia. El nombre de este archivo
puede ser fijo (Logger.Txt por ejemplo). El formato de cada lnea puede ser como sigue:
<Fecha Actual> <Hora Actual>: <Texto descriptivo del evento>
6.4.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): La Figura 6.16 presenta el mapa
mental que resulta luego de hacer una revisin del texto del enunciado del problema.
Paso 2 (Identificar actores / nombres): Se tiene la siguiente lista de nombres: Conjunto, nmero,
ambiente, letra, identificador, unin, interseccin, diferencia, resultado, informacin, contenido,
clave, archivo, comando, evento, logger y formato.
Paso 3 (Identificar procesos / requerimientos): Al igual que ocurre con los dos problemas
anteriores, hay un usuario como actor del ambiente para el manejo de conjuntos de nmeros
242
VOLVER A MEN
enteros. Adicionalmente y tal como lo indica el enunciado del problema, los comandos pueden
venir tanto del usuario como de un archivo. Por otro lado, se tiene tambin la generacin del
archivo de datos para guardar la informacin actual del entorno y la posterior recuperacin de
la informacin de estos archivos de datos. Finalmente, se tiene la generacin del archivo de
eventos. Al igual que el usuario, todos estos archivos deben ser representados como actores
externos del ambiente.
Figura 6.17. Diagrama de casos de uso relativo al problema del ambiente para el manejo de conjuntos.
La Figura 6.17 muestra un diagrama de casos de uso apropiado para representar lo que se
desea resolver en este problema. Ntese la presencia de los 4 actores antes mencionados:
usuario, archivo de comandos, archivo de data y archivo de eventos. Tambin ntese el sentido
correcto de flujo de actuacin entre estos actores y los casos de uso correspondientes. La
interaccin con el ambiente se centraliza en un nico caso de uso para Introducir comando y
Mostrar resultado. Cada uno de los comandos expecficos extiende el caso de uso general.
Paso 4 (Identificar clases y asociaciones): De la lista de nombres identificada en el Paso 2 se
tienen los siguientes observables:
Nmero, conjunto, evento, comando y archivo son implementaciones.
Letra e identificador son redundantes y adems atributo de conjunto.
Unin, interseccin y diferencia son operaciones.
Informacin, contenido y formato son conceptos vagos.
Resultado y clave son irrelevantes.
Conjunto de enteros es un caso articular de conjunto.
243
VOLVER A MEN
Figura 6.18. Diagrama no detallado de clases relativo al problema del ambiente para el manejo de conjuntos.
6.4.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): Se trata de un problema cuya implementacin
requiere de un programa que posee interaccin con tres tipos de archivos diferentes: 1) un
archivo de comandos que es modo texto; 2) un archivo de data que puede ser tanto texto como
binario pero preferiblemente binario y 3) un archivo de eventos que es modo texto. Tanto para
el archivo de comandos como para el archivo de eventos se tiene un formato especfico para
leer / escribir la informacin que contienen.
Por otro lado, no se dan detalles especficos de cmo manejar la interfaz. Lo mejor en este
caso es tener una interfaz modo texto con interpretacin de comandos segn lo planteado en
el enunciado del problema que se describe en la Seccin 6.4.1.
Paso 2 (Detallar las clases): Al agregar los atributos y mtodos a las clases de la Figura 6.18
resulta el diagrama de clases detallado de la Figura 6.19. Ntese el tipo de dato de los atributos
(a la derecha, despus de :); el tipo de dato de retorno de los mtodos expresados como un
estereotipo (encerrados entre << y >>); el uso de parmetros en los mtodos (encerrados
entre ( y )), si aplica.
244
VOLVER A MEN
Figura 6.19. Diagrama detallado de clases relativo al problema del ambiente para el manejo de conjuntos.
Paso 3 (Desarrollar los modelos de estado): Ntese que la clase Archivo Eventos no posee
ningn atributo, los cambios de estados relativos a esta clase estn asociados a la clase base
Archivo y, por ser sta una implementacin, Archivo Eventos no es susceptible de sufrir
cambios de estado. En consecuencia esta clase no tiene un diagrama de cambios de estado
asociado. Algo parecido ocurre con Conjunto Enteros en la cual su nico atributo recibe un
valor inicial en tiempo de construccin del objeto. El resto de los estados estn asociados a
la clase base Conjunto. En este sentido, la Figura 6.20 muestra los diagramas de estado
presentes en el modelo de este problema.
Figura 6.20. Diagramas de estado relativos al problema del ambiente para el manejo de conjuntos.
VOLVER A MEN
Figura 6.21. Diagrama de colaboracin relativo al problema del ambiente para el manejo de conjuntos.
Figura 6.22. Diagrama de componentes relativo al problema del ambiente para el manejo de conjuntos.
246
VOLVER A MEN
6.4.4 Programacin
A continuacin el cdigo escrito en C++ relativo al problema. Se tienen los archivos
fuente ManejoConjuntos.hpp y el correspondiente ManejoConjuntos.cpp,
ArchivoEventos.hpp y el correspondiente ArchivoEventos.cpp y el programa
principal en main.cpp. Ntese que la implementacin hace uso de plantillas para la
generalizacin del tipo de dato de los elementos del conjunto.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.4
* ManejoConjuntos.hpp
* Mauricio Paletta
*/
#ifndef MANEJOCONJUNTOS_HPP
#define MANEJOCONJUNTOS_HPP
#include <set>
#include <string>
#include ArchivoEventos.hpp
#include TrimString.hpp
using namespace std;
// Representa un conjunto de enteros
//
class ConjuntoEnteros : public set<int> {
private:
char Identificador;
public:
ConjuntoEnteros() : set<int>() {
247
VOLVER A MEN
Identificador = *;
};
ConjuntoEnteros(char Id) : set<int>() {
if (Id < A || Id > Z) Id = *;
Identificador = Id;
};
char ObtId() const { return Identificador; }
operator char() { return ObtId(); }
bool Pertenece(int E) { return this->find(E) != this->end(); }
bool Agregar(int E);
ConjuntoEnteros operator <<(int E) {
Agregar(E); return *this;
}
bool Suprimir(int E) {
if (!Pertenece(E)) return false;
this->erase(E);
return true;
}
ConjuntoEnteros operator >>(int E) {
Suprimir(E); return *this;
}
void MostrarOrdenado();
void GuardarArchivo(ofstream *MiArchivo);
};
// Representa el manejador de conjunto de enteros
//
struct CompConjuntoEnteros {
bool operator() (const ConjuntoEnteros& C1, const ConjuntoEnteros& C2) const {
return C1.ObtId() < C2.ObtId();
}
};
248
VOLVER A MEN
class ManejadorConjuntos {
private:
set<ConjuntoEnteros, CompConjuntoEnteros> Conjuntos;
ArchivoEventos *Logger;
public:
ManejadorConjuntos() {
Logger = new ArchivoEventos();
Logger->EscribirEvento(Inicio de sesin);
}
~ManejadorConjuntos() {
Logger->EscribirEvento(Fin de sesin);
delete Logger;
}
bool operator() (ConjuntoEnteros C1, ConjuntoEnteros C2) const {
return C1.ObtId() < C2.ObtId();
}
ConjuntoEnteros *BuscarConjunto(char Id);
bool AgregarConjunto(char Id);
ManejadorConjuntos operator <<(char Id) {
AgregarConjunto(Id); return *this;
}
bool SuprimirConjunto(char Id);
ManejadorConjuntos operator >>(char Id) {
SuprimirConjunto(Id); return *this;
}
bool AgregarElemento(int E, char Id);
bool SuprimirElemento(int E, char Id);
bool PerteneceElemento(int E, char Id);
bool HacerUnion(char Id1, char Id2, char Id3);
bool HacerInterseccion(char Id1, char Id2, char Id3);
bool HacerDiferencia(char Id1, char Id2, char Id3);
bool EstaVacio(char Id);
249
VOLVER A MEN
void MostrarOrdenado();
bool Guardar(string Nombre);
bool Cargar(string Nombre);
bool EjecutarComando(TrimString Comando);
bool EjecutarComandos(string Nombre);
};
#endif /* MANEJOCONJUNTOS_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.4
* ManejoConjuntos.cpp
* Mauricio Paletta
*/
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
#include ManejoConjuntos.hpp
// Mtodos de la clase ConjuntoEnteros
//
bool ConjuntoEnteros::Agregar(int E) {
set<int>::iterator It = this->find(E);
if (It != this->end()) return false;
this->insert(E);
return true;
}
void ConjuntoEnteros::MostrarOrdenado() {
250
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
return C->Agregar(E);
}
bool ManejadorConjuntos::SuprimirElemento(int E, char Id) {
// Primero se busca el conjunto
//
ConjuntoEnteros *C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == NULL) return false;
return C->Suprimir(E);
}
bool ManejadorConjuntos::PerteneceElemento(int E, char Id) {
// Primero se busca el conjunto
//
ConjuntoEnteros *C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == NULL) return false;
return C->Pertenece(E);
}
bool ManejadorConjuntos::HacerUnion(char Id1, char Id2, char Id3) {
set<int>::iterator It;
ConjuntoEnteros *C1 = BuscarConjunto(Id1), *C2 = BuscarConjunto(Id2), *C3 =
BuscarConjunto(Id3);
// Primero se verifica la existencia de los 3 conjuntos
//
if (C1 == NULL || C2 == NULL || C3 == NULL) return false;
253
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
}
}
bool ManejadorConjuntos::Guardar(string Nombre) {
ofstream MiArchivo(Nombre.c_str(), ios::out | ios::binary);
int S = Conjuntos.size();
if (!MiArchivo.is_open()) return false;
// Primero se guarda el nmero de conjuntos
//
MiArchivo.write((char *)&S, sizeof(int));
for (set<ConjuntoEnteros>::iterator It = Conjuntos.begin(); It != Conjuntos.end(); It++) {
ConjuntoEnteros *C = (ConjuntoEnteros *)(&(*It));
if (C) C->GuardarArchivo(&MiArchivo);
}
MiArchivo.close();
return true;
}
bool ManejadorConjuntos::Cargar(string Nombre) {
ifstream MiArchivo(Nombre.c_str(), ios::in | ios::binary);
char IdCjto;
int S, N, *V;
// Cualquier cosa previa se suprime
//
Conjuntos.clear();
if (!MiArchivo.is_open()) return false;
// Se lee el nmero de conjuntos
//
256
VOLVER A MEN
VOLVER A MEN
bool bAux;
TrimString Op, Arg, sAux;
char C[3];
// Se elimina cuaquier espacio antes y despus del comando
//
Comando.trim();
Logger->EscribirEvento(Comando + Comando);
Aux = Comando.find( , 0);
if (Aux < 0) return false;
Op = Comando.substr(0, Aux);
if (Op.size() > 1) return false;
// Las acciones dependen de la operacin
//
if (Op == N || Op == C || Op == M || Op == V) {
// Debe haber un argumento de tres caracteres
//
Arg = Comando.substr(Aux + 1, Comando.length() - (Aux + 1));
Arg.trim();
if (Arg.length() != 3 || Arg[0] != < || Arg[2] != >) return false;
if (Op == N) return AgregarConjunto(Arg[1]);
if (Op == C) return SuprimirConjunto(Arg[1]);
if (Op == M) { MostrarOrdenado(); return true; }
return EstaVacio(Arg[1]);
}
if (Op == A || Op == D || Op == P) {
// Deben haber dos argumentos
//
Arg = Comando.substr(Aux + 1, Comando.length() - (Aux + 1));
Arg.trim();
Aux = Arg.find( , 0);
if (Aux < 0) return false;
258
VOLVER A MEN
VOLVER A MEN
if (Op == S || Op == L) {
// Debe haber un argumento
//
bAux = (Op == S);
Arg = Comando.substr(Aux + 1, Comando.length() - (Aux + 1));
Arg.trim();
if (Arg.length() < 3 || Arg[0] != < || Arg[Arg.length()-1] != >) return false;
return (bAux ? Guardar(Arg.substr(1, Arg.length()-2)) : Cargar(Arg.substr(1, Arg.length()-2)));
}
return false;
}
bool ManejadorConjuntos::EjecutarComandos(string Nombre) {
ifstream MiArchivo(Nombre.c_str(), ios::in);
char Buffer[80];
if (!MiArchivo.is_open()) return false;
Logger->EscribirEvento(Archivo de Comandos + Nombre);
while (!MiArchivo.eof()) {
MiArchivo.getline(Buffer, 80);
EjecutarComando(Buffer);
}
return true;
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.4
* ArchivoEventos.hpp
* Mauricio Paletta
*/
260
VOLVER A MEN
#ifndef ARCHIVOEVENTOS_HPP
#define ARCHIVOEVENTOS_HPP
#include <string>
#include <fstream>
using namespace std;
class ArchivoEventos : public ofstream {
public:
ArchivoEventos(string Nombre) : ofstream(Nombre.c_str()) { };
ArchivoEventos() : ofstream() { open(Logger.Txt); };
~ArchivoEventos() { close(); }
void EscribirEvento(string Ev);
};
#endif /* ARCHIVOEVENTOS_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.4
* ArchivoEventos.cpp
* Mauricio Paletta
*/
#include <ctime>
#include ArchivoEventos.hpp
void ArchivoEventos::EscribirEvento(string Ev) {
time_t tSac = time(NULL);
struct tm* pt = localtime(&tSac);
261
VOLVER A MEN
*this << < << pt->tm_mday << / << pt->tm_mon+1 << / << pt->tm_year+1900 << > ;
*this << < << pt->tm_hour << : << pt->tm_min << : << pt->tm_sec << >: ;
*this << Ev.c_str() << endl;
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.4
* Main.cpp
* Mauricio Paletta
*/
#include <cstdlib>
#include <iostream>
#include ManejoConjuntos.hpp
using namespace std;
// Programa principal
//
int main(int argc, char** argv) {
bool Fin = false;
char Buffer[80];
TrimString S, strO;
int Aux;
ManejadorConjuntos *Manejador = new ManejadorConjuntos();
do {
// Primero se muestra el indicador
//
cout << Conjuntos> ;
262
VOLVER A MEN
en el ambiente\n;
cout << + <C1> <C2> <C3>\tCalcular y guardar en <C3> la unin de <C1> con <C2>\n;
cout << * <C1> <C2> <C3>\tCalcular y guardar en <C3> la interseccin de <C1> con <C2>\n;
cout << - <C1> <C2> <C3>\tCalcular y guardar en <C3> la diferencia entre <C1> y <C2>\n;
cout << M <C>\t\t\tMostrar la informacin ordenada del conjunto de identificador <C>\n;
263
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
MiArchivo.write(E[i]);
}
}
}
class SetComparator implements Comparator<ConjuntoEnteros> {
@Override
public int compare(ConjuntoEnteros C1, ConjuntoEnteros C2) {
if (C1.ObtId() > C2.ObtId()) return 1;
if (C1.ObtId() < C2.ObtId()) return -1;
return 0;
}
}
private TreeSet<ConjuntoEnteros> Conjuntos;
private ArchivoEventos Logger;
public ManejadorConjuntos() {
try {
Conjuntos = new TreeSet(new SetComparator());
Logger = new ArchivoEventos();
Logger.EscribirEvento(Inicio de sesin);
} catch (FileNotFoundException ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
null, ex);
267
VOLVER A MEN
@Override
public void finalize() {
try {
Logger.EscribirEvento(Fin de sesin);
Logger.finalize();
} catch (IOException ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
null, ex);
} catch (Throwable ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
null, ex);
}
}
public ConjuntoEnteros BuscarConjunto(char Id) {
for (Iterator<ConjuntoEnteros> sIt = Conjuntos.iterator(); sIt.hasNext(); ) {
ConjuntoEnteros C = sIt.next();
if (C.ObtId() == Id) return C;
}
return null;
}
public boolean AgregarConjunto(char Id) {
// Se verifica que el Id es vlido
//
if (Id < A || Id > Z) return false;
// Se verifica que no hay ningn otro conjunto con el mismo Id
//
ConjuntoEnteros C = BuscarConjunto(Id);
if (C != null) return false;
Conjuntos.add(new ConjuntoEnteros(Id));
268
VOLVER A MEN
return true;
}
public boolean SuprimirConjunto(char Id) {
// Se busca el conjunto
//
ConjuntoEnteros C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == null) return false;
Conjuntos.remove(C);
return true;
}
public boolean AgregarElemento(int E, char Id) {
// Primero se busca el conjunto
//
ConjuntoEnteros C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == null) return false;
return C.Agregar(E);
}
public boolean SuprimirElemento(int E, char Id) {
// Primero se busca el conjunto
//
ConjuntoEnteros C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == null) return false;
269
VOLVER A MEN
return C.Suprimir(E);
}
public boolean PerteneceElemento(int E, char Id) {
// Primero se busca el conjunto
//
ConjuntoEnteros C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == null) return false;
return C.Pertenece(E);
}
public boolean HacerUnion(char Id1, char Id2, char Id3) {
ConjuntoEnteros C1 = BuscarConjunto(Id1), C2 = BuscarConjunto(Id2), C3 =
BuscarConjunto(Id3);
// Primero se verifica la existencia de los 3 conjuntos
//
if (C1 == null || C2 == null || C3 == null) return false;
// Se procede a hacer la unin de C1 con C2 y guardar el resultado en C3
// Se elimina cualquier cosa previa que exista en C3
//
C3.clear();
C3.addAll(C1);
C3.addAll(C2);
return true;
}
public boolean HacerInterseccion(char Id1, char Id2, char Id3) {
ConjuntoEnteros C1 = BuscarConjunto(Id1), C2 = BuscarConjunto(Id2), C3 =
BuscarConjunto(Id3);
270
VOLVER A MEN
271
VOLVER A MEN
272
VOLVER A MEN
try {
MiArchivo = new FileOutputStream(Nombre);
// Primero se guarda el nmero de conjuntos en el entorno
//
MiArchivo.write(Conjuntos.size());
for (Iterator<ConjuntoEnteros> It = Conjuntos.iterator(); It.hasNext(); ) {
ConjuntoEnteros C = It.next();
if (C != null) C.GuardarArchivo(MiArchivo);
}
MiArchivo.close();
} catch (FileNotFoundException ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
null, ex);
return false;
} catch (IOException ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
null, ex);
return false;
}
return true;
}
public boolean Cargar(String Nombre) {
FileInputStream MiArchivo;
char IdCjto;
int C, N, V;
try {
MiArchivo = new FileInputStream(Nombre);
// Cualquier cosa previa se suprime
//
Conjuntos.clear();
273
VOLVER A MEN
null, ex);
return false;
} catch (IOException ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
274
null, ex);
VOLVER A MEN
return false;
}
return true;
}
public boolean EjecutarComando(String Comando) {
int Aux, E;
boolean bAux;
String Op, Arg, sAux;
char C[] = new char[3];
// Se elimina cuaquier espacio antes y despus del comando
//
Comando.trim();
try {
Logger.EscribirEvento(Comando + Comando);
} catch (IOException ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
null, ex);
VOLVER A MEN
Arg.trim();
if (Arg.length() != 3 || Arg.charAt(0) != < || Arg.charAt(2) != >) return false;
if (Op.compareTo(N) == 0) return AgregarConjunto(Arg.charAt(1));
if (Op.compareTo(C) == 0) return SuprimirConjunto(Arg.charAt(1));
if (Op.compareTo(M) == 0) { MostrarOrdenado(Arg.charAt(1)); return true; }
return EstaVacio(Arg.charAt(1));
}
if (Op.compareTo(A) == 0 || Op.compareTo(D) == 0 || Op.compareTo(P) == 0) {
// Deben haber dos argumentos
//
Arg = Comando.substring(Aux + 1, Comando.length());
Arg.trim();
Aux = Arg.indexOf( , 0);
if (Aux < 0) return false;
sAux = Arg.substring(0, Aux);
sAux.trim();
if (sAux.length() < 3 || sAux.charAt(0) != < || sAux.charAt(sAux.length()-1) != >) return false;
try {
E = Integer.parseInt(sAux.substring(1, sAux.length()-1));
} catch (NumberFormatException ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
null, ex);
return false;
}
sAux = Arg.substring(Aux + 1, Arg.length());
sAux.trim();
if (sAux.length() != 3 || sAux.charAt(0) != < || sAux.charAt(2) != >) return false;
if (Op.compareTo(A) == 0) return AgregarElemento(E, sAux.charAt(1));
if (Op.compareTo(D) == 0) return SuprimirElemento(E, sAux.charAt(1));
return PerteneceElemento(E, sAux.charAt(1));
}
if (Op.compareTo(+) == 0 || Op.compareTo(-) == 0 || Op.compareTo(*) == 0) {
276
VOLVER A MEN
VOLVER A MEN
return false;
} catch (IOException ex) {
java.util.logging.Logger.getLogger(ManejadorConjuntos.class.getName()).log(Level.SEVERE,
null, ex);
return false;
}
return true;
}
public static void main(String[] args) {
boolean Fin = false;
BufferedReader Buffer = new BufferedReader(new InputStreamReader(System.in));
String S, strO, Arg;
int Aux;
ManejadorConjuntos Manejador = new ManejadorConjuntos();
do {
278
VOLVER A MEN
return;
}
// Se ubica la operacin
//
Aux = S.indexOf( , 0);
if (Aux < 0)
strO = S;
else
strO = S.substring(0, Aux);
// Proceder segn el operador
//
if (strO.compareTo(?) == 0) {
System.out.println(?\t\t\tMuestra la lista de opciones);
System.out.println(N <C>\t\t\tAgregar al ambiente un conjunto de identificador <C>);
System.out.println(C <C>\t\t\tSuprimir del ambiente el conjunto de identificador <C>);
System.out.println(V <C>\t\t\tIndicar si el conjunto de identificador <C> est o no vaco);
System.out.println(A <N> <C>\t\tAgregar el elemento <N> al conjunto <C> que est
actualmente en el ambiente);
System.out.println(D <N> <C>\t\tSuprimir el elemento <N> del conjunto <C> que est
279
actualmente en el ambiente);
VOLVER A MEN
est
actualmente en el ambiente);
System.out.println(+ <C1> <C2> <C3>\tCalcular y guardar en <C3> la unin de <C1> con
<C2>);
System.out.println(* <C1> <C2> <C3>\tCalcular y guardar en <C3> la interseccin de <C1>
con <C2>);
System.out.println(- <C1> <C2> <C3>\tCalcular y guardar en <C3> la diferencia entre <C1>
<C2>);
System.out.println(M <C>\t\t\tMostrar la informacin ordenada del conjunto de identificador
<C>);
System.out.println(I\t\t\tMostrar la informacin ordenada del ambiente);
System.out.println(S <A>\t\t\tGuardar el estado del ambiente en el archivo de nombre <A>);
System.out.println(L <A>\t\t\tCargar o recuperar del archivo de nombre <A> lo que debe
estar
en el ambiente);
System.out.println(E <A>\t\t\tEjecutar el archivo de comandos de nombre <A>);
System.out.println(F\t\t\tSalir del entorno\n);
}
else
if (strO.compareTo(V) == 0) {
if (Manejador.EjecutarComando(S))
System.out.println(El conjunto est vaco);
else
System.out.println(El conjunto no est vaco el conjunto no existe);
}
else
if (strO.compareTo(P) == 0) {
if (Manejador.EjecutarComando(S))
System.out.println(El elemento SI pertenece al conjunto);
else
System.out.println(El elemento NO pertenece al conjunto el conjunto no existe);
}
280
VOLVER A MEN
else
if (strO.compareTo(I) == 0) Manejador.MostrarOrdenado();
else
if (strO.compareTo(F) == 0) {
Manejador.finalize();
Fin = true;
}
else
if (strO.compareTo(E) == 0) {
// Debe haber un argumento
//
Arg = S.substring(Aux + 1, S.length());
Arg.trim();
Manejador.EjecutarComandos(Arg.substring(1, Arg.length()-1));
}
else {
if (!Manejador.EjecutarComando(S))
System.out.println(Algn problema ejecutando el comando);
}
} while (!Fin);
}
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.4
* ArchivoEventos.java
* Mauricio Paletta
*/
package manejoconjuntos;
import java.io.FileWriter;
import java.io.IOException;
281
VOLVER A MEN
import java.io.PrintWriter;
import java.util.Calendar;
// Representa un archivo de eventos
//
public class ArchivoEventos extends FileWriter {
private PrintWriter Pw;
public ArchivoEventos(String Nombre) throws IOException{
super(Nombre);
Pw = new PrintWriter(this);
}
public ArchivoEventos() throws IOException {
this(Logger.Txt);
}
@Override
public void finalize() throws Throwable {
super.finalize();
this.close();
}
public void EscribirEvento(String Ev) throws IOException {
Calendar C = Calendar.getInstance();
String Fecha = < + Integer.toString(C.get(Calendar.DAY_OF_MONTH)) + / +
Integer.toString(C.get(Calendar.MONTH) + 1) + / + Integer.toString(C.get(Calendar.YEAR)) +
Integer.toString(C.get(Calendar.MINUTE)) + : + Integer.toString(C.get(Calendar.SECOND)) +
>: ;
Pw.println(Fecha + Ev);
}
}
282
VOLVER A MEN
Por ltimo, a continuacin el cdigo escrito en C#. Se tienen los archivos fuente
ManejadorConjuntos.cs y ArchivoEventos.cs y todos los elementos definidos
asociados al paquete o espacio de nombres identificado como ManejoConjuntos
(ver Figura 6.22).
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C#; caso prctico Seccin 6.4
* ManejadorConjuntos.cs
* Mauricio Paletta
*/
using System;
using System.IO;
using System.Collections.Generic;
namespace ManejoConjuntos
{
// Representa un conjunto de enteros
//
class ConjuntoEnteros : SortedSet<int> {
private char Identificador;
public ConjuntoEnteros(char Id) : base() {
if (Id < A || Id > Z) Id = *;
Identificador = Id;
}
public ConjuntoEnteros() : this(*) { }
public char ObtId() { return Identificador; }
public bool Pertenece(int E) { return this.Contains(E); }
public bool Agregar(int E) {
return this.Add(E);
}
public bool Suprimir(int E) {
return this.Remove(E);
283
VOLVER A MEN
}
public void MostrarOrdenado() {
Console.Write(Convert.ToString(Identificador) + : { );
foreach (int E in this)
Console.Write({0} , E);
Console.WriteLine(});
}
public void GuardarArchivo(BinaryWriter MiArchivo) {
int []E;
if (MiArchivo == null) return;
MiArchivo.Write(Identificador);
MiArchivo.Write((Int32)this.Count);
if (this.Count > 0) {
E = new int[this.Count];
this.CopyTo(E);
for (int i=0; i < Count; i++)
MiArchivo.Write((Int32)E[i]);
}
}
}
// Define un comparador para los conjuntos de enteros
//
class ComparadorConjuntoEnteros : IComparer<ConjuntoEnteros> {
public int Compare(ConjuntoEnteros C1, ConjuntoEnteros C2)
{
if (C1.ObtId() < C2.ObtId()) return -1;
if (C1.ObtId() > C2.ObtId()) return 1;
return 0;
}
}
284
VOLVER A MEN
class ManejadorConjuntos
{
private SortedSet<ConjuntoEnteros> Conjuntos;
private ArchivoEventos Logger;
public ManejadorConjuntos() {
Conjuntos = new SortedSet<ConjuntoEnteros>(new ComparadorConjuntoEnteros());
Logger = new ArchivoEventos();
Logger.EscribirEvento(Inicio de sesin);
}
~ManejadorConjuntos() {
Logger.EscribirEvento(Fin de sesin);
Logger.Cerrar();
}
public ConjuntoEnteros BuscarConjunto(char Id) {
foreach (ConjuntoEnteros C in Conjuntos)
if (C.ObtId() == Id) return C;
return null;
}
public bool AgregarConjunto(char Id) {
// Se verifica que el Id es vlido
//
if (Id < A || Id > Z) return false;
// Se verifica que no hay ningn otro conjunto con el mismo Id
//
ConjuntoEnteros C = BuscarConjunto(Id);
if (C != null) return false;
Conjuntos.Add(new ConjuntoEnteros(Id));
return true;
285
VOLVER A MEN
}
public bool SuprimirConjunto(char Id) {
// Se busca el conjunto
//
ConjuntoEnteros C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == null) return false;
Conjuntos.Remove(C);
return true;
}
public bool AgregarElemento(int E, char Id) {
// Primero se busca el conjunto
//
ConjuntoEnteros C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == null) return false;
return C.Agregar(E);
}
public bool SuprimirElemento(int E, char Id) {
// Primero se busca el conjunto
//
ConjuntoEnteros C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
//
if (C == null) return false;
return C.Suprimir(E);
}
286
VOLVER A MEN
C3 = BuscarConjunto(Id3);
// Primero se verifica la existencia de los 3 conjuntos
//
if (C1 == null || C2 == null || C3 == null) return false;
// Se procede a hacer la unin de C1 con C2 y guardar el resultado en C3
// Se elimina cualquier cosa previa que exista en C3
//
C3.Clear();
C3.UnionWith(C1);
C3.UnionWith(C2);
return true;
}
public bool HacerInterseccion(char Id1, char Id2, char Id3) {
ConjuntoEnteros C1 = BuscarConjunto(Id1), C2 = BuscarConjunto(Id2),
C3 = BuscarConjunto(Id3);
// Primero se verifica la existencia de los 3 conjuntos
//
if (C1 == null || C2 == null || C3 == null) return false;
287
VOLVER A MEN
C3 = BuscarConjunto(Id3);
// Primero se verifica la existencia de los 3 conjuntos
//
if (C1 == null || C2 == null || C3 == null) return false;
// Se procede a hacer la unin de C1 con C2 y guardar el resultado en C3
// Se elimina cualquier cosa previa que exista en C3
//
C3.Clear();
C3.UnionWith(C1);
C3.ExceptWith(C2);
return true;
}
public bool EstaVacio(char Id) {
// Primero se busca el conjunto
//
ConjuntoEnteros C = BuscarConjunto(Id);
// Se verifica si un conjunto con ese Id existe
// Caso contrario se dice que est vaco
//
288
VOLVER A MEN
VOLVER A MEN
290
VOLVER A MEN
VOLVER A MEN
Arg.Trim();
Aux = Arg.IndexOf( , 0);
if (Aux < 0) return false;
sAux = Arg.Substring(0, Aux);
sAux.Trim();
if (sAux.Length < 3 || sAux[0] != < || sAux[sAux.Length-1] != >) return false;
E = Convert.ToInt32(sAux.Substring(1, sAux.Length-2));
sAux = Arg.Substring(Aux + 1, Arg.Length - (Aux + 1));
sAux.Trim();
if (sAux.Length != 3 || sAux[0] != < || sAux[2] != >) return false;
if (Op == A) return AgregarElemento(E, sAux[1]);
if (Op == D) return SuprimirElemento(E, sAux[1]);
return PerteneceElemento(E, sAux[1]);
}
if (Op == + || Op == - || Op == *) {
// Deben haber tres argumentos
//
Arg = Comando;
for (int i=0; i < 3; i++) {
Arg = Arg.Substring(Aux + 1, Arg.Length - (Aux + 1));
Arg.Trim();
Aux = Arg.IndexOf( , 0);
if (i < 2) {
if (Aux < 0) return false;
sAux = Arg.Substring(0, Aux);
}
else
sAux = Arg;
sAux.Trim();
if (sAux.Length != 3 || sAux[0] != < || sAux[2] != >) return false;
C[i] = sAux[1];
}
292
VOLVER A MEN
Cargar(Arg.Substring(1, Arg.Length-2)));
}
return false;
}
public bool EjecutarComandos(string Nombre) {
StreamReader MiArchivo = new StreamReader(Nombre);
Logger.EscribirEvento(Archivo de Comandos + Nombre);
while (!MiArchivo.EndOfStream)
EjecutarComando(MiArchivo.ReadLine());
MiArchivo.Close();
return true;
}
public static void Main(string[] args)
{
bool Fin = false;
string S, strO, Arg;
int Aux;
ManejadorConjuntos Manejador = new ManejadorConjuntos();
293
VOLVER A MEN
do {
// Primero se muestra el indicador
//
Console.Write(Conjuntos> );
// Se lee una lnea de comando
//
S = Console.In.ReadLine();
S.Trim();
// Se ubica la operacin
//
Aux = S.IndexOf( , 0);
if (Aux < 0)
strO = S;
else
strO = S.Substring(0, Aux);
// Proceder segn el operador
//
if (strO == ?) {
Console.WriteLine(?\t\t\tMuestra la lista de opciones);
Console.WriteLine(N <C>\t\t\tAgregar al ambiente un conjunto de identificador <C>);
Console.WriteLine(C <C>\t\t\tSuprimir del ambiente el conjunto de identificador <C>);
vaco);
actualmente en el ambiente);
Console.WriteLine(P <N> <C>\t\tIndicar si el elemento <N> pertenece al conjunto <C>
con
<C2>);
Console.WriteLine(* <C1> <C2> <C3>\tCalcular y guardar en <C3> la interseccin de
294
VOLVER A MEN
<C1> y <C2>);
Console.WriteLine(M <C>\t\t\tMostrar la informacin ordenada del conjunto de
identificador <C>);
Console.WriteLine(I\t\t\tMostrar la informacin ordenada del ambiente);
Console.WriteLine(S <A>\t\t\tGuardar el estado del ambiente en el archivo de nombre
<A>);
Console.WriteLine(L <A>\t\t\tCargar o recuperar del archivo de nombre <A> lo que debe
estar en el ambiente);
Console.WriteLine(E <A>\t\t\tEjecutar el archivo de comandos de nombre <A>);
Console.WriteLine(F\t\t\tSalir del entorno\n);
}
else
if (strO == V) {
if (Manejador.EjecutarComando(S))
Console.WriteLine(El conjunto est vaco);
else
Console.WriteLine(El conjunto no est vaco el conjunto no existe);
}
else
if (strO == P) {
if (Manejador.EjecutarComando(S))
Console.WriteLine(El elemento SI pertenece al conjunto);
else
Console.WriteLine(El elemento NO pertenece al conjunto el conjunto no existe);
}
else
if (strO == I) Manejador.MostrarOrdenado();
else
if (strO == F) {
Fin = true;
}
295
VOLVER A MEN
else
if (strO == E) {
// Debe haber un argumento
//
Arg = S.Substring(Aux + 1, S.Length - (Aux + 1));
Arg.Trim();
Manejador.EjecutarComandos(Arg.Substring(1, Arg.Length-2));
}
else {
if (!Manejador.EjecutarComando(S))
Console.WriteLine(Algn problema ejecutando el comando);
}
} while (!Fin);
}
}
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C#; caso prctico Seccin 6.4
* ArchivoEventos.cs
* Mauricio Paletta
*/
using System;
using System.IO;
namespace ManejoConjuntos
{
// Representa un archivo de eventos
//
public class ArchivoEventos : StreamWriter {
public ArchivoEventos(string Nombre) : base(Nombre) { }
296
VOLVER A MEN
VOLVER A MEN
haber un servicio que no sea atendido por ninguna taquilla. Una taquilla puede atender
todos los servicios y un mismo servicio puede ser atendido por todas las taquillas.
La cola de atencin se maneja segn una numeracin consecutiva por tipo de cliente.
Previo al inicio de la simulacin hay que configurar el escenario con la siguiente informacin:
1. Tipos de servicio.
2. Nmero de taquillas de atencin.
3. Servicios que presta cada taquilla de atencin.
Esta informacin se debe almacenar en disco, de manera tal que cada vez que el simulador
abra se cargue la informacin actualizada y cuando el simulador se cierre guarde siempre
su estado actual.
La simulacin consiste en lo siguiente:
1. Viene un cliente e identifica su tipo (prioridad) y el servicio que requiere.
2. El simulador le asigna un nmero.
3. Basado en la prioridad de atencin del tipo de cliente, en el servicio que requiere, en
las taquillas disponibles y la forma como stas estn configuradas, el simulador debe
informar el nmero siguiente a atender y en qu taquilla debe dirigirse el cliente.
4. Se asume que el tiempo que dura un cliente en una taquilla est entre 3 y 6 segundos y
se debe asignar de forma aleatoria una vez que el simulador seleccione el nmero del
cliente para su atencin.
5. Durante la simulacin se pueden habilitar o deshabilitar taquillas de atencin. Tambin
se pueden habilitar o deshabilitar servicios prestados por taquilla.
6. Se debe mostrar en todo momento el nmero de clientes en espera a ser atendidos.
7. Al cerrar la atencin al pblico, es decir, no aceptar ms clientes y una vez que sean
atendidos todos los clientes en espera, se debe emitir un resumen estadstico que
contenga la siguiente informacin:
Total de clientes atendidos en la oficina.
Total de clientes atendidos por taquilla.
Total de clientes atendidos por servicio.
Tiempo promedio de atencin desde que un cliente solicit el nmero de servicio
hasta que fue completamente atendido.
298
VOLVER A MEN
6.5.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): Luego de hacer una revisin del
texto del enunciado del problema descrito en la seccin anterior, un posible mapa mental que
resulta de este anlisis es el que se muestra en la Figura 6.23.
Figura 6.23. Mapa mental relativo al problema del manejo inteligente de colas de atencin.
Paso 2 (Identificar actores / nombres): Se tiene la siguiente lista de nombres: Simulador, manejo
de colas, cliente, servicio, prioridad, oficina, taquilla, cola de atencin, archivo y estadstica.
Paso 3 (Identificar procesos / requerimientos): Nuevamente se tiene un usuario como actor del
simulador y al igual que en el problema anterior, se tiene un archivo para guardar / recuperar
la informacin relativa a la configuracin del entorno de simulacin. En este sentido y tomando
en cuenta los requerimientos identificados en la Seccin 6.5.1, se tiene el diagrama de casos
de uso que se muestra en la Figura 6.24.
299
VOLVER A MEN
Figura 6.24. Diagrama de casos de uso relativo al problema del manejo inteligente de colas de atencin.
300
VOLVER A MEN
Figura 6.25. Diagrama no detallado de clases relativo al problema del manejo inteligente de colas de atencin.
6.5.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): Para este problema es conveniente usar una
interfaz grfica con un panel de botones para las diferentes opciones a realizar: configurar,
cargar, guardar, e iniciar / detener la simulacin. Es conveniente tambin tener un par de
formularios (formas) para permitir por un lado la configuracin basado en la edicin de los
parmetros correspondientes y por otro lado para mostrar la simulacin. Adicionalmente se
requiere la interaccin con un archivo para guardar / cargar la configuracin. Para ello se
decidi utilizar el formato XML con el siguiente detalle que se presenta a continuacin con un
ejemplo basado en 6 servicios: S1, S2, S3, S4, S5 y S6; 1 oficina identificada con el
nmero 1 que tiene 4 taquillas identificadas con los nmeros 1, 2, 3 y 4 respectivamente; la
taquilla 1 ofrece los servicios S1, S2, y S5; la taquilla 2 ofrece los servicios S1 y S3; la
taquilla 3 ofrece los servicios S2, S4 y S6 y la taquilla 4 ofrece los servicios S2 y S4.
<?xml version=1.0?>
<ManejoColas>
<Servicios>
301
<Servicio>S1</Servicio>
<Servicio>S2</Servicio>
<Servicio>S3</Servicio>
<Servicio>S4</Servicio>
VOLVER A MEN
<Servicio>S5</Servicio>
<Servicio>S6</Servicio>
</Servicios>
<Oficina Id=1 Taquillas=4>
<Taquilla Id=1>
<Servicio>S1</Servicio>
<Servicio>S2</Servicio>
<Servicio>S5</Servicio>
</Taquilla>
<Taquilla Id=2>
<Servicio>S1</Servicio>
<Servicio>S3</Servicio>
</Taquilla>
<Taquilla Id=3>
<Servicio>S2</Servicio>
<Servicio>S4</Servicio>
<Servicio>S6</Servicio>
</Taquilla>
<Taquilla Id=4>
<Servicio>S2</Servicio>
<Servicio>S4</Servicio>
</Taquilla>
</Oficina>
</ManejoColas>
Paso 2 (Detallar las clases): Al agregar los atributos y mtodos a las clases de la Figura 6.25
resulta el diagrama de clases detallado de la Figura 6.26.
302
VOLVER A MEN
Figura 6.26. Diagrama detallado de clases relativo al problema del manejo inteligente de colas de atencin.
Paso 3 (Desarrollar los modelos de estado): Ntese que las clases Cliente, ClienteEspera
y Servicio asignan sus atributos en tiempo de construccin del objeto y stos luegos no
son modificados nuevamente por ningn mtodo. De esta manera, la Figura 6.27 muestra los
diagramas de estado de cada una de las clases presentes en el modelo de este problema. A
fin de no complicar la lectura del diagrama se obvian las transiciones recursivas que indican
permanecer en el mismo estado luego de la llamada del mtodo correspondiente.
303
VOLVER A MEN
Figura 6.27. Diagramas de estado relativos al problema del manejo inteligente de colas de atencin.
Paso 4 (Elaborar los modelos de colaboracin): La Figura 6.28 muestra los diagramas de
secuencia relativos a este problema y basado en el diagrama de casos de uso de la Figura
6.24 y el diagrama de clases de la Figura 6.26. En este sentido se tienen dos diagramas, uno
para los casos de uso relacionados con la configuracin (parte superior) y otro para los casos
de uso relacionados con la simulacin (parte inferior). El orden en el cual se ejecutan los
eventos no est acorde a una secuencia de operacin aunque se trata de reflejar qu acciones
son precedentes de otras.
304
VOLVER A MEN
Figura 6.28. Diagramas de secuencia relativos al problema del manejo inteligente de colas de atencin:
1) configuracin (parte superior); 2) simulacin (parte inferior).
Paso 5 (Identificar componentes del dominio): Asumiendo el uso de C++ para la implementacin
de este caso prctico se tiene el diagrama de componentes correspondiente al problema que
se presenta en la Figura 6.29. Ntese las dependencias entre los archivos de cdigo fuente
extencin cpp y los archivos encabezado xon extensin hpp. Ntese tambin la incorporacin
de los elementos grficos (ui) relativos al kit de desarrollo de Qt.
305
VOLVER A MEN
Figura 6.29. Diagrama de componentes relativo al problema del manejo inteligente de colas de atencin.
6.5.4 Programacin
A continuacin el cdigo escrito en C++ relativo al problema. Para evitar ser tan extenso no
se agrega el manejo de la interfaz grfica (este puede ser consultado en el material digital
entregado junto a este libro). Primero se muestran los archivos Cliente.hpp y Cliente.cpp.
Luego se muestran los archivos Servicio.hpp y Servicio.cpp. Ntese que en estos dos
casos el archivo extensin cpp solo se utiliza para hacer la inclusin del archivo encabezado
hpp correspondiente. Posteriormente se muestran los archivos Oficina.hpp y Oficina.
cpp y finalmente se encuentra el cdigo fuente relativo a los archivos ManejadorCola.hpp y
ManejadorCola.cpp.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.5
* Cliente.hpp
* Mauricio Paletta
*/
#ifndef CLIENTE_HPP
#define
306
CLIENTE_HPP
VOLVER A MEN
enum PrioridadAtencion {
Baja, Media, Alta
};
class Cliente {
private:
PrioridadAtencion Prioridad;
int Id;
public:
Cliente(int id, PrioridadAtencion p) {
Id = id; Prioridad = p;
}
int ObtId() { return Id; }
PrioridadAtencion ObtPrioridad() { return Prioridad; }
};
typedef Cliente *pCliente;
#endif /* CLIENTE_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.5
* Cliente.cpp
* Mauricio Paletta
*/
#include Cliente.hpp
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.5
* Servicio.hpp
307
VOLVER A MEN
* Mauricio Paletta
*/
#ifndef SERVICIO_HPP
#define
SERVICIO_HPP
#include <string>
using namespace std;
class Servicio {
private:
string Nombre;
public:
Servicio(string Str) { Nombre = Str; }
string ObtNombre() { return Nombre; }
string ToString() { return ObtNombre(); }
bool operator ==(Servicio S) { return this->Nombre == S.Nombre; }
};
typedef Servicio *pServicio;
#endif /* SERVICIO_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.5
* Servicio.cpp
* Mauricio Paletta
*/
#include Servicio.hpp
308
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.5
* Oficina.hpp
* Mauricio Paletta
*/
#ifndef OFICINA_HPP
#define OFICINA_HPP
#include <QtGui>
#include <string>
#include <vector>
#include <sstream>
#include <time.h>
#include Servicio.hpp
#include Cliente.hpp
using namespace std;
// Para convertir nmeros a cadenas de caracteres
//
class Convertir {
public:
static string ToString(int N) {
stringstream R;
R << N;
return R.str() ;
}
static string ToString(double N) {
stringstream R;
R << N;
309
VOLVER A MEN
return R.str();
}
};
// Representa una taquilla de la oficina
//
class Taquilla {
private:
int Id;
vector<pServicio> Servicios;
bool Habilitada;
pServicio BuscarServicio(string nombreS);
public:
Taquilla(int id) {
Id = id; Habilitada = true;
}
~Taquilla();
int ObtId() { return Id; }
string ToString() { return Convertir::ToString(Id); }
int ObtNumeroServicios() { return Servicios.size(); }
pServicio ObtServicio(int Ind) { return Servicios[Ind]; }
void Habilitar() { Habilitada = true; }
void Deshabilitar() { Habilitada = false; }
bool EstaHabilitada() { return Habilitada; }
void AgregarServicio(Servicio S) {
// Primero se verifica si el servicio ya existe
//
if (BuscarServicio(S.ObtNombre()) != NULL) return;
Servicios.push_back(&S);
}
void AgregarServicio(string nombreS) {
310
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
313
VOLVER A MEN
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.5
* Oficina.cpp
* Mauricio Paletta
*/
#include <limits>
#include <cstdlib>
#include ManejadorColas.hpp
#include Oficina.hpp
// Mtodos de la clase Taquilla
//
Servicio *Taquilla::BuscarServicio(string nombreS) {
for (unsigned i=0; i < Servicios.size(); i++) {
pServicio S = Servicios[i];
if (nombreS == S->ObtNombre()) return S;
}
return NULL;
}
void Taquilla::RemoverServicio(Servicio S) {
for(vector<pServicio>::iterator It=Servicios.begin(); It != Servicios.end(); It++) {
pServicio T = (pServicio)*It;
if (T != NULL && *T == S) {
delete T;
Servicios.erase(It);
return;
}
}
}
315
VOLVER A MEN
Taquilla::~Taquilla() {
for(vector<pServicio>::iterator It=Servicios.begin(); It != Servicios.end(); It++) {
pServicio T = (pServicio)*It;
if (T != NULL) delete T;
}
Servicios.clear();
}
// Mtodos de la clase GestorEstadisticas
//
GestorEstadisticas::GestorEstadisticas(int N, int S) {
int i;
if (N <= 0) N = 1;
TotalClientesOficina = 0;
PromedioAtencion = MaximoAtencion = 0.0;
MinimoAtencion = numeric_limits<double>::max();
TotalClientesTaquilla = new int[N];
TotalClientesServicio = new int[S];
for (i=0; i < N; i++)
TotalClientesTaquilla[i] = 0;
for (i=0; i < S; i++)
TotalClientesServicio[i] = 0;
nT = N; nS = S;
}
GestorEstadisticas::~GestorEstadisticas() {
delete[] TotalClientesTaquilla;
delete[] TotalClientesServicio;
}
void GestorEstadisticas::AgregarClienteTaquilla(pClienteEspera CE) {
if (CE == NULL || CE->ObtTaquilla() == NULL || CE->ObtServicio() == NULL) return;
if (CE->ObtTaquilla()->ObtId() <= 0 || CE->ObtTaquilla()->ObtId() > nT) return;
316
VOLVER A MEN
Convertir::ToString(TotalClientesServicio[s]) + \n;
}
Promedio = TotalClientesOficina > 0 ? PromedioAtencion / TotalClientesOficina : 0.0;
Texto += Promedio de atencin: + Convertir::ToString(Promedio) + \n;
Texto += Tiempo mnimo de atencin: + Convertir::ToString(MinimoAtencion) + \n;
Texto += Tiempo mximo de atencin: + Convertir::ToString(MaximoAtencion) + \n;
return Texto;
}
317
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
ClientesEspera.push_back(CE);
// Se actualizan las estadsticas
//
Estadisticas->AgregarClienteTaquilla(CE);
}
}
void Oficina::RevisarEstadoTaquillas() {
pClienteEspera CE, *Menores;
bool *TaquillaLibre;
int T;
unsigned c;
// Si no hay clientes en espera nada que hacer
//
if (ClientesEspera.size() == 0) return;
Menores = new pClienteEspera[Nt];
TaquillaLibre = new bool[Nt];
// Para todas las taquillas de la oficina
//
for (T=0; T < Nt; T++) {
Menores[T] = NULL;
TaquillaLibre[T] = true;
}
for (c=0; c < ClientesEspera.size(); ) {
CE = (pClienteEspera)ClientesEspera[c];
T = CE->ObtTaquilla()->ObtId() - 1;
321
VOLVER A MEN
VOLVER A MEN
Menores[T]->AsgEstado(Atendiendo);
Menores[T]->Atender();
}
}
delete[] Menores;
delete[] TaquillaLibre;
}
// Buscar el cliente que se est atendiendo actualmente en la taquilla
// indicada y retornar una cadena de caracteres con formato para actualizar
// la lista de estado de avance correspondiente
//
string Oficina::ClienteAtendidoTaquilla(pTaquilla T) {
for (unsigned i=0; i < ClientesEspera.size(); i++) {
pClienteEspera CE = (pClienteEspera)ClientesEspera[i];
if (CE->ObtTaquilla() == T && CE->ObtEstado() == Atendiendo)
return Convertir::ToString(CE->ObtCliente()->ObtId()) + ( +
Convertir::ToString(CE->ObtNumeroAtencion()) + );
}
return ;
}
// Armar en una cadena de caracteres la cola de clientes asociados a un servicio
// de una taquilla especfica
//
string Oficina::ClientesEsperaTaquilla(pTaquilla T, pServicio S) {
string Clientes = ;
for (unsigned i=0; i < ClientesEspera.size(); i++) {
pClienteEspera CE = (pClienteEspera)ClientesEspera[i];
if (CE->ObtTaquilla() == T && CE->ObtEstado() != Atendiendo && CE->ObtServicio() == S)
Clientes += Convertir::ToString(CE->ObtCliente()->ObtId()) + ( +
323
VOLVER A MEN
Convertir::ToString(CE->ObtNumeroAtencion()) + ) ;
}
return Clientes;
}
// Mtodos de la clase ClienteEspera
//
ClienteEspera::ClienteEspera(pCliente c, pServicio s, pTaquilla t, pOficina o, int n) {
C = c; S = s; T = t; N = n; O = o; E = Espera;
DuracionServicio = (rand() % 6) + 1;
}
// Para representar el reloj del tiempo de duracin del cliente en espera
//
void ClienteEspera::OnTimedEvent() {
time_t FinServicio;
// Ver si el cliente ya ha sido servido
//
time(&FinServicio);
if (difftime(FinServicio, InicioServicio) >= DuracionServicio) {
E = Servido;
// Se actualiza las estadsticas
//
O->ClienteServido((double)DuracionServicio);
}
}
324
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.5
* ManejadorColas.cpp
* Mauricio Paletta
*/
#ifndef MANEJADORCOLAS_HPP
#define MANEJADORCOLAS_HPP
#include <QtGui>
#include <vector>
#include Servicio.hpp
#include Oficina.hpp
using namespace std;
class ManejadorColas {
private:
static vector<pServicio> Servicios;
vector<pOficina> Oficinas;
QTreeView *TreeSimulacion;
pServicio BuscarServicio(string nombreS);
QXmlStreamReader::TokenType ObtProxToken(QXmlStreamReader *Rxml);
public slots:
void OnTimedEvent();
public:
ManejadorColas() { }
~ManejadorColas() { LimpiarDatos(); }
325
VOLVER A MEN
326
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
}
Oficinas.clear();
for(vector<pServicio>::iterator It=Servicios.begin(); It != Servicios.end(); It++) {
pServicio S = (pServicio)*It;
if (S != NULL) delete S;
}
Servicios.clear();
}
bool ManejadorColas::IniciarSimulacion(int iD, QTreeView *TreeS) {
// La simulacin no puede iniciar si no estn dadas las condiciones
//
time_t segundos;
pOficina O = BuscarOficina(1);
if (!RevisarPrestacionServicios(iD) || O == NULL) return false;
// Iniciar la simulacin
//
time(&segundos);
srand((unsigned)segundos);
O->LimpiarClientes();
TreeSimulacion = TreeS;
// Se carga el rbol de la simulacin
//
QStandardItemModel *Model;
QStandardItem *nOficina = new QStandardItem(Oficina 1);
Model = (QStandardItemModel *)TreeSimulacion->model();
if (Model != NULL)
delete Model;
Model = new QStandardItemModel();
329
VOLVER A MEN
330
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
if (Token == QXmlStreamReader::Characters)
Token = Rxml->readNext();
return Token;
}
bool ManejadorColas::CargarConfiguracion(QString NombreA) {
int j, nT;
pOficina O;
QFile xmlDoc(NombreA);
QXmlStreamReader Rxml;
QXmlStreamReader::TokenType Token;
if (!xmlDoc.open(QFile::ReadOnly | QFile::Text)) return false;
Rxml.setDevice(&xmlDoc);
Token = Rxml.readNext();
if (Token != QXmlStreamReader::StartDocument) {
xmlDoc.close();
return false;
}
Token = Rxml.readNext();
if (Token != QXmlStreamReader::StartElement || Rxml.name() != ManejoColas) {
xmlDoc.close();
return false;
}
// Primero se limpia cualquier dato existente
//
LimpiarDatos();
// Se cargan los servicios
//
333
VOLVER A MEN
Token = ObtProxToken(&Rxml);
if (Token != QXmlStreamReader::StartElement || Rxml.name() != Servicios) {
xmlDoc.close();
return false;
}
Token = ObtProxToken(&Rxml);
while(!Rxml.atEnd() && !Rxml.hasError() && Token != QXmlStreamReader::EndElement) {
if (Token == QXmlStreamReader::StartElement && Rxml.name() == Servicio) {
string Aux = Rxml.readElementText().toStdString();
AgregarServicio(Aux);
}
Token = ObtProxToken(&Rxml);
}
// Se agrega una oficina
//
Token = ObtProxToken(&Rxml);
if (Token == QXmlStreamReader::StartElement && Rxml.name() == Oficina) {
nT = Rxml.attributes()[1].value().toString().toInt();
AgregarOficina(1, nT, Servicios.size());
O = BuscarOficina(1);
// Se cargan los servicios x taquillas
//
for (j=0; j < nT; j++) {
Token = ObtProxToken(&Rxml);
if (Token == QXmlStreamReader::StartElement && Rxml.name() == Taquilla) {
Token = ObtProxToken(&Rxml);
while (!Rxml.atEnd() && !Rxml.hasError() && Token != QXmlStreamReader::EndElement) {
if (Token == QXmlStreamReader::StartElement && Rxml.name() == Servicio) {
O->AgregarServicioTaquilla(Rxml.readElementText().toStdString(), j);
}
Token = ObtProxToken(&Rxml);
334
VOLVER A MEN
}
}
}
}
Rxml.clear();
xmlDoc.close();
return true;
}
bool ManejadorColas::GuardarConfiguracion(QString NombreA) {
int i, j;
pOficina O;
QFile xmlDoc(NombreA);
xmlDoc.open(QIODevice::WriteOnly);
QXmlStreamWriter xmlWriter(&xmlDoc);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
// Elemento raz
//
xmlWriter.writeStartElement(ManejoColas);
// Servicios
//
xmlWriter.writeStartElement(Servicios);
for (i=0; i < ObtNumeroServicios(); i++) {
pServicio S = ObtServicio(i);
if (S != NULL) {
xmlWriter.writeTextElement(Servicio, S->ObtNombre().c_str());
}
}
335
VOLVER A MEN
xmlWriter.writeEndElement();
// Se agrega la oficina
//
O = BuscarOficina(1);
if (O != NULL) {
xmlWriter.writeStartElement(Oficina);
xmlWriter.writeAttribute(Id, 1);
xmlWriter.writeAttribute(Taquillas, Convertir::ToString(O->ObtNumeroTaquillas()).c_str());
for (i=0; i < O->ObtNumeroTaquillas(); i++) {
xmlWriter.writeStartElement(Taquilla);
xmlWriter.writeAttribute(Id, Convertir::ToString(i+1).c_str());
for (j=0; j < O->ObtNumeroServiciosTaquilla(i); j++) {
pServicio S = O->ObtServicioTaquilla(i, j);
if (S != NULL)
xmlWriter.writeTextElement(Servicio, S->ObtNombre().c_str());
}
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
}
// Se escribe la data en el archivo XML
//
xmlWriter.writeEndElement();
xmlDoc.close();
return true;
}
336
VOLVER A MEN
En relacin a Java se tiene el cdigo fuente que aparece a continuacin (sin incluir el manejo
de la interfaz grfica). Se tiene el paquete ManejadorColas y los siguientes archivos fuente:
ManejadorColas.java, Servicio.java, Cliente.java y Oficina.java.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.5
* ManejadorColas.java
* Mauricio Paletta
*/
package ManejadorColas;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
337
VOLVER A MEN
VOLVER A MEN
else
if (Rnd.nextDouble() < 0.66) P = Cliente.PrioridadAtencion.Media;
else
P = Cliente.PrioridadAtencion.Alta;
C = new Cliente(O.ProximoCliente(), P);
// Se selecciona al azar el servicio que desea hacer el cliete
//
S = ObtServicio(Rnd.nextInt(Servicios.size()));
O.NuevoClienteEspera(C, S);
}
// Actaulizar el rbol de visualizacin del estado de la simulacin
//
DefaultTreeModel Model = (DefaultTreeModel)jTreeSimulacion.getModel();
DefaultMutableTreeNode nOficina =
VOLVER A MEN
A = Aux.indexOf(:);
if (A >= 0) {
N = Aux.substring(0, A);
nServicio.setUserObject(N + : +
O.ClientesEsperaTaquilla(O.BuscarTaquilla(t), BuscarServicio(N)));
}
}
}
}
}
Model.reload(nOficina);
for (int i=0; i < jTreeSimulacion.getRowCount(); i++)
jTreeSimulacion.expandRow(i);
}
};
private Timer timerS;
public ManejadorColas() {
if (Servicios == null)
Servicios = new ArrayList<Servicio>();
Oficinas = new ArrayList<Oficina>();
}
private Servicio BuscarServicio(String nombreS) {
for (Iterator<Servicio> It = Servicios.iterator(); It.hasNext(); ) {
Servicio S = It.next();
if (nombreS.compareTo(S.ObtNombre()) == 0) return S;
}
return null;
}
public static Servicio BuscarServicio(int Ind) {
return Servicios.get(Ind);
340
VOLVER A MEN
}
public static int BuscarIndiceServicio(String nombreS) {
for (int i=0; i < Servicios.size(); i++) {
Servicio S = Servicios.get(i);
if (nombreS.compareTo(S.ObtNombre()) == 0) return i;
}
return -1;
}
public void AgregarServicio(String nombreS) {
if (BuscarServicio(nombreS) != null) return;
Servicios.add(new Servicio(nombreS));
}
public void RemoverServicio(String nombreS) {
Servicio S = BuscarServicio(nombreS);
if (S == null) return;
Servicios.remove(S);
}
public int ObtNumeroServicios() {
return Servicios.size();
}
public Servicio ObtServicio(int Ind) {
return Servicios.get(Ind);
}
public Oficina BuscarOficina(int iD) {
for (Iterator<Oficina> It = Oficinas.iterator(); It.hasNext(); ) {
Oficina O = It.next();
if (O.ObtId() == iD) return O;
341
VOLVER A MEN
}
return null;
}
public void AgregarOficina(int iD, int nT, int nS) {
if (BuscarOficina(iD) != null) return;
Oficinas.add(new Oficina(iD, nT, nS));
}
public void RemoverOficina(int iD) {
Oficina O = BuscarOficina(iD);
if (O == null) return;
Oficinas.remove(O);
}
// Elimina todos los datos existentes en el objeto
//
public void LimpiarDatos() {
Servicios.clear();
Oficinas.clear();
}
// Revisa que todos los servicios estn garantizados a ser
// prestados en la oficina iD
//
public boolean RevisarPrestacionServicios(int iD) {
// Primero se ubica la oficina
//
Oficina O = BuscarOficina(iD);
if (O == null) return false;
return O.RevisarPrestacionServicios(Servicios);
}
342
VOLVER A MEN
VOLVER A MEN
344
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
}
// Se agrega la oficina
//
O = BuscarOficina(1);
if (O != null) {
ElementoO = doc.createElement(Oficina);
ElementoO.setAttribute(Id, 1);
ElementoO.setAttribute(Taquillas, Integer.toString(O.ObtNumeroTaquillas()));
Elemento.appendChild(ElementoO);
for (i=0; i < O.ObtNumeroTaquillas(); i++) {
ElementoT = doc.createElement(Taquilla);
ElementoT.setAttribute(Id, Integer.toString(i+1));
ElementoO.appendChild(ElementoT);
for (j=0; j < O.ObtNumeroServiciosTaquilla(i); j++) {
Servicio S = O.ObtServicioTaquilla(i, j);
if (S != null) {
ElementoS = doc.createElement(Servicio);
ElementoS.appendChild(doc.createTextNode(S.ObtNombre()));
ElementoT.appendChild(ElementoS);
}
}
}
}
// Se escribe la data en el archivo XML
//
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(XmlFile);
transformer.transform(source, result);
347
VOLVER A MEN
return true;
} catch (ParserConfigurationException ex) {
Logger.getLogger(ManejoColas.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerConfigurationException ex) {
Logger.getLogger(ManejoColas.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerException ex) {
Logger.getLogger(ManejoColas.class.getName()).log(Level.SEVERE, null, ex);
}
return false;
}
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.5
* Servicio.java
* Mauricio Paletta
*/
package ManejadorColas;
// Representa un servicio a ser prestado por una taquilla de una oficina
//
public class Servicio {
private String Nombre;
public Servicio(String Str) {
Nombre = Str;
}
public String ObtNombre() {
return Nombre;
}
348
VOLVER A MEN
@Override
public String toString() {
return ObtNombre();
}
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.5
* Cliente.java
* Mauricio Paletta
*/
package ManejadorColas;
// Representa un cliente de la oficina
//
public class Cliente {
public enum PrioridadAtencion {
Baja, Media, Alta
}
private PrioridadAtencion Prioridad;
private int Id;
public Cliente(int id, PrioridadAtencion p) {
Id = id;
Prioridad = p;
}
public int ObtId() {
return Id;
}
349
VOLVER A MEN
VOLVER A MEN
MinimoAtencion = Double.MAX_VALUE;
TotalClientesTaquilla = new int[N];
TotalClientesServicio = new int[S];
for (i=0; i < N; i++)
TotalClientesTaquilla[i] = 0;
for (i=0; i < S; i++)
TotalClientesServicio[i] = 0;
}
private void AgregarClienteTaquilla(ClienteEspera CE) {
if (CE == null || CE.T == null || CE.S == null) return;
if (CE.T.Id <= 0 || CE.T.Id > TotalClientesTaquilla.length) return;
if (ManejadorColas.BuscarIndiceServicio(CE.S.ObtNombre()) < 0) return;
TotalClientesOficina++;
TotalClientesTaquilla[CE.T.Id-1]++;
TotalClientesServicio[ManejadorColas.BuscarIndiceServicio(CE.S.ObtNombre())]++;
}
private void ClienteServido(double Tpo) {
PromedioAtencion += Tpo;
if (Tpo < MinimoAtencion) MinimoAtencion = Tpo;
if (Tpo > MaximoAtencion) MaximoAtencion = Tpo;
}
@Override
public String toString() {
String Texto = ;
double Promedio;
Texto += Total Clientes Oficina: + Integer.toString(TotalClientesOficina) + \n;
Texto += Total Clientes Taquilla:\n;
for (int t=0; t < TotalClientesTaquilla.length; t++) {
Texto += \t + Integer.toString(t+1) + : + Integer.toString(TotalClientesTaquilla[t]) +\n;
351
VOLVER A MEN
}
Texto += Total Clientes Servicio:\n;
for (int s=0; s < TotalClientesServicio.length; s++) {
Texto += \t + ManejadorColas.BuscarServicio(s) + : +
Integer.toString(TotalClientesServicio[s]) +\n;
}
Promedio = TotalClientesOficina > 0 ? PromedioAtencion / TotalClientesOficina : 0.0;
Texto += Promedio de atencin: + Double.toString(Promedio) + \n;
Texto += Tiempo mnimo de atencin: + Double.toString(MinimoAtencion) + \n;
Texto += Tiempo mximo de atencin: + Double.toString(MaximoAtencion) + \n;
return Texto;
}
}
// Representa una taquilla de la oficina
//
public class Taquilla {
private int Id;
private ArrayList<Servicio> Servicios;
private boolean Habilitada;
public Taquilla(int id) {
Id = id;
Servicios = new ArrayList<Servicio>();
Habilitada = true;
}
public int ObtId() {
return Id;
}
@Override
352
VOLVER A MEN
VOLVER A MEN
//
if (S == null || Servicios.indexOf(S) >= 0 || BuscarServicio(S.ObtNombre()) != null) return;
Servicios.add(S);
}
public void AgregarServicio(String nombreS) {
// Primero se verifica si el servicio ya existe
//
if (BuscarServicio(nombreS) != null) return;
Servicios.add(new Servicio(nombreS));
}
public void RemoverServicio(Servicio S) {
Servicios.remove(S);
}
public void RemoverServicio(String nombreS) {
Servicios.remove(BuscarServicio(nombreS));
}
public boolean OfreceServicio(String nombreS) {
return BuscarServicio(nombreS) != null;
}
}
// Representa un cliente en espera
//
public enum Estado {
Espera, Atendiendo, Servido
}
public class ClienteEspera {
private Cliente C;
private Servicio S;
private Taquilla T;
354
VOLVER A MEN
private int N;
private Estado E;
private long TiempoServicio;
// Para representar el reloj del tiempo de duracin del cliente en espera
//
private TimerTask timerEspera = new TimerTask() {
public void run() {
// Este cliente ya ha sido servido
//
E = Estado.Servido;
timerE.cancel();
// Se actualiza las estadsticas
//
Estadisticas.ClienteServido((double)TiempoServicio);
}
};
private Timer timerE;
public ClienteEspera(Cliente c, Servicio s, Taquilla t, int n) {
C = c; S = s; T = t; N = n; E = Estado.Espera;
}
public Cliente ObtCliente() { return C; }
public Servicio ObtServicio() { return S; }
public Taquilla ObtTaquilla() { return T; }
public int ObtNumeroAtencion() { return N; }
public Estado ObtEstado() { return E; }
public void Atender() {
E = Estado.Atendiendo;
timerE = new Timer();
TiempoServicio = 1000 * (new Random().nextInt(6) + 1);
355
VOLVER A MEN
timerE.scheduleAtFixedRate(timerEspera, 0, TiempoServicio);
}
}
private int Id;
private Taquilla []Taquillas;
protected GestorEstadisticas Estadisticas;
private int nCliente;
private ArrayList<ClienteEspera> ClientesEspera;
public Oficina(int id, int nT, int nS) {
Id = id;
if (nT <= 0) nT = 1;
Taquillas = new Taquilla[nT];
for (int i=0; i < nT; i++) {
Taquillas[i] = new Taquilla(i+1);
Taquillas[i].Habilitar();
}
Estadisticas = new GestorEstadisticas(nT, nS);
nCliente = 0;
ClientesEspera = new ArrayList<ClienteEspera>();
}
public int ObtId() {
return Id;
}
@Override
public String toString() {
return Integer.toString(Id);
}
356
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
}
}
}
// Este servicio debe ser dado por al menos una taquilla
//
if (!ServicioPrestado) return false;
}
return true;
}
public void NuevoClienteEspera(Cliente c, Servicio s) {
if (c == null || s == null) return;
// Se buscan las taquillas que ofrecen el servicio solicitado por el cliente
//
int nMenor, tMenor;
int T[] = new int[Taquillas.length];
ClienteEspera CE;
for (int i=0; i < Taquillas.length; i++) {
T[i] = (Taquillas[i].EstaHabilitada() && Taquillas[i].OfreceServicio(s.ObtNombre()) ? 0 : -1);
}
// Para todos los clientes actualmente en espera
// Hay que buscar la taquilla que ofrezca el servicio solicitado por el cliente
// con el menor nmero de clientes de la misma prioridad
//
for (Iterator<ClienteEspera> It = ClientesEspera.iterator(); It.hasNext(); ) {
CE = It.next();
if (CE.E != Estado.Servido && T[CE.T.Id - 1] >= 0 && T[CE.T.Id - 1] < CE.N)
T[CE.T.Id - 1] = CE.N;
}
359
VOLVER A MEN
nMenor = Integer.MAX_VALUE;
tMenor = -1;
for (int i=0; i < Taquillas.length; i++) {
if (T[i] >= 0) {
if (T[i] < nMenor) {
nMenor = T[i];
tMenor = i;
}
}
}
if (tMenor >= 0 && tMenor < Taquillas.length) {
CE = new ClienteEspera(c, s, Taquillas[tMenor], nMenor+1);
ClientesEspera.add(CE);
// Se actualizan las estadsticas
//
Estadisticas.AgregarClienteTaquilla(CE);
}
}
public void RevisarEstadoTaquillas() {
ClienteEspera CE, Menores[] = new ClienteEspera[Taquillas.length];
boolean TaquillaLibre[] = new boolean[Taquillas.length];
int T, c;
// Si no hay clientes en espera nada que hacer
//
if (ClientesEspera.isEmpty()) return;
// Para todas las taquillas de la oficina
//
for (T=0; T < Taquillas.length; T++) {
360
VOLVER A MEN
Menores[T] = null;
TaquillaLibre[T] = true;
}
for (c=0; c < ClientesEspera.size(); ) {
CE = ClientesEspera.get(c);
T = CE.ObtTaquilla().Id - 1;
if (CE.E == Estado.Atendiendo) {
// Si el cliente no ha sido servido an, la taquilla no est disponible
//
TaquillaLibre[T] = false;
c++;
}
else
if (CE.E == Estado.Servido) {
// Si el cliente ya fue servido se debe sacar de la cola
//
ClientesEspera.remove(CE);
}
else {
// Forma parte de la bsqueda de un nuevo cliente a ser atendido
//
if ((Menores[T] == null) ||
(CE.C.ObtPrioridad().compareTo(Menores[T].C.ObtPrioridad()) > 0) ||
(CE.C.ObtPrioridad().compareTo(Menores[T].C.ObtPrioridad()) > 0 &&
CE.N < Menores[T].N))
Menores[T] = CE;
c++;
}
}
361
VOLVER A MEN
VOLVER A MEN
El cdigo fuente relativo a C# aparece a continuacin y, al igual que los casos anteriores, no
se incluye el manejo de la interfaz grfica. De la misma manera como se hizo con Java, se
tiene un paquete (espacio de nombres) identificado como ManejadorColas y los siguientes
archivos fuente: ManejadorColas.cs, Servicio.cs, Cliente.cs y Oficina.cs.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.5
* ManejadorColas.cs
* Mauricio Paletta
*/
using System;
using System.Collections;
using System.Windows.Forms;
using System.Xml;
namespace ManejoColas
{
public class ManejadorColas
{
private static ArrayList Servicios = null;
363
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
if (O == null) return;
// Se revisa primero el estado de las taquillas
//
O.RevisarEstadoTaquillas();
// Comprobar si hay o no un cliente
// Hay un cliente, se decide su prioridad
//
if (Rnd.NextDouble() > 0.5) {
Cliente C;
PrioridadAtencion P;
doubleR = Rnd.NextDouble();
VOLVER A MEN
367
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
Oficina O;
XmlDocument XmlDoc = new XmlDocument();
XmlNodeList nList, nListS, nListT;
XmlElement Elemento;
XmlDoc.Load(NombreA);
nList = XmlDoc.GetElementsByTagName(ManejoColas);
if (nList != null)
{
// Primero se limpia cualquier dato existente
//
LimpiarDatos();
// Se cargan los servicios
//
nList = XmlDoc.GetElementsByTagName(Servicios);
if (nList != null)
{
nListS = nList.Item(0).ChildNodes;
for (i=0; i < nListS.Count; i++)
Elemento = (XmlElement)nListS[i];
AgregarServicio(Elemento.InnerText);
}
// Se agrega una oficina
//
Elemento = (XmlElement)XmlDoc.GetElementsByTagName(Oficina).Item(0);
nT = Convert.ToInt32(Elemento.GetAttribute(Taquillas));
AgregarOficina(1, nT, Servicios.Count);
O = BuscarOficina(1);
371
VOLVER A MEN
VOLVER A MEN
ElementoSo = xmlDoc.CreateElement(Servicio);
ElementoSo.AppendChild(xmlDoc.CreateTextNode(S.ObtNombre()));
ElementoS.AppendChild(ElementoSo);
}
}
// Se agrega la oficina
//
O = BuscarOficina(1);
if (O != null) {
ElementoO = xmlDoc.CreateElement(Oficina);
ElementoO.SetAttribute(Id, 1);
ElementoO.SetAttribute(Taquillas, Convert.ToString(O.ObtNumeroTaquillas()));
Elemento.AppendChild(ElementoO);
for (i=0; i < O.ObtNumeroTaquillas(); i++) {
ElementoT = xmlDoc.CreateElement(Taquilla);
ElementoT.SetAttribute(Id, Convert.ToString(i+1));
ElementoO.AppendChild(ElementoT);
for (j=0; j < O.ObtNumeroServiciosTaquilla(i); j++) {
Servicio S = O.ObtServicioTaquilla(i, j);
if (S != null) {
ElementoS = xmlDoc.CreateElement(Servicio);
ElementoS.AppendChild(xmlDoc.CreateTextNode(S.ObtNombre()));
ElementoT.AppendChild(ElementoS);
}
}
}
}
// Se escribe la data en el archivo XML
//
xmlDoc.Save(NombreA);
373
VOLVER A MEN
return true;
}
}
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.5
* Servicio.cs
* Mauricio Paletta
*/
using System;
namespace ManejoColas
{
// Representa un servicio
//
public class Servicio
{
private string Nombre;
public Servicio(string Str) {
Nombre = Str;
}
public string ObtNombre() {
return Nombre;
}
public override string ToString() {
return ObtNombre();
}
}
}
374
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.5
* Cliente.cs
* Mauricio Paletta
*/
using System;
namespace ManejoColas
{
public enum PrioridadAtencion {
Baja, Media, Alta
}
// Representa un cliente
//
public class Cliente
{
private PrioridadAtencion Prioridad;
private int Id;
public Cliente(int id, PrioridadAtencion p)
{
Id = id;
Prioridad = p;
}
public int ObtId() {
return Id;
}
public PrioridadAtencion ObtPrioridad() {
return Prioridad;
}
}
}
375
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.5
* Oficina.cs
* Mauricio Paletta
*/
using System;
using System.Collections;
namespace ManejoColas
{
// Representa una oficina
//
public class Oficina
{
// Representa un gestor de estadsticas x oficina
//
protected class GestorEstadisticas {
protected int TotalClientesOficina;
protected int []TotalClientesTaquilla;
protected int []TotalClientesServicio;
protected double PromedioAtencion, MinimoAtencion, MaximoAtencion;
public GestorEstadisticas(int N, int S) {
int i;
if (N <= 0) N = 1;
TotalClientesOficina = 0;
PromedioAtencion = MaximoAtencion = 0.0;
MinimoAtencion = Double.MaxValue;
TotalClientesTaquilla = new int[N];
TotalClientesServicio = new int[S];
for (i=0; i < N; i++)
376
VOLVER A MEN
TotalClientesTaquilla[i] = 0;
for (i=0; i < S; i++)
TotalClientesServicio[i] = 0;
}
public void AgregarClienteTaquilla(ClienteEspera CE) {
if (CE == null || CE.ObtTaquilla() == null || CE.ObtServicio() == null) return;
if (CE.ObtTaquilla().ObtId() <= 0 || CE.ObtTaquilla().ObtId() > TotalClientesTaquilla.Length)
return;
VOLVER A MEN
Convert.ToString(TotalClientesServicio[s]) + \n;
}
Promedio = TotalClientesOficina > 0 ? PromedioAtencion / TotalClientesOficina : 0.0;
Texto += Promedio de atencin: + Convert.ToString(Promedio) + \n;
Texto += Tiempo mnimo de atencin: + Convert.ToString(MinimoAtencion) + \n;
Texto += Tiempo mximo de atencin: + Convert.ToString(MaximoAtencion) + \n;
return Texto;
}
}
// Representa una taquilla de la oficina
//
public class Taquilla {
private int Id;
private ArrayList Servicios;
private bool Habilitada;
public Taquilla(int id) {
Id = id;
Servicios = new ArrayList();
Habilitada = true;
}
public int ObtId() {
return Id;
}
public override string ToString() {
return Convert.ToString(Id);
}
378
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
E = Estado.Atendiendo;
timerE.Interval = 1000 * (new Random().Next(1, 7));
timerE.Start();
}
}
private int Id;
private Taquilla []Taquillas;
protected GestorEstadisticas Estadisticas;
private int nCliente;
private ArrayList ClientesEspera;
public Oficina(int id, int nT, int nS) {
Id = id;
if (nT <= 0) nT = 1;
Taquillas = new Taquilla[nT];
for (int i=0; i < nT; i++) {
Taquillas[i] = new Taquilla(i+1);
Taquillas[i].Habilitar();
}
Estadisticas = new GestorEstadisticas(nT, nS);
nCliente = 0;
ClientesEspera = new ArrayList();
}
public int ObtId() {
return Id;
}
public override string ToString() {
return Convert.ToString(Id);
}
public int ObtNumeroTaquillas() {
382
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
}
}
// Este servicio debe ser dado por al menos una taquilla
//
if (!ServicioPrestado) return false;
}
return true;
}
public void NuevoClienteEspera(Cliente c, Servicio s) {
if (c == null || s == null) return;
// Se buscan las taquillas que ofrecen el servicio solicitado por el cliente
//
int nMenor, tMenor;
int []T = new int[Taquillas.Length];
ClienteEspera CE;
for (int i=0; i < Taquillas.Length; i++) {
T[i] = (Taquillas[i].EstaHabilitada() && Taquillas[i].OfreceServicio(s.ObtNombre()) ? 0 : -1);
}
// Para todos los clientes actualmente en espera
// Hay que buscar la taquilla que ofrezca el servicio solicitado por el cliente
// con el menor nmero de clientes de la misma prioridad
//
for (int i=0; i < ClientesEspera.Count; i++) {
CE = (ClienteEspera)ClientesEspera[i];
if (CE.ObtEstado() != Estado.Servido && T[CE.ObtTaquilla().ObtId() - 1] >= 0 &&
T[CE.ObtTaquilla().ObtId() - 1] < CE.ObtNumeroAtencion())
T[CE.ObtTaquilla().ObtId() - 1] = CE.ObtNumeroAtencion();
}
385
VOLVER A MEN
nMenor = int.MaxValue;
tMenor = -1;
for (int i=0; i < Taquillas.Length; i++) {
if (T[i] >= 0) {
if (T[i] < nMenor) {
nMenor = T[i];
tMenor = i;
}
}
}
if (tMenor >= 0 && tMenor < Taquillas.Length) {
CE = new ClienteEspera(c, s, Taquillas[tMenor], this, nMenor+1);
ClientesEspera.Add(CE);
// Se actualizan las estadsticas
//
Estadisticas.AgregarClienteTaquilla(CE);
}
}
public void RevisarEstadoTaquillas() {
ClienteEspera CE;
ClienteEspera []Menores = new ClienteEspera[Taquillas.Length];
bool []TaquillaLibre = new bool[Taquillas.Length];
int T, c;
// Si no hay clientes en espera nada que hacer
//
if (ClientesEspera.Count == 0) return;
// Para todas las taquillas de la oficina
//
for (T=0; T < Taquillas.Length; T++)
386
VOLVER A MEN
{
Menores[T] = null;
TaquillaLibre[T] = true;
}
for (c=0; c < ClientesEspera.Count; )
{
CE = (ClienteEspera)ClientesEspera[c];
T = CE.ObtTaquilla().ObtId() - 1;
if (CE.ObtEstado() == Estado.Atendiendo)
{
// Si el cliente no ha sido servido an, la taquilla no est disponible
//
TaquillaLibre[T] = false;
c++;
}
else
if (CE.ObtEstado() == Estado.Servido)
{
// Si el cliente ya fue servido se debe sacar de la cola
//
ClientesEspera.Remove(CE);
}
else
{
// Forma parte de la bsqueda de un nuevo cliente a ser atendido
//
if ((Menores[T] == null) ||
(CE.ObtCliente().ObtPrioridad().CompareTo(Menores[T].ObtCliente().ObtPrioridad()) >
0) ||
==
387
(CE.ObtCliente().ObtPrioridad().CompareTo(Menores[T].ObtCliente().ObtPrioridad())
VOLVER A MEN
Menores[T] = CE;
c++;
}
}
// Hacer las asignaciones de los clientes en las respectivas taquillas
//
for (T=0; T < Taquillas.Length; T++)
{
if (TaquillaLibre[T] && Menores[T] != null)
{
Menores[T].AsgEstado(Estado.Atendiendo);
Menores[T].Atender();
}
}
}
// Buscar el cliente que se est atendiendo actualmente en la taquilla
// indicada y retornar una cadena de caracteres con formato para actualizar
// la lista de estado de avance correspondiente
//
public string ClienteAtendidoTaquilla(Taquilla T) {
for (int i=0; i < ClientesEspera.Count; i++) {
ClienteEspera CE = (ClienteEspera)ClientesEspera[i];
if (CE.ObtTaquilla() == T && CE.ObtEstado() == Estado.Atendiendo)
return Convert.ToString(CE.ObtCliente().ObtId()) + ( +
Convert.ToString(CE.ObtNumeroAtencion()) + );
}
return ;
}
public string ClienteAtendidoTaquilla(int idxT) {
return idxT >= 0 && idxT < Taquillas.Length ? ClienteAtendidoTaquilla(Taquillas[idxT]) : ;
388
VOLVER A MEN
}
// Armar en una cadena de caracteres la cola de clientes asociados a un servicio
// de una taquilla especfica
//
public string ClientesEsperaTaquilla(Taquilla T, Servicio S) {
string Clientes = ;
for (int i=0; i < ClientesEspera.Count; i++) {
ClienteEspera CE = (ClienteEspera)ClientesEspera[i];
if (CE.ObtTaquilla() == T && CE.ObtEstado() != Estado.Atendiendo &&
CE.ObtServicio() == S)
Clientes = Clientes + Convert.ToString(CE.ObtCliente().ObtId()) +
( + Convert.ToString(CE.ObtNumeroAtencion()) + ) ;
}
return Clientes;
}
// Obtener las estadsticas en un formato texto
//
public string ObtEstadisticas() {
return Estadisticas.ToString();
}
public void ClienteServido(double TiempoServicio) {
Estadisticas.ClienteServido(TiempoServicio);
}
}
}
389
VOLVER A MEN
6.6.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): El anlisis del enunciado nos lleva
a un posible mapa mental como el que se muestra en la Figura 6.31.
390
VOLVER A MEN
Figura 6.32. Diagrama de casos de uso relativo al problema del generador de energa.
Figura 6.33. Diagrama no detallado de clases relativo al problema del generador de energa.
391
VOLVER A MEN
6.6.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): Se propone el uso de una iinterfaz grfica
con control manual. Las condiciones iniciales del sistema en cuanto a cantidad de agua,
combustible y temperatura inicial de la caldera sern tomadas al azar. Inicialmente el sistema
estar apagado (mechero y turbina apagados y vlvulas cerradas). Se asume que el agua y el
combustible se agregan en unidades de porcentaje.
Paso 2 (Detallar las clases): Al agregar los atributos y mtodos a las clases de la Figura 6.33
resulta el diagrama de clases detallado de la Figura 6.34.
Figura 6.34. Diagrama detallado de clases relativo al problema del generador de energa.
Paso 3 (Desarrollar los modelos de estado): La Figura 6.35 muestra los diagramas de estado
de cada una de las clases presentes en el modelo de este problema. En relacin a la clase
Generador energa, el cambio de estado est asociado al cambio de estado de cada uno de
sus tres componentes: LaCaldera, LaTurbina y ElMechero.
392
VOLVER A MEN
393
VOLVER A MEN
6.6.4 Programacin
A continuacin el cdigo fuente escrito en C++. Las clases estn definidas en el paquete
(espacio de nombres) GeneradorEnergia. Sin tomar en cuenta lo reativo a la interfaz se
tienen los archivos GeneradorEnergia.hpp y GeneradorEnergia.cpp.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.6
* GeneradorEnergia.hpp
* Mauricio Paletta
*/
#ifndef GENERADORENERGIA_HPP
#define GENERADORENERGIA_HPP
#include <time.h>
namespace GeneradorEnergia {
394
VOLVER A MEN
VOLVER A MEN
double ObtNivel() {
return Porcentaje;
}
};
// Representa un mechero o quemador
//
class Mechero {
private:
Deposito *DepositoCombustible;
bool Encendido;
time_t InicioEncendido;
public:
Mechero(double C=0.0) {
DepositoCombustible = new Deposito(C);
Encendido = false;
}
~Mechero() {
delete DepositoCombustible;
}
void Encender() { Encendido = true; time(&InicioEncendido); }
void Apagar() { Encendido = false; }
void AgregarCombustible(double C) {
DepositoCombustible->Agregar(C);
}
double ObtNivelCombustible() {
return DepositoCombustible->ObtNivel();
}
void RevisarCombustible();
bool EstaEncendido() { return Encendido; }
};
396
VOLVER A MEN
VOLVER A MEN
void Revisar();
bool ValvulaAguaAbierta() { return Agua.EstaAbierta(); }
bool ValvulaPresionAbierta() { return Presion.EstaAbierta(); }
};
// Representa una turbina
//
class Turbina {
private:
double RPM;
public:
Turbina() {
RPM = 0.0;
}
void Parar() { RPM = 0.0; }
void Acelerar(double rpm) { RPM += rpm; }
void Disminuir(double rpm) {
RPM -= rpm;
if (RPM < 0.0) Parar();
}
double ObtRPM() { return RPM; }
};
// Representa un generador de energa
//
class GeneradorEnergia {
private:
Caldera *LaCaldera;
Turbina *LaTurbina;
Mechero *ElMechero;
public:
398
VOLVER A MEN
VOLVER A MEN
return LaCaldera->ObtTemperatura();
}
bool EstaEncendido() { return ElMechero->EstaEncendido(); }
void Generar();
void AbrirPresion() { LaCaldera->AbrirValvulaPresion(); }
void CerrarPresion() { LaCaldera->CerrarValvulaPresion(); }
};
}
#endif /* GENERADORENERGIA_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.6
* GeneradorEnergia.cpp
* Mauricio Paletta
*/
#include <math.h>
#include GeneradorEnergia.hpp
namespace GeneradorEnergia {
void Mechero::RevisarCombustible() {
time_t TiempoActual;
double Consumido;
// Se asume un consumo de combustible equivalente a 0.33 unidades de % x segundo
//
time(&TiempoActual);
Consumido = 0.33 * difftime(TiempoActual, InicioEncendido);
DepositoCombustible->Consumir(Consumido);
400
VOLVER A MEN
VOLVER A MEN
ElMechero->RevisarCombustible();
LaCaldera->Revisar();
// La aceleracin / disminucin de velocidad de la turbina depende de las
// condiciones de la caldera
// Se estima a 1 RPM cada 1/3 segundos
//
if (LaCaldera->ObtTemperatura() >= 100.0 && LaCaldera->ValvulaPresionAbierta())
LaTurbina->Acelerar(1.0);
else
LaTurbina->Disminuir(1.0);
}
}
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.6
* Turbina.java
* Mauricio Paletta
*/
package GeneradorEnergia;
public class Turbina {
private double RPM;
public Turbina() { RPM = 0.0; }
public void Parar() { RPM = 0.0; }
public void Acelerar(double rpm) { RPM += rpm; }
public void Disminuir(double rpm) {
RPM -= rpm;
if (RPM < 0.0) Parar();
}
public double ObtRPM() { return RPM; }
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.6
* Deposito.java
* Mauricio Paletta
*/
package GeneradorEnergia;
public class Deposito {
private double Porcentaje;
public Deposito(double C) {
if (C > 100.0) C = 100.0;
403
VOLVER A MEN
Porcentaje = C;
}
public void Agregar(double C) {
Porcentaje += C;
if (Porcentaje > 100.0) Porcentaje = 100.0;
}
public void Consumir(double C) {
Porcentaje -= C;
if (Porcentaje < 0.0) Porcentaje = 0.0;
}
public double ObtNivel() { return Porcentaje; }
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.6
* Mechero.java
* Mauricio Paletta
*/
package GeneradorEnergia;
import java.util.Calendar;
import java.util.Date;
public class Mechero {
private Deposito DepositoCombustible;
private boolean Encendido;
private Date InicioEncendido;
public Mechero(double C) {
DepositoCombustible = new Deposito(C);
Encendido = false;
}
404
VOLVER A MEN
VOLVER A MEN
import java.util.Date;
public class Caldera {
private Deposito DepositoAgua;
private Valvula Agua, Presion;
private double Temperatura;
private long CambioTemperatrura, TiempoEbullicion;
public Caldera(double A, double T) {
DepositoAgua = new Deposito(A);
Agua = new Valvula();
Presion = new Valvula();
Temperatura = T;
CambioTemperatrura = TiempoEbullicion = 0;
}
public void AgregarAgua(double A) {
Agua.Abrir();
DepositoAgua.Agregar(A);
Agua.Cerrar();
}
public void AbrirValvulaPresion() {
Presion.Abrir();
}
public void CerrarValvulaPresion() {
Presion.Cerrar();
}
public double ObtNivelAgua() {
return DepositoAgua.ObtNivel();
}
public double ObtTemperatura() { return Temperatura; }
public void Revisar() {
Date Aux = Calendar.getInstance().getTime();
long TiempoActual = Aux.getTime();
406
VOLVER A MEN
if (CambioTemperatrura == 0) {
CambioTemperatrura = TiempoActual;
return;
}
// La temperatura aumenta exponencialmente hasta alcanzar el nivel de ebullicin
// Mientras menos agua ms rpido el calentamiento
//
if (Temperatura < 100.0)
Temperatura += Math.exp((TiempoActual - CambioTemperatrura) / 1000) /
DepositoAgua.ObtNivel();
// Se asume el consumo de agua de la caldera dependiendo si la vlvula de
// presin est abierta y se ha llegado a la temperatura de ebullicin
// En ese caso se consumen 3 unidades de % x segundo
//
if (Temperatura >= 100.0 && Presion.EstaAbierta()) {
if (TiempoEbullicion == 0) {
TiempoEbullicion = TiempoActual;
return;
}
DepositoAgua.Consumir(3.0 * (TiempoActual - TiempoEbullicion) / 1000);
}
}
public boolean ValvulaAguaAbierta() { return Agua.EstaAbierta(); }
public boolean ValvulaPresionAbierta() { return Presion.EstaAbierta(); }
}
407
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.6
* GeneradorEnergia.java
* Mauricio Paletta
*/
package GeneradorEnergia;
public class GeneradorEnergia {
private Caldera LaCaldera;
private Turbina LaTurbina;
private Mechero ElMechero;
public GeneradorEnergia(double C, double A, double T) {
LaCaldera = new Caldera(A, T);
LaTurbina = new Turbina();
ElMechero = new Mechero(C);
}
public void Encender() { ElMechero.Encender(); }
public void Apagar() {
ElMechero.Apagar();
LaCaldera.CerrarValvulaPresion();
}
public void AgregarCombustible(double C) {
ElMechero.AgregarCombustible(C);
}
public void AgregarAgua(double A) {
LaCaldera.AgregarAgua(A);
}
public double ObtNivelAgua() {
return LaCaldera.ObtNivelAgua();
}
public double ObtNivelCombustible() {
408
VOLVER A MEN
return ElMechero.ObtNivelCombustible();
}
public double ObtRPM() {
return LaTurbina.ObtRPM();
}
public double ObtTemperatura() {
return LaCaldera.ObtTemperatura();
}
public boolean EstaEncendido() { return ElMechero.EstaEncendido(); }
public void Generar() {
ElMechero.RevisarCombustible();
LaCaldera.Revisar();
// La aceleracin / disminucin de velocidad de la turbina depende de las
// condiciones de la caldera
// Se estima a 1 RPM cada 1/3 segundos
//
if (LaCaldera.ObtTemperatura() >= 100.0 && LaCaldera.ValvulaPresionAbierta())
LaTurbina.Acelerar(1.0);
else
LaTurbina.Disminuir(1.0);
}
public void AbrirPresion() { LaCaldera.AbrirValvulaPresion(); }
public void CerrarPresion() { LaCaldera.CerrarValvulaPresion(); }
}
En relacin a C# se tiene el siguiente cdigo fuente. Al igual que en C++ y en Java, todas
las clases involucradas en el problema estn definidas en el paquete o espacio de nombres
GeneradorEnergia.
409
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C#; caso prctico Seccin 6.6
* GeneradorEnergia.cs
* Mauricio Paletta
*/
using System;
namespace GeneradorEnergia
{
public class Valvula
{
private bool Abierta;
public Valvula() { Abierta = false; }
public void Abrir() { Abierta = true; }
public void Cerrar() { Abierta = false; }
public bool EstaAbierta() { return Abierta; }
}
public class Turbina
{
private double RPM;
public Turbina() { RPM = 0.0; }
public void Parar() { RPM = 0.0; }
public void Acelerar(double rpm) { RPM += rpm; }
public void Disminuir(double rpm) {
RPM -= rpm;
if (RPM < 0.0) Parar();
}
public double ObtRPM() { return RPM; }
}
410
VOLVER A MEN
VOLVER A MEN
InicioEncendido = DateTime.Now;
}
public void Apagar() { Encendido = false; }
public void AgregarCombustible(double C)
{
DepositoCombustible.Agregar(C);
}
public double ObtNivelCombustible()
{
return DepositoCombustible.ObtNivel();
}
public void RevisarCombustible()
{
DateTime TiempoActual = DateTime.Now;
double Consumido;
// Se asume un consumo de combustible equivalente a 0.33 unidades de % x segundo
//
Consumido = 0.33 * TiempoActual.Subtract(InicioEncendido).Milliseconds / 1000;
DepositoCombustible.Consumir(Consumido);
if (DepositoCombustible.ObtNivel() <= 0.0) Apagar();
}
public bool EstaEncendido() { return Encendido; }
}
public class Caldera {
private Deposito DepositoAgua;
private Valvula Agua, Presion;
private double Temperatura;
private long CambioTemperatrura, TiempoEbullicion;
public Caldera(double A, double T)
{
412
VOLVER A MEN
VOLVER A MEN
return;
}
// La temperatura aumenta exponencialmente hasta alcanzar el nivel de ebullicin
// Mientras menos agua ms rpido el calentamiento
//
if (Temperatura < 100.0)
Temperatura += Math.Exp((TiempoActual - CambioTemperatrura) / 1000) /
DepositoAgua.ObtNivel();
// Se asume el consumo de agua de la caldera dependiendo si la vlvula de
// presin est abierta y se ha llegado a la temperatura de ebullicin
// En ese caso se consumen 3 unidades de % x segundo
//
if (Temperatura >= 100.0 && Presion.EstaAbierta())
{
if (TiempoEbullicion == 0)
{
TiempoEbullicion = TiempoActual;
return;
}
DepositoAgua.Consumir(3.0 * (TiempoActual - TiempoEbullicion) / 1000);
}
}
public bool ValvulaAguaAbierta() { return Agua.EstaAbierta(); }
public bool ValvulaPresionAbierta() { return Presion.EstaAbierta(); }
}
public class GeneradorEnergia
{
private Caldera LaCaldera;
private Turbina LaTurbina;
private Mechero ElMechero;
414
VOLVER A MEN
VOLVER A MEN
{
return LaCaldera.ObtTemperatura();
}
public bool EstaEncendido() { return ElMechero.EstaEncendido(); }
public void Generar()
{
ElMechero.RevisarCombustible();
LaCaldera.Revisar();
// La aceleracin / disminucin de velocidad de la turbina depende de las
// condiciones de la caldera
// Se estima a 1 RPM cada 1/3 segundos
//
if (LaCaldera.ObtTemperatura() >= 100.0 && LaCaldera.ValvulaPresionAbierta())
LaTurbina.Acelerar(1.0);
else
LaTurbina.Disminuir(1.0);
}
public void AbrirPresion() { LaCaldera.AbrirValvulaPresion(); }
public void CerrarPresion() { LaCaldera.CerrarValvulaPresion(); }
}
}
VOLVER A MEN
agua y otros lquidos necesarios para ir realizando la mezcla. Una vez que la masa est
concluida, una ltima vlvula deja caer la mezcla a un molde que a su vez va dejando caer la
preparacin moldeada a una correa transportadora que mueve el producto crudo a un horno
para su coccin. Al terminar la coccin esta misma correa trasporta el producto terminado hacia
su proceso de reposo y posterior almacenamiento. Para que el proceso se haga correctamente
se deben realizar tres controles: sobre la frmula, sobre el amasado de la mezcla y sobre el
horneado. La Figura 6.38 presenta un diagrama esquemtico de la fbrica de galletas.
6.7.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): La Figura 6.39 presenta un mapa
mental relativo al enunciado del problema.
417
VOLVER A MEN
Paso 2 (Identificar actores / nombres): Se tiene la siguiente lista de nombres: Fbrica, galleta,
frmula, ingrediente, cantidad, peso, tiempo de amasado, tiempo de horneado, depsito,
harina, azcar, avena, sal, vlvula, canal, balanza, agua, mezcla, molde, depsito, correa
transportadora, producto, horno y coccin.
Paso 3 (Identificar procesos / requerimientos): Debe haber un ente ya sea humano o
automatizado que realice el control de la fabricacin de las galletas el cual, como se mencion
en el enunciado, est asociado a tres partes del proceso: frmula, amasado y horneado. Ntese
que se ve conveniente para este problema representar tambin un actor que recibe las galletas
fabricadas y que puede representar un depsito de almacenamiento o almacn. El diagrama
de casos de uso correspondiente se muestra en la Figura 6.40.
Se proponen las siguientes clases: Fbrica, frmula, ingrediente, vlvula, balanza, depsito
y horno. En este sentido, se tiene el diagrama no detallado de clases que se muestra en la
Figura 6.41.
418
VOLVER A MEN
6.6.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): Para este problema se usar una interfaz grfica
que permite mostrar la simulacin del control de la fbrica de galletas. La implementacin que se
muestra no tomar en cuenta la administracin de las frmulas las cuales sern representadas
en formato XML haciendo uso de la estructura que se muestra a continuacin.
<?xml version=1.0?>
<Frmula Nombre=un nombre Amasado=tiempo Horneado=tiempo Temperatura=grados>
</Frmula>
Paso 2 (Detallar las clases): Al agregar los atributos y mtodos a las clases de la Figura 6.41
resulta el diagrama de clases detallado de la Figura 6.42.
419
VOLVER A MEN
Paso 3 (Desarrollar los modelos de estado): La Figura 6.43 muestra los diagramas de estado de
cada una de la mayora de las clases presentes en el modelo de este problema. No se incluye
la clase Vlvula por ser similar al del problema anterior (ver diagrama de estado en la Figura
6.35). Se omite la clase Fbrica por trener un diagrama extenso y depender sus estados de
los diferentes objetos de otras clases que forman parte de la fbrica: balanza, horno, depsito
y vlvulas. Ntese que los cambios de estado asociados al agregar / suprimir frmulas para la
clase Fbrica se representan de manera similar como se hace con el diagrama de estados de
la clase Frmula al agregar / suprimir ingredientes y que se muestra en la Figura 6.42.
420
VOLVER A MEN
421
VOLVER A MEN
422
VOLVER A MEN
6.7.4 Programacin
Para el cdigo fuente correspondiente al lenguaje de programacin C++, todas las clases se
definieron en el archivo FabricaGalletas.hpp y parte de la definicin de los mtodos outline
estn en el archivo FabricaGalletas.cpp. A continuacin el contenido de estos archivos.
Ntese que se incorporaron otras clases adicionales a las identificadas en el diagrama de la
Figura 6.42. Estas clases se agregaron por comodidad para combinar un Depsito con una
Vlvula por ejemplo.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.7
* FabricaGalletas.hpp
* Mauricio Paletta
*/
#ifndef FABRICAGALLETAS_HPP
#define FABRICAGALLETAS_HPP
#include <string>
#include <vector>
using namespace std;
class Balanza {
private:
double Peso;
public:
Balanza() { Peso = 0.0; }
void AgregarMasa(double M) { Peso += M; }
double ObtPeso() { return Peso; }
void Normalizar() { Peso = 0.0; }
};
class Deposito {
423
VOLVER A MEN
private:
double Capacidad;
double NivelActual;
string Contenido;
public:
Deposito(double C) {
Capacidad = C; NivelActual = 0.0;
}
void Agregar(double C) {
NivelActual += C;
if (NivelActual > Capacidad) NivelActual = Capacidad;
}
bool Consumir(double C) {
if (C > NivelActual) return false;
NivelActual -= C;
return true;
}
bool Vacio() { return NivelActual == 0.0; }
bool Lleno() { return NivelActual == Capacidad; }
string ObtContenido() { return Contenido; }
void AsgContenido(string N) { Contenido = N; }
double ObtNivelActual() { return NivelActual; }
};
class Valvula {
private:
bool Abierta;
public:
Valvula() { Abierta = false; }
void Abrir() { Abierta = true; }
void Cerrar() { Abierta = false; }
424
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
}
int ObtNumeroIngredientes() { return Ingredientes.size(); }
};
typedef Formula *pFormula;
// Estados de la fabricacin
//
enum Etapas { Pesado, Amasado, Moldeado, Horneado };
// Permite representar un depsito para almacenar los
// diferentes ingredientes a usar en las frmulas
// Se asume una capacidad de 100 y lleno del ingrediente
//
class DepositoIngrediente : public Deposito {
public:
Valvula *V;
DepositoIngrediente() : Deposito(100) {
V = new Valvula();
Deposito::Agregar(100);
}
~DepositoIngrediente() { delete V; }
bool Consumir(double C) {
bool Ret;
V->Abrir();
Ret = Deposito::Consumir(C);
V->Cerrar();
return Ret;
}
};
typedef DepositoIngrediente *pDepositoIngrediente;
427
VOLVER A MEN
428
VOLVER A MEN
void AgregarAgua() {
VAgua->Abrir();
// ...
VAgua->Cerrar();
}
void AgregarOtrosLiquidos() {
VOtros->Abrir();
// ...
VOtros->Cerrar();
}
void VaciarAlMolde() {
VMolde->Abrir();
// ...
VMolde->Cerrar();
}
};
typedef DepositoTemporal *pDepositoTemporal;
class FabricaGalletas {
private:
vector<pFormula> Formulas;
vector<pDepositoIngrediente> Ingredientes;
pBalanzaRegulada LaBalanza;
pDepositoTemporal ElAmasador;
Horno *ElHorno;
pDepositoIngrediente BuscarIngrediente(string N);
public:
FabricaGalletas() {
LaBalanza = new BalanzaRegulada();
ElAmasador = new DepositoTemporal();
ElHorno = new Horno();
429
VOLVER A MEN
}
~FabricaGalletas();
bool AgregarFormula(pFormula Frm);
bool SuprimirFormula(Formula Frm);
bool SuprimirFormula(string Frm);
void SuprimirFormulas();
pFormula ObtFormula(int Idx) {
if (Idx < 0 || (unsigned)Idx >= Formulas.size())
return NULL;
return Formulas[Idx];
}
bool AgregarIngrediente(string N);
bool SuprimirIngrediente(string N);
void ConsumirIngrediente(string N, double C) {
pDepositoIngrediente D = BuscarIngrediente(N);
if (D == NULL) return;
D->Consumir(C);
}
void AgregarIngrediente(string N, double C) {
pDepositoIngrediente D = BuscarIngrediente(N);
if (D == NULL) return;
D->Agregar(C);
}
double ObtDisponibilidadIngrediente(string N) {
pDepositoIngrediente D = BuscarIngrediente(N);
if (D == NULL) return 0.0;
return D->ObtNivelActual();
}
double ObtPesoBalanza() {
430
VOLVER A MEN
return LaBalanza->ObtPeso();
}
void AgregarMasaBalanza(double M) {
LaBalanza->AgregarMasa(M);
}
void NormalizarBalanza() {
LaBalanza->Normalizar();
}
void AgregarIngredienteAmasador(double I) {
ElAmasador->Agregar(I);
}
void AsgTemperaturaHorno(double G) {
ElHorno->AsgTemperatura(G);
}
void AgregarAgua() { ElAmasador->AgregarAgua(); }
void AgregarOtrosLiquidos() { ElAmasador->AgregarOtrosLiquidos(); }
void Moldear() { ElAmasador->VaciarAlMolde(); }
};
#endif /* FABRICAGALLETAS_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.7
* FabricaGalletas.cpp
* Mauricio Paletta
*/
#include FabricaGalletas.hpp
Formula::~Formula() {
for(vector<pIngredienteFormula>::iterator It=Ingredientes.begin(); It != Ingredientes.end(); It++) {
431
VOLVER A MEN
pIngredienteFormula I = (pIngredienteFormula)*It;
if (I != NULL) delete I;
}
Ingredientes.clear();
}
pIngredienteFormula Formula::BuscarIngrediente(string N) {
pIngredienteFormula I;
for (unsigned i=0; i < Ingredientes.size(); i++) {
I = Ingredientes[i];
if (I->ObtNombre() == N) return I;
}
return NULL;
}
bool Formula::AgregarIngrediente(string N, double P) {
// Se verifica que el ingrediente no est repetido
//
pIngredienteFormula I = BuscarIngrediente(N);
if (I != NULL) return false;
Ingredientes.push_back(new IngredienteFormula(N, P));
return true;
}
bool Formula::SuprimirIngrediente(string N) {
pIngredienteFormula I;
for (unsigned i=0; i < Ingredientes.size(); i++) {
I = Ingredientes[i];
if (I->ObtNombre() == N) {
Ingredientes.erase(Ingredientes.begin() + i);
return true;
}
}
432
VOLVER A MEN
return false;
}
FabricaGalletas::~FabricaGalletas() {
delete LaBalanza;
delete ElAmasador;
delete ElHorno;
for(vector<pDepositoIngrediente>::iterator It=Ingredientes.begin(); It != Ingredientes.end(); It++) {
pDepositoIngrediente I = (pDepositoIngrediente)*It;
if (I != NULL) delete I;
}
Ingredientes.clear();
SuprimirFormulas();
}
pDepositoIngrediente FabricaGalletas::BuscarIngrediente(string N) {
pDepositoIngrediente D;
for (unsigned i=0; i < Ingredientes.size(); i++) {
D = Ingredientes[i];
if (D->ObtContenido() == N) return D;
}
return NULL;
}
bool FabricaGalletas::AgregarFormula(pFormula Frm) {
// Se revisa primero si no existe una frmula con ese nombre
//
for (unsigned i=0; i < Formulas.size(); i++) {
pFormula F = Formulas[i];
if (F == Frm || F->ObtNombre() == Frm->ObtNombre()) return false;
}
Formulas.push_back(Frm);
return true;
433
VOLVER A MEN
}
bool FabricaGalletas::SuprimirFormula(Formula Frm) {
for (unsigned i=0; i < Formulas.size(); i++) {
pFormula F = Formulas[i];
if (F->ObtNombre() == Frm.ObtNombre()) {
Formulas.erase(Formulas.begin() + i);
return true;
}
}
return false;
}
bool FabricaGalletas::SuprimirFormula(string Frm) {
for (unsigned i=0; i < Formulas.size(); i++) {
pFormula F = Formulas[i];
if (F->ObtNombre() == Frm) {
Formulas.erase(Formulas.begin() + i);
return true;
}
}
return false;
}
void FabricaGalletas::SuprimirFormulas() {
for (vector<pFormula>::iterator It=Formulas.begin(); It != Formulas.end(); It++) {
pFormula F = (pFormula)*It;
if (F != NULL) delete F;
}
Formulas.clear();
}
bool FabricaGalletas::AgregarIngrediente(string N) {
434
VOLVER A MEN
VOLVER A MEN
package FabricaGalletas;
public class Balanza {
private double Peso;
public Balanza() { Peso = 0.0; }
public void AgregarMasa(double M) { Peso += M; }
public double ObtPeso() { return Peso; }
public void Normalizar() { Peso = 0.0; }
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.7
* Deposito.java
* Mauricio Paletta
*/
package FabricaGalletas;
public class Deposito {
private double Capacidad;
private double NivelActual;
private String Contenido;
public Deposito(double C) {
Capacidad = C; NivelActual = 0.0;
}
public void Agregar(double C) {
NivelActual += C;
if (NivelActual > Capacidad) NivelActual = Capacidad;
}
public boolean Consumir(double C) {
if (C > NivelActual) return false;
NivelActual -= C;
436
VOLVER A MEN
return true;
}
public boolean Vacio() { return NivelActual == 0.0; }
public boolean Lleno() { return NivelActual == Capacidad; }
public String ObtContenido() { return Contenido; }
public void AsgContenido(String N) { Contenido = N; }
public double ObtNivelActual() { return NivelActual; }
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.7
* Horno.java
* Mauricio Paletta
*/
package FabricaGalletas;
public class Horno {
private double Temperatura;
public Horno() { Temperatura = 0.0; }
public double ObtTemperatura() { return Temperatura; }
public void AsgTemperatura(double T) {
if (T < 1000.0 && T >= 0.0) Temperatura = T;
}
public boolean Encendido() { return Temperatura > 0.0; }
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.7
* Valvula.java
* Mauricio Paletta
*/
437
VOLVER A MEN
package FabricaGalletas;
public class Valvula {
private boolean Abierta;
public Valvula() { Abierta = false; }
public void Abrir() { Abierta = true; }
public void Cerrar() { Abierta = false; }
public boolean EstaAbierta() { return Abierta; }
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.7
* Ingrediente.java
* Mauricio Paletta
*/
package FabricaGalletas;
public class Ingrediente {
private String Nombre;
public Ingrediente(String N) { Nombre = N; }
public String ObtNombre() { return Nombre; }
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.7
* Formula.java
* Mauricio Paletta
*/
package FabricaGalletas;
438
VOLVER A MEN
import java.util.ArrayList;
public class Formula {
class IngredienteFormula extends Ingrediente {
private double Peso;
public IngredienteFormula(String N, double P) {
super(N);
Peso = P;
}
public double ObtPeso() { return Peso; }
}
private String Nombre;
private ArrayList<IngredienteFormula> Ingredientes;
private int TpoAmasado, TpoHorneado;
private double Grados;
public Formula(String N, int TA, int TH, double Gr) {
Ingredientes = new ArrayList<IngredienteFormula>();
Nombre = N; TpoAmasado = TA; TpoHorneado = TH; Grados = Gr;
}
public String ObtNombre() { return Nombre; }
public int ObtTpoAmasado() { return TpoAmasado; }
public int ObtTpoHorneado() { return TpoHorneado; }
public double ObtTemperatura() { return Grados; }
private IngredienteFormula BuscarIngrediente(String N) {
IngredienteFormula I;
for (int i=0; i < Ingredientes.size(); i++) {
I = Ingredientes.get(i);
if (I.ObtNombre().compareTo(N) == 0) return I;
}
439
VOLVER A MEN
return null;
}
public boolean AgregarIngrediente(String N, double P) {
// Se verifica que el ingrediente no est repetido
//
IngredienteFormula I = BuscarIngrediente(N);
if (I != null) return false;
Ingredientes.add(new IngredienteFormula(N, P));
return true;
}
public boolean SuprimirIngrediente(String N) {
IngredienteFormula I = BuscarIngrediente(N);
if (I != null) {
Ingredientes.remove(I);
return true;
}
return false;
}
public double ObtPesoIngrediente(String N) {
IngredienteFormula I = BuscarIngrediente(N);
if (I != null) return I.ObtPeso();
return 0.0;
}
public Ingrediente ObtIngrediente(int Idx) {
if (Idx >= 0 && Idx < Ingredientes.size())
return (Ingrediente)Ingredientes.get(Idx);
return null;
}
public int ObtNumeroIngredientes() { return Ingredientes.size(); }
}
440
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.7
* Fabrica.java
* Mauricio Paletta
*/
package FabricaGalletas;
import java.util.ArrayList;
public class Fabrica {
// Estados de la fabricacin
//
public enum Etapas { Pesado, Amasado, Moldeado, Horneado }
// Permite representar un depsito para almacenar los
// diferentes ingredientes a usar en las frmulas
// Se asume una capacidad de 100 y lleno del ingrediente
//
class DepositoIngrediente extends Deposito {
public Valvula V;
public DepositoIngrediente() {
super(100);
V = new Valvula();
super.Agregar(100);
}
public boolean Consumir(double C) {
boolean Ret;
V.Abrir();
Ret = super.Consumir(C);
V.Cerrar();
return Ret;
}
441
VOLVER A MEN
}
class BalanzaRegulada extends Balanza {
public Valvula V;
public BalanzaRegulada() {
super();
V = new Valvula();
}
public void Normalizar() {
V.Abrir();
super.Normalizar();
V.Cerrar();
}
}
class DepositoTemporal extends Deposito {
public Valvula VIngrediente, VAgua, VOtros, VMolde;
public DepositoTemporal() {
super(1000);
VIngrediente = new Valvula();
VAgua = new Valvula();
VOtros = new Valvula();
VMolde = new Valvula();
}
public void AgregarAgua() {
VAgua.Abrir();
// ...
VAgua.Cerrar();
}
442
VOLVER A MEN
VOLVER A MEN
return true;
}
public boolean SuprimirFormula(Formula Frm) {
for (int i=0; i < Formulas.size(); i++) {
Formula F = Formulas.get(i);
if (F == Frm) {
Formulas.remove(Frm);
return true;
}
}
return false;
}
public boolean SuprimirFormula(String Frm) {
for (int i=0; i < Formulas.size(); i++) {
Formula F = Formulas.get(i);
if (F.ObtNombre().compareTo(Frm) == 0) {
Formulas.remove(F);
return true;
}
}
return false;
}
public void SuprimirFormulas() {
Formulas.clear();
}
public Formula ObtFormula(int Idx) {
if (Idx < 0 || Idx >= Formulas.size())
return null;
return Formulas.get(Idx);
}
private DepositoIngrediente BuscarIngrediente(String N) {
DepositoIngrediente D;
444
VOLVER A MEN
VOLVER A MEN
D.Agregar(C);
}
public double ObtDisponibilidadIngrediente(String N) {
DepositoIngrediente D = BuscarIngrediente(N);
if (D == null) return 0.0;
return D.ObtNivelActual();
}
public double ObtPesoBalanza() {
return LaBalanza.ObtPeso();
}
public void AgregarMasaBalanza(double M) {
LaBalanza.AgregarMasa(M);
}
public void NormalizarBalanza() {
LaBalanza.Normalizar();
}
public void AgregarIngredienteAmasador(double I) {
ElAmasador.Agregar(I);
}
public void AsgTemperaturaHorno(double G) {
ElHorno.AsgTemperatura(G);
}
public void AgregarAgua() { ElAmasador.AgregarAgua(); }
public void AgregarOtrosLiquidos() { ElAmasador.AgregarOtrosLiquidos(); }
public void Moldear() { ElAmasador.VaciarAlMolde(); }
}
A continuacin el cdigo fuente relativo al lenguaje de programacin C#. Todas las clases involucradas
en el problema estn definidas en el paquete o espacio de nombres identificado como FabricaGalletas.
446
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C#; caso prctico Seccin 6.7
* FabricaGalletas.cs
* Mauricio Paletta
*/
using System;
using System.Collections.Generic;
namespace FabricaGalletas
{
public class Valvula
{
private bool Abierta;
public Valvula() { Abierta = false; }
public void Abrir() { Abierta = true; }
public void Cerrar() { Abierta = false; }
public bool EstaAbierta() { return Abierta; }
}
public class Deposito
{
private double Capacidad;
private double NivelActual;
private string Contenido;
public Deposito(double C)
{
Capacidad = C; NivelActual = 0.0;
}
public void Agregar(double C)
{
447
VOLVER A MEN
NivelActual += C;
if (NivelActual > Capacidad) NivelActual = Capacidad;
}
public bool Consumir(double C)
{
if (C > NivelActual) return false;
NivelActual -= C;
return true;
}
public bool Vacio() { return NivelActual == 0.0; }
public bool Lleno() { return NivelActual == Capacidad; }
public string ObtContenido() { return Contenido; }
public void AsgContenido(string N) { Contenido = N; }
public string ElContenido
{
get { return ObtContenido(); }
set { AsgContenido(value); }
}
public double ObtNivelActual() { return NivelActual; }
}
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
//
class DepositoIngrediente : Deposito
{
public Valvula V;
public DepositoIngrediente()
: base(100)
{
V = new Valvula();
base.Agregar(100);
}
public new bool Consumir(double C)
{
bool Ret;
V.Abrir();
Ret = base.Consumir(C);
V.Cerrar();
return Ret;
}
}
class BalanzaRegulada : Balanza
{
public Valvula V;
public BalanzaRegulada()
: base()
{
V = new Valvula();
}
public new void Normalizar()
{
453
VOLVER A MEN
V.Abrir();
base.Normalizar();
V.Cerrar();
}
}
class DepositoTemporal : Deposito
{
public Valvula VIngrediente, VAgua, VOtros, VMolde;
public DepositoTemporal()
: base(1000)
{
VIngrediente = new Valvula();
VAgua = new Valvula();
VOtros = new Valvula();
VMolde = new Valvula();
}
public void AgregarAgua()
{
VAgua.Abrir();
// ...
VAgua.Cerrar();
}
public void AgregarOtrosLiquidos()
{
VOtros.Abrir();
// ...
VOtros.Cerrar();
}
public void VaciarAlMolde()
{
454
VOLVER A MEN
VMolde.Abrir();
// ...
VMolde.Cerrar();
}
}
private List<Formula> Formulas;
private List<DepositoIngrediente> Ingredientes;
private BalanzaRegulada LaBalanza;
private DepositoTemporal ElAmasador;
private Horno ElHorno;
public Fabrica()
{
Formulas = new List<Formula>();
Ingredientes = new List<DepositoIngrediente>();
LaBalanza = new BalanzaRegulada();
ElAmasador = new DepositoTemporal();
ElHorno = new Horno();
}
public bool AgregarFormula(Formula Frm)
{
// Se revisa primero si no existe una frmula con ese nombre
//
for (int i=0; i < Formulas.Count; i++)
{
Formula F = Formulas[i];
if (F == Frm || F.ElNombre == Frm.ElNombre) return false;
}
Formulas.Add(Frm);
return true;
}
455
VOLVER A MEN
VOLVER A MEN
return null;
return Formulas[Idx];
}
private DepositoIngrediente BuscarIngrediente(string N)
{
DepositoIngrediente D;
for (int i=0; i < Ingredientes.Count; i++)
{
D = Ingredientes[i];
if (D.ElContenido == N) return D;
}
return null;
}
public bool AgregarIngrediente(string N)
{
// Se revisa primero si no existe ya un ingrediente con ese nombre
//
DepositoIngrediente D = BuscarIngrediente(N);
if (D != null) return false;
D = new DepositoIngrediente();
D.ElContenido = N;
Ingredientes.Add(D);
return true;
}
public bool SuprimirIngrediente(string N)
{
DepositoIngrediente D = BuscarIngrediente(N);
if (D == null) return false;
Ingredientes.Remove(D);
return true;
}
457
VOLVER A MEN
VOLVER A MEN
ElAmasador.Agregar(I);
}
public void AsgTemperaturaHorno(double G) { ElHorno.LaTemperatura = G; }
public void AgregarAgua() { ElAmasador.AgregarAgua(); }
public void AgregarOtrosLiquidos() { ElAmasador.AgregarOtrosLiquidos(); }
public void Moldear() { ElAmasador.VaciarAlMolde(); }
}
}
459
VOLVER A MEN
VOLVER A MEN
8. Asignar una peticin previamente agregada. Esto slo es posible si el recurso tiene
una instancia disponible; est claro que al hacer la asignacin del recurso al proceso la
peticin desaparece.
9. Liberar un recurso previamente asignado a un proceso.
10. Guardar en un archivo el GAR actual; el nombre del archivo debe ser dado.
11. Dado el nombre de un archivo, cargar en memoria el GAR que ste contiene.
c) La herramienta debe mostrar en cada momento el estado actual del GAR.
6.8.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): Se tiene un posible mapa mental
del problema segn se muestra en la Figura 6.47.
Figura 6.47. Mapa mental relativo al problema del grafo de asignacin de recursos.
Paso 2 (Identificar actores / nombres): Se tiene la siguiente lista de nombres: Tcnica, estado,
recurso, memoria, CPU, dispositivo I/O, proceso, programa, hilo de ejecucin, sistema operativo,
entorno, GAR, mecanismo, lazo mortal, grafo, crculo, cuadrado, nodo, punto, instancia, puerto
USB, arista, peticin y asignacin.
Paso 3 (Identificar procesos / requerimientos): La herramienta automatizada al cual se refiere
este problema es utilizada por un usuario quien es actor de la misma. Por otro lado se pide
que la herramienta permita crear un archivo con la data asociada a un GAR as como tambin
cargar la data de un GAR de un archivo. El diagrama de casos de uso correspondiente se
muestra en la Figura 6.48.
461
VOLVER A MEN
Figura 6.48. Diagrama de casos de uso relativo al problema del grafo de asignacin de recursos.
VOLVER A MEN
Ntese tambin que los conceptos proceso y recurso son representados por una sola clase
identificada como NodoGAR y que peticin y asignacin son representados por la clase
AristaGAR. Observe tambin el correcto uso de las relaciones de herencia o generalizacin
entre las clases GAR y Grafo; se lee un GAR es un caso particular de grafo. Tambin
se tiene esta relacin entre las clases AristaGAR y Arista; se lee una arista es un caso
particular de AristaGAR.
Figura 6.49. Diagrama no detallado de clases relativo al problema del grafo de asignacin de recursos.
6.8.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): En este problema se usar una interfaz grfica
para tanto administrar el GAR como para mostrar el estado actual del mismo. Adicionalmente
se tendr interaccin de lectura / escritura con archivos binarios con el objeto de cargar /
guardar la informacin de un GAR.
Paso 2 (Detallar las clases): Al agregar los atributos y mtodos a las clases de la Figura 6.49
resulta el diagrama de clases detallado de la Figura 6.50. Solo se detallan las clases que no
son de implementacin. Ntese que adicionalmente se agrega el enumerado TipoNodoGAR.
Figura 6.50. Diagrama detallado de clases relativo al problema del grafo de asignacin de recursos.
463
VOLVER A MEN
Paso 3 (Desarrollar los modelos de estado): En este problema la lgica de cambio de estado
de los objetos involucrados depende casi en su totalidad de la implementacin del grafo (en la
clase GAR). Al obviar los cambios de estado inherentes al agregar/suprimir nodos y agregar/
suprimir aristas en el grafo y por lo tanto en el GAR, se tienen los diagramas de estado de
la Figura 6.51. Ntese que no hay ningn atributo propio en la clase GAR ya que todos son
heredados y no hay cambios de estado en los objetos de la clase AristaGAR.
Figura 6.51. Diagrama de estado relativo al problema del grafo de asignacin de recursos.
Figura 6.52. Diagrama de colaboracin relativo al problema del grafo de asignacin de recursos.
464
VOLVER A MEN
Figura 6.53. Diagrama de componentes relativo al problema del grafo de asignacin de recursos.
6.8.4 Programacin
A continuacin el cdigo fuente relativo al lenguaje de programacin C++. En este caso
particular no se tiene una implementacin de Grafo como parte de la biblioteca de clases del
lenguaje. Se anexa tambin el cdigo fuente relativo a la definicin de esta clase. Se tiene
entonces los archivos fuente Grafo.hpp, Grafo.cpp, GAR.hpp y GAR.cpp.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.8
* Grafo.hpp
* Mauricio Paletta
*/
#ifndef GRAFO_HPP
#define
GRAFO_HPP
#include <vector>
namespace GrafoBib {
using namespace std;
template <class N>
class Nodo {
465
VOLVER A MEN
private:
N Objeto;
public:
Nodo(N Obj) { Objeto = Obj; }
N ObtObjeto() { return Objeto; }
};
template <class N>
class Arista {
private:
Nodo<N> *O, *D;
public:
Arista(Nodo<N> *o, Nodo<N> *d) { O = o; D = d; }
Nodo<N> *ObtOrigen() { return O; }
Nodo<N> *ObtDestino() { return D; }
};
template <class N>
class Grafo {
protected:
bool Orientado;
vector<Nodo<N> *> Nodos;
vector<Arista<N> *> Aristas;
void Limpiar() {
unsigned i;
for (i=0; i < Nodos.size(); i++)
delete Nodos[i];
Nodos.clear();
for (i=0; i < Aristas.size(); i++)
466
VOLVER A MEN
delete Aristas[i];
Aristas.clear();
}
int BuscarNodo(N obj) {
for (unsigned i=0; i < Nodos.size(); i++) {
Nodo<N> *O = Nodos[i];
if (O->ObtObjeto() == obj) return (int)i;
}
return -1;
}
int BuscarArista(Nodo<N> *O, Nodo<N> *D);
public:
Grafo(bool O) { Orientado = O; }
~Grafo() { Limpiar(); }
bool AgregarNodo(N obj) {
if (BuscarNodo(obj) >= 0) return false;
Nodos.push_back(new Nodo<N>(obj));
return true;
}
void SuprimirNodo(N obj) {
SuprimirNodo(BuscarNodo(obj));
}
void SuprimirNodo(int Idx) {
if (Idx >=0 && Idx < (int)Nodos.size()) {
delete Nodos[Idx];
Nodos.erase(Nodos.begin() + Idx);
}
}
bool AgregarArista(Nodo<N> *O, Nodo<N> *D) {
if (BuscarArista(O, D) >= 0) return false;
Aristas.push_back(new Arista<N>(O, D));
return true;
467
VOLVER A MEN
}
void SuprimirArista(Nodo<N> *O, Nodo<N> *D) {
SuprimirArista(BuscarArista(O, D));
}
void SuprimirArista(int Idx) {
if (Idx >= 0 && Idx < Aristas.size()) {
delete Aristas[Idx];
Aristas.erase(Aristas.begin() + Idx);
}
}
bool EsOrientado() { return Orientado; }
int NumNodos() { return Nodos.size(); }
int NumAristas() { return Aristas.size(); }
int Orden() { return NumNodos(); }
bool EsNulo() { return Orden() == 0; }
};
}
#endif /* GRAFO_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.8
* Grafo.cpp
* Mauricio Paletta
*/
#include Grafo.hpp
namespace GrafoBib {
template <class N>
int Grafo<N>::BuscarArista(Nodo<N> *O, Nodo<N> *D) {
for (unsigned i=0; i < Nodos.size(); i++) {
468
VOLVER A MEN
Arista<N> *A = Aristas[i];
if (A->ObtOrigen() == O && A->ObtDestino() == D) return (int)i;
}
return -1;
}
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.8
* GAR.hpp
* Mauricio Paletta
*/
#ifndef GAR_HPP
#define GAR_HPP
#include <string>
#include <vector>
#include Grafo.hpp
using namespace GrafoBib;
enum TipoNodoGAR { Proceso, Recurso };
class NodoGAR {
private:
unsigned Id, nTotRec, nRecOcu;
bool *I;
TipoNodoGAR tNodo;
public:
NodoGAR(int id, TipoNodoGAR t, int nRec = 0) {
469
VOLVER A MEN
VOLVER A MEN
return (int)i;
}
return -1;
}
bool LiberarRecurso(unsigned i) {
if (EsRecurso() && nRecOcu > 0 && i >=0 && i < nTotRec) {
I[i] = false;
nRecOcu--;
return true;
}
return false;
}
};
typedef NodoGAR *pNodoGAR;
class AristaGAR : public Arista<pNodoGAR> {
private:
int InstanciaR;
public:
AristaGAR(Nodo<pNodoGAR> *O, Nodo<pNodoGAR> *D, int I = 0) : Arista<pNodoGAR>(O, D) {
InstanciaR = I;
}
bool EsPeticion() {
return ObtOrigen()->ObtObjeto()->EsProceso() && ObtDestino()->ObtObjeto()->EsRecurso();
}
bool EsAsignacion() {
return ObtOrigen()->ObtObjeto()->EsRecurso() && ObtDestino()->ObtObjeto()->EsProceso();
}
int ObtInstanciaR() {
return InstanciaR;
}
};
471
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
//
int GAR::ObtId(TipoNodoGAR t) {
unsigned i;
int Min = 1;
bool Enc = true;
while (Enc) {
// Para todos los nodos del grafo
//
for (i=0; i < Nodos.size(); i++) {
Nodo<pNodoGAR> *N = Nodos[i];
pNodoGAR NGAR = N->ObtObjeto();
bool EsTipo = (t == Proceso && NGAR->EsProceso()) || (t == Recurso && NGAR>EsRecurso());
if (EsTipo && NGAR->ObtId() == Min) {
Min++;
break;
}
}
Enc = i < Nodos.size();
}
return Min;
}
pNodoGAR GAR::BuscarNodoGAR(int Id, TipoNodoGAR t) {
// Para todos los nodos del grafo
//
for (unsigned i=0; i < Nodos.size(); i++) {
Nodo<pNodoGAR> *N = Nodos[i];
pNodoGAR NGAR = N->ObtObjeto();
bool EsTipo = (t == Proceso && NGAR->EsProceso()) || (t == Recurso && NGAR->EsRecurso());
if (EsTipo && NGAR->ObtId() == Id) {
return NGAR;
474
VOLVER A MEN
}
}
return NULL;
}
Nodo<pNodoGAR> *GAR::BuscarNodo(int Id, TipoNodoGAR t) {
// Para todos los nodos del grafo
//
for (unsigned i=0; i < Nodos.size(); i++) {
Nodo<pNodoGAR> *N = Nodos[i];
pNodoGAR NGAR = N->ObtObjeto();
bool EsTipo = (t == Proceso && NGAR->EsProceso()) || (t == Recurso && NGAR->EsRecurso());
if (EsTipo && NGAR->ObtId() == Id) {
return N;
}
}
return NULL;
}
bool GAR::SuprimirNodoGAR(int Id, TipoNodoGAR t) {
// Para todos los nodos del grafo
//
for (unsigned i=0; i < Nodos.size(); i++) {
Nodo<pNodoGAR> *N = Nodos[i];
pNodoGAR NGAR = N->ObtObjeto();
bool EsTipo = (t == Proceso && NGAR->EsProceso()) || (t == Recurso && NGAR->EsRecurso());
if (EsTipo && NGAR->ObtId() == Id) {
delete N->ObtObjeto();
delete N;
Nodos.erase(Nodos.begin() + i);
return true;
}
}
return false;
475
VOLVER A MEN
}
pAristaGAR GAR::BuscarAristaGAR(int IdO, int IdD) {
// Para todas las aristas del grafo
//
for (unsigned i=0; i < Aristas.size(); i++) {
pAristaGAR A = (pAristaGAR)Aristas[i];
pNodoGAR O = A->ObtOrigen()->ObtObjeto(), D = A->ObtDestino()->ObtObjeto();
if (O->ObtId() == IdO && D->ObtId() == IdD) {
return A;
}
}
return NULL;
}
bool GAR::SuprimirAristaGAR(int IdO, int IdD) {
// Para todas las aristas del grafo
//
for (unsigned i=0; i < Aristas.size(); i++) {
pAristaGAR A = (pAristaGAR)Aristas[i];
pNodoGAR O = A->ObtOrigen()->ObtObjeto(), D = A->ObtDestino()->ObtObjeto();
if (O->ObtId() == IdO && D->ObtId() == IdD) {
delete A;
Aristas.erase(Aristas.begin() + i);
return true;
}
}
return false;
}
void GAR::Limpiar() {
unsigned i;
for (i=0; i < Nodos.size(); i++) {
delete Nodos[i]->ObtObjeto();
476
VOLVER A MEN
}
Grafo<pNodoGAR>::Limpiar();
}
int GAR::AgregarRecurso(int Rs) {
// Se busca un identificar vlido
//
int Id = ObtId(Recurso);
return AgregarNodo(new NodoGAR(Id, Recurso, Rs)) ? Id : -1;
}
bool GAR::AgregarRecurso(int Id, int Rs) {
// Se verifica si el identificador no est repetido
//
if (BuscarRecurso(Id) != NULL) return false;
return AgregarNodo(new NodoGAR(Id, Recurso, Rs));
}
int GAR::AgregarProceso() {
// Se busca un identificar vlido
//
int Id = ObtId(Proceso);
return AgregarNodo(new NodoGAR(Id, Proceso)) ? Id : -1;
}
bool GAR::AgregarProceso(int Id) {
// Se verifica si el identificador no est repetido
//
if (BuscarProceso(Id) != NULL) return false;
return AgregarNodo(new NodoGAR(Id, Proceso));
}
bool GAR::AgregarPeticion(int IdP, int IdR) {
// Se buscan los nodos asociados al proceso y al recurso
//
Nodo<pNodoGAR> *Np = BuscarNodo(IdP, Proceso),
*Nr = BuscarNodo(IdR, Recurso);
477
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
if (R == 1)
AgregarAsignacion(Id, nR);
else
AgregarPeticion(Id, nR);
}
MiArchivo.close();
} catch (...) {
return false;
}
return true;
}
// Obtener el listado de los identificadores de procesos
//
vector<unsigned> GAR::ObtListaProcesos() {
vector<unsigned> V;
for (unsigned i=0; i < Nodos.size(); i++) {
pNodoGAR N = Nodos[i]->ObtObjeto();
if (N->EsProceso()) V.push_back(N->ObtId());
}
return V;
}
// Obtener el listado de los identificadores de recursos
//
vector<unsigned> GAR::ObtListaRecursos() {
vector<unsigned> V;
for (unsigned i=0; i < Nodos.size(); i++) {
pNodoGAR N = Nodos[i]->ObtObjeto();
if (N->EsRecurso()) V.push_back(N->ObtId());
}
481
VOLVER A MEN
return V;
}
// Obtener el listado de las aristas del GAR
//
vector<pAristaGAR> GAR::ObtAristasGAR() {
vector<pAristaGAR> V;
for (unsigned i=0; i < Aristas.size(); i++) {
V.push_back((pAristaGAR)Aristas[i]);
}
return V;
}
El cdigo fuente escrito en Java es el que se muestra a continuacin. Al igual que ocurre en el
caso anterior se tiene el paquete GrafoBib con la definicin de las clases para la representacin
del grafo y los archivos fuente Nodo.java, Arista.java y Grafo.java. Por otro lado se tiene
el paquete GAR y el archivo fuente GAR.java con el conjunto de clases necesarias para
representar un GAR.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.8
* Nodo.java
* Mauricio Paletta
*/
package GrafoBib;
public class Nodo<N> {
private N Objeto;
public Nodo(N Obj) { Objeto = Obj; }
public N ObtObjeto() { return Objeto; }
}
482
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.8
* Arista.java
* Mauricio Paletta
*/
package GrafoBib;
public class Arista<N> {
private Nodo<N> O, D;
public Arista(Nodo<N> o, Nodo<N> d) { O = o; D = d; }
public Nodo<N> ObtOrigen() { return O; }
public Nodo<N> ObtDestino() { return D; }
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.8
* Grafo.java
* Mauricio Paletta
*/
package GrafoBib;
import java.util.ArrayList;
public class Grafo<N> {
protected boolean Orientado;
protected ArrayList<Nodo<N>> Nodos;
protected ArrayList<Arista<N>> Aristas;
protected void Limpiar() {
Nodos.clear();
Aristas.clear();
}
483
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
import java.util.logging.Level;
public class GAR extends Grafo {
public enum TipoNodoGAR {
Proceso, Recurso
}
public class NodoGAR {
private int Id, nTotRec, nRecOcu;
boolean I[];
TipoNodoGAR tNodo;
public NodoGAR(int id, TipoNodoGAR t, int nRec) {
Id = id; tNodo = t; nTotRec = nRec; nRecOcu = 0;
if (nTotRec > 0) {
I = new boolean[nTotRec];
for (int i=0; i < nTotRec; I[i++] = false);
}
}
public int ObtId() { return Id; }
public boolean EsRecurso() { return tNodo == TipoNodoGAR.Recurso; }
public boolean EsProceso() { return !EsRecurso(); }
public int ObtNumTotalRecursos() {
if (EsRecurso()) return nTotRec;
return 0;
}
public int ObtNumRecursosDisponibles() {
if (EsRecurso()) return nTotRec - nRecOcu;
return 0;
}
public int ObtNumRecursosOcupados() {
if (EsRecurso()) return nRecOcu;
486
VOLVER A MEN
return 0;
}
public boolean HayRecursosDisponibles() {
if (EsRecurso()) return ObtNumRecursosDisponibles() > 0;
return false;
}
public int AsignarRecurso() {
if (HayRecursosDisponibles()) {
// Se busca la primera instancia libre
//
int i;
for (i=0; i < nTotRec && I[i]; i++);
I[i] = true;
nRecOcu++;
return i;
}
return -1;
}
public boolean LiberarRecurso(int i) {
if (EsRecurso() && nRecOcu > 0 && i >=0 && i < nTotRec) {
I[i] = false;
nRecOcu--;
return true;
}
return false;
}
}
public class AristaGAR extends Arista {
private int InstanciaR;
public AristaGAR(Nodo O, Nodo D, int I) {
487
VOLVER A MEN
super(O, D);
InstanciaR = I;
}
public boolean EsPeticion() {
return ((NodoGAR)(ObtOrigen().ObtObjeto())).EsProceso() &&
((NodoGAR)(ObtDestino().ObtObjeto())).EsRecurso();
}
public boolean EsAsignacion() {
return ((NodoGAR)(ObtOrigen().ObtObjeto())).EsRecurso() &&
((NodoGAR)(ObtDestino().ObtObjeto())).EsProceso();
}
public int ObtInstanciaR() {
return InstanciaR;
}
}
public GAR() { super(true); }
private int ObtId(TipoNodoGAR t) {
int i, Min = 1;
boolean Enc = true;
while (Enc) {
// Para todos los nodos del grafo
//
for (i=0; i < Nodos.size(); i++) {
Nodo N = (Nodo)Nodos.get(i);
NodoGAR NGAR = (NodoGAR)N.ObtObjeto();
boolean EsTipo = (t == TipoNodoGAR.Proceso && NGAR.EsProceso()) ||
(t == TipoNodoGAR.Recurso && NGAR.EsRecurso());
if (EsTipo && NGAR.ObtId() == Min) {
Min++;
break;
488
VOLVER A MEN
}
}
Enc = i < Nodos.size();
}
return Min;
}
private NodoGAR BuscarNodoGAR(int Id, TipoNodoGAR t) {
// Para todos los nodos del grafo
//
for (int i=0; i < Nodos.size(); i++) {
Nodo N = (Nodo)Nodos.get(i);
NodoGAR NGAR = (NodoGAR)N.ObtObjeto();
boolean EsTipo = (t == TipoNodoGAR.Proceso && NGAR.EsProceso()) ||
(t == TipoNodoGAR.Recurso && NGAR.EsRecurso());
if (EsTipo && NGAR.ObtId() == Id) {
return NGAR;
}
}
return null;
}
private AristaGAR BuscarAristaGAR(int IdO, int IdD) {
// Para todas las aristas del grafo
//
for (int i=0; i < Aristas.size(); i++) {
AristaGAR A = (AristaGAR)Aristas.get(i);
NodoGAR O = (NodoGAR)A.ObtOrigen().ObtObjeto(),
D = (NodoGAR)A.ObtDestino().ObtObjeto();
if (O.ObtId() == IdO && D.ObtId() == IdD) {
return A;
}
}
return null;
}
489
VOLVER A MEN
VOLVER A MEN
AristaGAR A = (AristaGAR)Aristas.get(i);
NodoGAR O = (NodoGAR)A.ObtOrigen().ObtObjeto(),
D = (NodoGAR)A.ObtDestino().ObtObjeto();
if (O.ObtId() == IdO && D.ObtId() == IdD) {
Aristas.remove(i);
return true;
}
}
return false;
}
public NodoGAR BuscarRecurso(int Id) {
return BuscarNodoGAR(Id, TipoNodoGAR.Recurso);
}
public NodoGAR BuscarProceso(int Id) {
return BuscarNodoGAR(Id, TipoNodoGAR.Proceso);
}
public int AgregarRecurso(int Rs) {
// Se busca un identificar vlido
//
int Id = ObtId(TipoNodoGAR.Recurso);
return AgregarNodo(new NodoGAR(Id, TipoNodoGAR.Recurso, Rs)) ? Id : -1;
}
public boolean AgregarRecurso(int Id, int Rs) {
// Se verifica si el identificador no est repetido
//
if (BuscarRecurso(Id) != null) return false;
return AgregarNodo(new NodoGAR(Id, TipoNodoGAR.Recurso, Rs));
}
public boolean SuprimirRecurso(int Id) {
return SuprimirNodoGAR(Id, TipoNodoGAR.Recurso);
}
public int AgregarProceso() {
491
VOLVER A MEN
492
VOLVER A MEN
VOLVER A MEN
MiArchivo.write(N.EsRecurso() ? 1 : 0);
MiArchivo.write(N.ObtId());
if (N.EsRecurso()) {
MiArchivo.write(N.ObtNumTotalRecursos());
}
}
// Se guardan ahora las aristas
//
Aux = Aristas.size();
MiArchivo.write(Aux);
for (i=0; i < Aux; i++) {
AristaGAR A = (AristaGAR)Aristas.get(i);
MiArchivo.write(A.EsAsignacion() ? 1 : 0);
MiArchivo.write(((NodoGAR)(A.ObtOrigen().ObtObjeto())).ObtId());
MiArchivo.write(((NodoGAR)(A.ObtDestino().ObtObjeto())).ObtId());
}
MiArchivo.close();
} catch (FileNotFoundException ex) {
java.util.logging.Logger.getLogger(GAR.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (IOException ex) {
java.util.logging.Logger.getLogger(GAR.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
return true;
}
public boolean Cargar(String Nombre) {
FileInputStream MiArchivo;
int i, N, R, Id, nR;
try {
MiArchivo = new FileInputStream(Nombre);
494
VOLVER A MEN
VOLVER A MEN
return false;
} catch (IOException ex) {
java.util.logging.Logger.getLogger(GAR.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
return true;
}
public ArrayList<Integer> ObtListaProcesos() {
ArrayList<Integer> V = new ArrayList();
for (int i=0; i < Nodos.size(); i++) {
NodoGAR N = (NodoGAR)(((Nodo)(Nodos.get(i))).ObtObjeto());
if (N.EsProceso()) V.add(new Integer(N.ObtId()));
}
return V;
}
public ArrayList<Integer> ObtListaRecursos() {
ArrayList<Integer> V = new ArrayList();
for (int i=0; i < Nodos.size(); i++) {
NodoGAR N = (NodoGAR)(((Nodo)(Nodos.get(i))).ObtObjeto());
if (N.EsRecurso()) V.add(new Integer(N.ObtId()));
}
return V;
}
public ArrayList<AristaGAR> ObtAristasGAR() {
ArrayList<AristaGAR> V = new ArrayList();
for (int i=0; i < Aristas.size(); i++) {
V.add((AristaGAR)Aristas.get(i));
}
return V;
}
}
496
VOLVER A MEN
A continuacin el cdigo relativo a C#. Similar a los casos anteriores, se tiene el paquete GrafoBib con
la implementacin del grafo en el archivo fuente Grafo.cs y el paquete GAR con la implementacin
del GAR en el archivo fuente GAR.cs.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C#; caso prctico Seccin 6.8
* Grafo.cs
* Mauricio Paletta
*/
using System;
using System.Collections.Generic;
namespace GrafoBib
{
public class Nodo<N>
{
private N Objeto;
public Nodo(N Obj) { Objeto = Obj; }
public N ObtObjeto() { return Objeto; }
}
public class Arista<N>
{
private Nodo<N> O, D;
public Arista(Nodo<N> o, Nodo<N> d) { O = o; D = d; }
public Nodo<N> ObtOrigen() { return O; }
public Nodo<N> ObtDestino() { return D; }
}
public class Grafo<N>
{
497
VOLVER A MEN
VOLVER A MEN
}
public bool AgregarNodo(N obj)
{
if (BuscarNodo(obj) >= 0) return false;
Nodos.Add(new Nodo<N>(obj));
return true;
}
public void SuprimirNodo(N obj)
{
SuprimirNodo(BuscarNodo(obj));
}
public void SuprimirNodo(int Idx)
{
if (Idx >=0 && Idx < Nodos.Count)
Nodos.Remove(Nodos[Idx]);
}
public bool AgregarArista(Nodo<N> O, Nodo<N> D)
{
if (BuscarArista(O, D) >= 0) return false;
Aristas.Add(new Arista<N>(O, D));
return true;
}
public void SuprimirArista(Nodo<N> O, Nodo<N> D)
{
SuprimirArista(BuscarArista(O, D));
}
public void SuprimirArista(int Idx)
{
if (Idx >= 0 && Idx < Aristas.Count)
Aristas.Remove(Aristas[Idx]);
}
public bool EsOrientado() { return Orientado; }
public int NumNodos() { return Nodos.Count; }
499
VOLVER A MEN
VOLVER A MEN
{
I = new bool[nTotRec];
for (int i=0; i < nTotRec; I[i++] = false);
}
}
public int ObtId() { return Id; }
public bool EsRecurso() { return tNodo == TipoNodoGAR.Recurso; }
public bool EsProceso() { return !EsRecurso(); }
public int ObtNumTotalRecursos()
{
if (EsRecurso()) return nTotRec;
return 0;
}
public int ObtNumRecursosDisponibles()
{
if (EsRecurso()) return nTotRec - nRecOcu;
return 0;
}
public int ObtNumRecursosOcupados()
{
if (EsRecurso()) return nRecOcu;
return 0;
}
public bool HayRecursosDisponibles()
{
if (EsRecurso()) return ObtNumRecursosDisponibles() > 0;
return false;
}
public int AsignarRecurso()
{
if (HayRecursosDisponibles())
{
501
VOLVER A MEN
VOLVER A MEN
{
return ((NodoGAR)(ObtOrigen().ObtObjeto())).EsProceso() &&
((NodoGAR)(ObtDestino().ObtObjeto())).EsRecurso();
}
public bool EsAsignacion()
{
return ((NodoGAR)(ObtOrigen().ObtObjeto())).EsRecurso() &&
((NodoGAR)(ObtDestino().ObtObjeto())).EsProceso();
}
public int ObtInstanciaR()
{
return InstanciaR;
}
}
public class GAR : Grafo<NodoGAR>
{
public GAR() : base(true) { }
private int ObtId(TipoNodoGAR t)
{
int i, Min = 1;
bool Enc = true;
while (Enc) {
// Para todos los nodos del grafo
//
for (i=0; i < Nodos.Count; i++) {
Nodo<NodoGAR> N = (Nodo<NodoGAR>)Nodos[i];
NodoGAR NGAR = (NodoGAR)N.ObtObjeto();
503
VOLVER A MEN
VOLVER A MEN
NodoGAR O = (NodoGAR)A.ObtOrigen().ObtObjeto(),
D = (NodoGAR)A.ObtDestino().ObtObjeto();
if (O.ObtId() == IdO && D.ObtId() == IdD) return A;
}
return null;
}
private Nodo<NodoGAR> BuscarNodo(int Id, TipoNodoGAR t)
{
// Para todos los nodos del grafo
//
for (int i=0; i < Nodos.Count; i++) {
Nodo<NodoGAR> N = (Nodo<NodoGAR>)Nodos[i];
NodoGAR NGAR = (NodoGAR)N.ObtObjeto();
bool EsTipo = (t == TipoNodoGAR.Proceso && NGAR.EsProceso()) ||
(t == TipoNodoGAR.Recurso && NGAR.EsRecurso());
if (EsTipo && NGAR.ObtId() == Id) return N;
}
return null;
}
private bool SuprimirNodoGAR(int Id, TipoNodoGAR t)
{
// Para todos los nodos del grafo
//
for (int i=0; i < Nodos.Count; i++) {
Nodo<NodoGAR> N = (Nodo<NodoGAR>)Nodos[i];
NodoGAR NGAR = (NodoGAR)N.ObtObjeto();
bool EsTipo = (t == TipoNodoGAR.Proceso && NGAR.EsProceso()) ||
(t == TipoNodoGAR.Recurso && NGAR.EsRecurso());
if (EsTipo && NGAR.ObtId() == Id) {
Nodos.Remove(N);
return true;
}
}
505
VOLVER A MEN
return false;
}
private bool SuprimirAristaGAR(int IdO, int IdD)
{
// Para todas las aristas del grafo
//
for (int i=0; i < Aristas.Count; i++) {
AristaGAR A = (AristaGAR)Aristas[i];
NodoGAR O = (NodoGAR)A.ObtOrigen().ObtObjeto(),
D = (NodoGAR)A.ObtDestino().ObtObjeto();
if (O.ObtId() == IdO && D.ObtId() == IdD)
{
Aristas.Remove(A);
return true;
}
}
return false;
}
public NodoGAR BuscarRecurso(int Id)
{
return BuscarNodoGAR(Id, TipoNodoGAR.Recurso);
}
public NodoGAR BuscarProceso(int Id)
{
return BuscarNodoGAR(Id, TipoNodoGAR.Proceso);
}
public int AgregarRecurso(int Rs)
{
// Se busca un identificar vlido
//
int Id = ObtId(TipoNodoGAR.Recurso);
return AgregarNodo(new NodoGAR(Id, TipoNodoGAR.Recurso, Rs)) ? Id : -1;
506
VOLVER A MEN
}
public bool AgregarRecurso(int Id, int Rs)
{
// Se verifica si el identificador no est repetido
//
if (BuscarRecurso(Id) != null) return false;
return AgregarNodo(new NodoGAR(Id, TipoNodoGAR.Recurso, Rs));
}
public bool SuprimirRecurso(int Id)
{
return SuprimirNodoGAR(Id, TipoNodoGAR.Recurso);
}
public int AgregarProceso()
{
// Se busca un identificar vlido
//
int Id = ObtId(TipoNodoGAR.Proceso);
return AgregarNodo(new NodoGAR(Id, TipoNodoGAR.Proceso, 0)) ? Id : -1;
}
public bool AgregarProceso(int Id)
{
// Se verifica si el identificador no est repetido
//
if (BuscarProceso(Id) != null) return false;
return AgregarNodo(new NodoGAR(Id, TipoNodoGAR.Proceso, 0));
}
public bool SuprimirProceso(int Id)
{
return SuprimirNodoGAR(Id, TipoNodoGAR.Proceso);
}
public bool AgregarPeticion(int IdP, int IdR)
{
507
VOLVER A MEN
VOLVER A MEN
{
// Primero se libera el recurso
//
NodoGAR Nr = BuscarRecurso(IdR);
AristaGAR A = BuscarAristaGAR(IdR, IdP);
if (Nr == null || A == null) return false;
Nr.LiberarRecurso(A.ObtInstanciaR());
return SuprimirAristaGAR(IdR, IdP);
}
public bool Guardar(string Nombre)
{
FileStream MiArchivo = new FileStream(Nombre, FileMode.Create);
BinaryWriter Bw = new BinaryWriter(MiArchivo);
try {
// Primero se guarda el nmero de nodos y luego los nodos
//
int i, Aux = Nodos.Count;
Bw.Write((Int32)Aux);
for (i=0; i < Aux; i++)
{
NodoGAR N = (NodoGAR)(((Nodo<NodoGAR>)(Nodos[i])).ObtObjeto());
Bw.Write((Int32)(N.EsRecurso() ? 1 : 0));
Bw.Write((Int32)(N.ObtId()));
if (N.EsRecurso()) Bw.Write((Int32)(N.ObtNumTotalRecursos()));
}
// Se guardan ahora las aristas
//
Aux = Aristas.Count;
Bw.Write((Int32)Aux);
for (i=0; i < Aux; i++)
{
AristaGAR A = (AristaGAR)Aristas[i];
509
VOLVER A MEN
Bw.Write((Int32)(A.EsAsignacion() ? 1 : 0));
Bw.Write((Int32)(((NodoGAR)(A.ObtOrigen().ObtObjeto())).ObtId()));
Bw.Write((Int32)(((NodoGAR)(A.ObtDestino().ObtObjeto())).ObtId()));
}
MiArchivo.Close();
}
catch (Exception)
{
return false;
}
return true;
}
public bool Cargar(string Nombre)
{
FileStream MiArchivo = new FileStream(Nombre, FileMode.Open);
BinaryReader Br = new BinaryReader(MiArchivo);
int i, N, R, Id, nR;
try {
// Cualquier cosa previa se suprime
//
Limpiar();
// Se lee el nmero de nodos y los nodos
//
N = Br.ReadInt32();
for (i=0; i < N; i++)
{
R = Br.ReadInt32();
Id = Br.ReadInt32();
if (R == 1)
{
nR = Br.ReadInt32();
AgregarRecurso(Id, nR);
510
VOLVER A MEN
}
else
{
AgregarProceso(Id);
}
}
// Se lee el nmero de aristas y las aristas
//
N = Br.ReadInt32();
for (i=0; i < N; i++)
{
R = Br.ReadInt32();
Id = Br.ReadInt32();
nR = Br.ReadInt32();
if (R == 1)
AgregarAsignacion(Id, nR);
else
AgregarPeticion(Id, nR);
}
MiArchivo.Close();
}
catch (Exception)
{
return false;
}
return true;
}
public List<int> ObtListaProcesos()
{
List<int> V = new List<int>();
for (int i=0; i < Nodos.Count; i++)
{
511
VOLVER A MEN
NodoGAR N = (NodoGAR)(((Nodo<NodoGAR>)(Nodos[i])).ObtObjeto());
if (N.EsProceso()) V.Add(N.ObtId());
}
return V;
}
public List<int> ObtListaRecursos()
{
List<int> V = new List<int>();
for (int i=0; i < Nodos.Count; i++)
{
NodoGAR N = (NodoGAR)(((Nodo<NodoGAR>)(Nodos[i])).ObtObjeto());
if (N.EsRecurso()) V.Add(N.ObtId());
}
return V;
}
public List<AristaGAR> ObtAristasGAR() {
List<AristaGAR> V = new List<AristaGAR>();
for (int i=0; i < Aristas.Count; i++)
{
V.Add((AristaGAR)Aristas[i]);
}
return V;
}
}
}
512
VOLVER A MEN
Figura 6.54. Ejemplo de un campo de batalla para el problema de la conquista del nuevo mundo.
Las unidades o entidades que intervienen en la simulacin slo se pueden mover de forma
ortogonal (hacia adelante para el avance, hacia atrs para la retirada y a los lados para cubrir
territorio), no de forma diagonal, a menos que el cuadro inmediato siguiente est ocupado
por una unidad enemiga. El nmero de cuadros con los cuales una unidad se puede mover
depende del tipo de unidad. Inicialmente todas las unidades estn ubicadas en el territorio de
sus banderas. Una unidad nunca puede ocupar un cuadro que est siendo ocupado por una
unidad del enemigo.
Cada unidad posee un valor discreto que determina su nivel de vida y cuando este valor llega a
cero implica la muerte de la unidad. Es importante que este valor se muestre en todo momento
durante la simulacin de forma tal de observar el estado actual de cada unidad.
Cada unidad posee su propia puntera y alcance de tiro que les son asignados en el momento
de la creacin. La puntera viene dada por una probabilidad de acertar al enemigo y el alcance
viene dado por el nmero de cuadros que lo separan del objetivo. La visin de tiro es ortogonal
(hacia adelante y a los lados).
A continuacin se presentan los tipos de unidades que se pueden tener:
Infantes: Su capacidad de movimiento es de un cuadro por turno. Su nivel de vida es igual
a 4. Su puntera viene dada por una probabilidad de 0.6. Su alcance es de un cuadro.
Caballera: Su capacidad de movimiento es de dos cuadros por turno. Su nivel de vida es
de 5. Su puntera viene dada por una probabilidad de 0.75. Su alcance es de un cuadro.
513
VOLVER A MEN
6.9.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): La revisin del enunciado del
problema lleva a un mapa mental segn se muestra en la Figura 6.55.
514
VOLVER A MEN
Figura 6.55. Mapa mental relativo al problema de la conquista del nuevo mundo.
Paso 2 (Identificar actores / nombres): Se tiene la siguiente lista de nombres: Batalla, territorio,
conquistador, nativo, bandera, oponente, campo de batalla, matriz, grupo, contrincante, unidad,
enemigo, nivel de vida, puntera, alcance de tiro, infante, caballera, artillera, cuadro y turno.
Paso 3 (Identificar procesos / requerimientos): En este problema se busca tener un juego en la
cual un usuario o jugador debe enfrentarse a un algoritmo como contrincante. Se tiene entonces
un actor representado por el jugador quin, adems de jugar, tambin realiza la configuracin
necesaria. Se tiene el diagrama de casos de uso que se muestra en la Figura 6.56. Ntese
que se representa tanto el juego realizado por el actor como el realizado automticamente y en
ambos casos se tiene opcionalmente la posibilidad de mover unidades y atacar.
Figura 6.56. Diagrama de casos de uso relativo al problema de la conquista del nuevo mundo.
VOLVER A MEN
Figura 6.57. Diagrama no detallado de clases relativo al problema de la conquista del nuevo mundo.
516
VOLVER A MEN
6.9.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): Lo ms adecuado para este problema es tener
una interfaz grfica y un par de formularios, uno para hacer la configuracin y el otro para jugar.
Con respecto al juego debe haber una manera de discriminar los turnos: jugador y algoritmo.
La interfaz debe adems, mostrar el estado actual del juego en todo momento. Esto implica
que hay que mostrar las unidades, el grupo al cual pertenecen, su tipo, sus niveles de vida y
su ubicacin en el campo de batalla.
Paso 2 (Detallar las clases): Al agregar los atributos y mtodos a las clases de la Figura 6.57
resulta el diagrama de clases detallado de la Figura 6.58. Por la complejidad del problema es
de esperarse que el detalle de las clases est conformado por un nmero mayor de elementos
comparado con los problemas previos. Ntese que se agrega el tipo de dato enumerado
TipoUnidad para representar en tres literales los tipos posibles de unidades. Ntese tambin
que la clase Espacio es abstracta (representado por el identificador escrito en letra cursiva) y
los mtodos UbicarUnidad, SacarUnidad y ObtPosicion son virtuales.
Figura 6.58. Diagrama detallado de clases relativo al problema de la conquista del nuevo mundo.
517
VOLVER A MEN
Paso 3 (Desarrollar los modelos de estado): La Figura 6.59 muestra los diagramas de estado de
las clases relativas a este problema. Las clases Cuadro y Base no aparecen porque carecen
de atributos propios; los cambios de estado se representan con la clase genrica Espacio.
A fin de simplificar el diagrama se estn obviendo algunas transiciones entre estados. Ntese
que con respecto a las clases Campo y Grupo el nico estado posible es dado en tiempo
de construccin del objeto, es decir, da a entender que ni el campo ni los grupos pueden ser
alterados durante el juego.
Figura 6.59. Diagramas de estado relativos al problema de la conquista del nuevo mundo.
Paso 4 (Elaborar los modelos de colaboracin): La Figura 6.60 muestra una simplificacin del
diagrama de secuencias relativo a este problema. Slo se representa lo ms relevante del
problema a fin de hacer el diagrama no tan complejo. Se muestra parte de la secuencia de
colaboracin usada para jugar el usuario; esta misma secuncia se debera repetir en el juego
automatizado. Ntese que se generaliza el uso de los objetos que representan las bases y los
cuadros del campo con la clase base genrica Espacio.
518
VOLVER A MEN
Figura 6.60. Diagrama de secuencias relativo al problema de la conquista del nuevo mundo.
Figura 6.61. Diagrama de componentes relativo al problema de la conquista del nuevo mundo.
519
VOLVER A MEN
6.9.4 Programacin
Para la implementacin de C++ se realizaron los siguientes archivos fuente: Campo.hpp
y Campo.cpp, Grupo.hpp y Grupo.cpp y la pareja Conquista.hpp y Conquista.cpp.
Adicionalmente y con el objeto de resolver conflictos en la compilacin de los diferentes
elementos cuyas definiciones estn cruzadas entre ellas, se tiene el archivo encabezado
DeclaracionesBase.hpp. A continuacin los listados correspondientes. Se utiliz un espacio
de nombres identificado como ConquistaNM.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Campo.hpp
* Mauricio Paletta
*/
#ifndef CAMPO_HPP
#define CAMPO_HPP
#include <QtGui>
#include <QPoint>
#include <string>
#include DeclaracionesBase.hpp
namespace ConquistaNM {
// Representa un espacio del campo donde van las unidades
//
class Espacio : public QFrame {
protected:
int Disponibilidad;
pConquista refJuego;
QFrame *panelCol1, *panelCol2;
void mousePressEvent(QMouseEvent *M);
520
VOLVER A MEN
public:
Espacio(pConquista J, std::string n, int x, int y, int u, int f);
~Espacio();
void Limpiar();
int ObtDisponibilidad() { return Disponibilidad; }
// Ubicar una unidad en el cuadro siempre y cuando no supere
// el mximo permitido: equivalente a 6 infantes
//
virtual bool UbicarUnidad(pUnidad U) = 0;
virtual bool SacarUnidad(pUnidad U) = 0;
virtual QPoint *ObtPosicion() = 0;
QFrame *EstaUnidad(pUnidad U);
int ObtIdBase();
bool Vacio() {
return panelCol1->children().count() == 0 && panelCol2->children().count() == 0;
}
int ObtNumeroUnidades() {
return panelCol1->children().count() + panelCol2->children().count();
}
int ObtNumeroUnidades(TipoUnidad T);
pUnidad ObtMasDebil();
};
typedef Espacio *pEspacio;
// Representa una base
//
class Base : public Espacio {
public:
Base(pConquista J, std::string n, int x, int y, int u, int f) :
Espacio(J, n, x, y, u, f) { }
521
VOLVER A MEN
VOLVER A MEN
private:
// Tamao del campo de batalla
//
int F, C;
pCuadro *Cuadros;
pBase *Bases;
QFrame *gridPanel;
pConquista refJuego;
public:
Campo(pConquista J, int f, int c, int uB1, int uB2);
~Campo();
bool UbicarUnidad(pUnidad U, int f, int c);
bool SacarUnidad(pUnidad U, int f, int c);
bool UbicarUnidad(pUnidad U, int b);
bool SacarUnidad(pUnidad U, int b);
QPoint *ObtPosicionUnidad(pUnidad U);
void Limpiar();
pEspacio BuscarUnidad(pUnidad U);
bool HayUnidad(int IdBase, QPoint *P);
pBase ObtBase(int IdBase) {
return (IdBase >= 1 && IdBase <= 2) ? Bases[IdBase-1] : NULL;
}
pCuadro ObtCuadro(int f, int c) {
return (f >= 0 && f < F && c >= 0 && c < C) ? Cuadros[f * F + c] : NULL;
}
int ObtNumFilas() { return F; }
int ObtNumColumnas() { return C; }
bool HayConquistadoresBaseNativos() {
return Bases[0]->HayUnidadEnemiga();
}
bool HayNativosBaseConquistadores() {
return Bases[1]->HayUnidadEnemiga();
523
VOLVER A MEN
}
};
}
#endif /* CAMPO_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Campo.cpp
* Mauricio Paletta
*/
#include Grupo.hpp
#include Conquista.hpp
#include Campo.hpp
namespace ConquistaNM {
// Mtodos de la clase Espacio
//
Espacio::Espacio(pConquista J, std::string n, int x, int y, int u, int f)
: QFrame(J->ObtFormulario()) {
refJuego = J;
if (u <= 0) u = 1;
Disponibilidad = u;
this->setGeometry(x, y, 90, 135 * f);
this->setObjectName(tr(n.c_str()));
this->setFrameShape(Panel);
this->setFrameShadow(Plain);
this->setLineWidth(2);
this->setCursor(Qt::PointingHandCursor);
524
VOLVER A MEN
VOLVER A MEN
L = panelCol1->children();
L.clear();
}
if (panelCol2 != NULL) {
L = panelCol2->children();
L.clear();
}
}
QFrame *Espacio::EstaUnidad(pUnidad U) {
int i;
if (U == NULL) return NULL;
for (i=0; i < panelCol1->children().count(); i++) {
if (panelCol1->children()[i] == U) return panelCol1;
}
for (i=0; i < panelCol2->children().count(); i++) {
if (panelCol2->children()[i] == U) return panelCol2;
}
return NULL;
}
int Espacio::ObtIdBase() {
if (panelCol1->children().count() != 0)
return ((pUnidad)(panelCol1->children()[0]))->ObtIdBase();
if (panelCol2->children().count() != 0)
return ((pUnidad)(panelCol2->children()[0]))->ObtIdBase();
return 0;
}
int Espacio::ObtNumeroUnidades(TipoUnidad T) {
int i, S = 0;
pUnidad U;
for (i=0; i < panelCol1->children().count(); i++) {
526
VOLVER A MEN
U = dynamic_cast<pUnidad>(panelCol1->children()[i]);
if (U->ObtTipo() == T) S++;
}
for (i=0; i < panelCol2->children().count(); i++) {
U = dynamic_cast<pUnidad>(panelCol2->children()[i]);
if (U->ObtTipo() == T) S++;
}
return S;
}
pUnidad Espacio::ObtMasDebil() {
pUnidad U, MasDebil = NULL;
int i;
for (i=0; i < panelCol1->children().count(); i++) {
U = dynamic_cast<pUnidad>(panelCol1->children()[i]);
if (MasDebil == NULL || U->ObtNivelVida() < MasDebil->ObtNivelVida())
MasDebil = U;
}
for (i=0; i < panelCol2->children().count(); i++) {
U = dynamic_cast<pUnidad>(panelCol2->children()[i]);
if (MasDebil == NULL || U->ObtNivelVida() < MasDebil->ObtNivelVida())
MasDebil = U;
}
return MasDebil;
}
// Mtodos de la clase Base
//
bool Base::UbicarUnidad(pUnidad U) {
int i, u;
if (U == NULL || Disponibilidad == 0 || U->HizoOperacion()) return false;
i = panelCol1->children().count();
527
VOLVER A MEN
u = panelCol1->height() / 45;
if (i < u) {
U->setParent(panelCol1);
panelCol1->repaint();
}
else {
i = panelCol2->children().count();
u = panelCol2->height() / 45;
if (i < u) {
U->setParent(panelCol2);
panelCol2->repaint();
}
else
return false;
}
U->show();
U->setGeometry(0, 45 * i, 45, 45);
U->EntrarBase();
U->Refrescar();
Disponibilidad--;
this->repaint();
return true;
}
bool Base::SacarUnidad(pUnidad U) {
QFrame *P = EstaUnidad(U);
QObjectList L;
if (U == NULL || P == NULL || U->HizoOperacion()) return false;
U->SalirBase();
U->setVisible(false);
U->setParent(refJuego->ObtFormulario());
L = P->children();
528
VOLVER A MEN
Disponibilidad++;
for (int i=0; i < L.size(); i++)
dynamic_cast<pUnidad>(L[i])->setGeometry(0, 45*i, U->width(), U->height());
P->repaint();
repaint();
return true;
}
bool Base::HayUnidadEnemiga() {
pUnidad U;
int i, EstaBase = this->x() <= 1 ? 1 : 2;
for (i=0; i < panelCol1->children().count(); i++) {
U = dynamic_cast<pUnidad>(panelCol1->children()[i]));
if (U->ObtIdBase() != EstaBase) return true;
}
for (i=0; i < panelCol2->children().count(); i++) {
U = dynamic_cast<pUnidad>(panelCol2->children()[i]));
if (U->ObtIdBase() != EstaBase) return true;
}
return false;
}
// Mtodos de la clase Cuadro
//
bool Cuadro::UbicarUnidad(pUnidad U) {
int i, Requerido;
if (U == NULL || U->HizoOperacion()) return false;
Requerido = U->ObtTipo() == Infante ? 1 : 2;
if (Disponibilidad - Requerido < 0) return false;
i = panelCol1->children().count();
if (i < 3) {
529
VOLVER A MEN
U->setParent(panelCol1);
panelCol1->repaint();
}
else {
i = panelCol2->children().count();
if (i < 3) {
U->setParent(panelCol2);
panelCol2->repaint();
}
else
return false;
}
U->show();
U->setGeometry(0, i * 45, 45, 45);
U->repaint();
Disponibilidad -= Requerido;
repaint();
return true;
}
bool Cuadro::SacarUnidad(pUnidad U) {
int Ocupado;
QFrame *P = EstaUnidad(U);
QObjectList L;
if (U == NULL || P == NULL || U->HizoOperacion()) return false;
Ocupado = U->ObtTipo() == Infante ? 1 : 2;
U->setVisible(false);
U->setParent(refJuego->ObtFormulario());
Disponibilidad += Ocupado;
L = P->children();
for (int i=0; i < L.size(); i++)
dynamic_cast<pUnidad>(L[i])->setGeometry(0, 45*i, U->width(), U->height());
530
VOLVER A MEN
P->repaint();
repaint();
return true;
}
bool Cuadro::HayUnidad(int IdBase) {
Unidad *U;
if (IdBase < 1 || IdBase > 2) return false;
if (panelCol1->children().count() > 0) {
U = dynamic_cast<pUnidad>(panelCol1->children()[0]);
return U->ObtIdBase() == IdBase;
}
if (panelCol2->children().count() > 0) {
U = dynamic_cast<pUnidad>(panelCol2->children()[0]);
return U->ObtIdBase() == IdBase;
}
return false;
}
// Mtodos de la clase Campo
//
Campo::Campo(pConquista J, int f, int c, int uB1, int uB2)
: QFrame(J->ObtFormulario()) {
if (f <= 0) f = 1;
if (c <= 0) c = 1;
F = f; C = c;
refJuego = J;
this->setGeometry(10, 10, 90 * (C + 2) + 1, 135 * F + (F - 3));
this->setObjectName(tr(PanelCampo));
this->setVisible(true);
531
VOLVER A MEN
this->setFrameShape(Panel);
this->setFrameShadow(Plain);
this->setLineWidth(2);
Bases = new pBase[2];
Bases[0] = new Base(refJuego, Base0, 0, 0, uB1, F);
Bases[0]->setParent(this);
Bases[1] = new Base(refJuego, Base1, 90 * (C + 1), 0, uB2, F);
Bases[1]->setParent(this);
gridPanel = new QFrame(this);
gridPanel->setGeometry(Bases[0]->width(), 0, 90 * C, 135 * F + 10);
Cuadros = new pCuadro[F * C];
for (int i=0; i < F; i++) {
for (int j=0; j < C; j++) {
QString S = QString(Cuadro) + QString::number(i) + QString::number(j);
Cuadros[i * C + j] = new Cuadro(refJuego, S.toStdString(), j * 90, i * 135 + 10);
Cuadros[i * C + j]->setParent(gridPanel);
Cuadros[i * C + j]->setGeometry(j * 90, i * 135, 90, 135);
}
}
}
Campo::~Campo() {
int i, j;
if (Cuadros != NULL) {
for (i=0; i < F; i++) {
for (j=0; j < C; j++) {
if (Cuadros[i * C + j] != NULL) delete Cuadros[i * C + j];
}
}
532
VOLVER A MEN
delete Cuadros;
Cuadros = NULL;
}
if (Bases[0] != NULL) delete Bases[0];
if (Bases[1] != NULL) delete Bases[1];
if (gridPanel != NULL) delete gridPanel;
}
bool Campo::UbicarUnidad(pUnidad U, int f, int c) {
if (U == NULL || f < 0 || f >= F || c < 0 || c >= C) return false;
return Cuadros[f * F + c]->UbicarUnidad(U);
}
bool Campo::SacarUnidad(pUnidad U, int f, int c) {
if (U == NULL || f < 0 || f >= F || c < 0 || c >= C) return false;
return Cuadros[f * F + c]->SacarUnidad(U);
}
bool Campo::UbicarUnidad(pUnidad U, int b) {
if (U == NULL || b < 1 || b > 2) return false;
return Bases[b-1]->UbicarUnidad(U);
}
bool Campo::SacarUnidad(pUnidad U, int b) {
if (U == NULL || b < 1 || b > 2) return false;
return Bases[b-1]->SacarUnidad(U);
}
QPoint *Campo::ObtPosicionUnidad(pUnidad U) {
for (int i=0; i < F; i++) {
for (int j=0; j < C; j++) {
if (Cuadros[i * C + j]->EstaUnidad(U) != NULL)
return new QPoint(i, j);
}
533
VOLVER A MEN
}
return NULL;
}
void Campo::Limpiar() {
for (int i=0; i < F; i++)
for (int j=0; j < C; j++)
Cuadros[i * C + j]->Limpiar();
Bases[0]->Limpiar();
Bases[1]->Limpiar();
}
pEspacio Campo::BuscarUnidad(pUnidad U) {
int IdBase;
if (U == NULL) return NULL;
IdBase = U->ObtIdBase();
if (IdBase < 1 || IdBase > 2) return NULL;
// Primero se busca en alguna de las bases
//
if (Bases[IdBase - 1]->EstaUnidad(U) != NULL) return Bases[IdBase - 1];
// Si no est en las bases se busca en alguno de los cuadros
//
for (int i=0; i < F; i++)
for (int j=0; j < C; j++)
if (Cuadros[i * C + j]->EstaUnidad(U) != NULL) return Cuadros[i * C + j];
return NULL;
}
bool Campo::HayUnidad(int IdBase, QPoint *P) {
if (IdBase < 1 || IdBase > 2) return false;
534
VOLVER A MEN
if (P->x() < 0 || P->x() >= C || P->y() < 0 || P->y() >= F) return false;
return Cuadros[(int)(P->y() * F + P->x())]->HayUnidad(IdBase);
}
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Grupo.hpp
* Mauricio Paletta
*/
#ifndef GRUPO_HPP
#define GRUPO_HPP
#include <QtGui>
#include <cstdlib>
#include <time.h>
#include <vector>
#include DeclaracionesBase.hpp
namespace ConquistaNM {
class Unidad : public QFrame {
private:
TipoUnidad Tipo;
int Vida, IdBase;
bool EnBase, HizoOp;
pConquista refJuego;
QGraphicsView *graphicsView;
535
VOLVER A MEN
QGraphicsScene *ImagenUnidad;
QLabel *labelVida;
protected:
void mousePressEvent(QMouseEvent *M);
public:
Unidad(pConquista J, TipoUnidad T, int Id);
~Unidad();
TipoUnidad ObtTipo() { return Tipo; }
int ObtNivelVida() { return Vida; }
bool ObtPunteria(int A) {
double p;
switch (Tipo) {
case Infante:
p = 0.6;
break;
case Caballeria:
p = 0.75;
break;
default:
p = A == 2 ? 0.5 : 0.95;
break;
}
return (rand() / (double)RAND_MAX) <= p;
}
// En el caso de la caballera se asume primer nivel de
// visibilidad o alcance
//
int ObtAlcance() {
536
VOLVER A MEN
VOLVER A MEN
pConquista refJuego;
public:
Grupo(pConquista J, int id) : std::vector<pUnidad>() {
refJuego = J;
Id = id;
}
void AgregarUnidad(TipoUnidad T) {
this->push_back(new Unidad(refJuego, T, Id));
}
void AgregarUnidades(int C, TipoUnidad T) {
for (int i=0; i < C; i++) AgregarUnidad(T);
}
int ObtCantidad() { return this->size(); }
int ObtCantidadVivos();
void ColocarEnBase();
int ObtId() { return Id; }
void Refrescar();
void Normalizar();
bool TodosEnBase();
void Jugar();
};
typedef Grupo *pGrupo;
}
#endif /* GRUPO_HPP */
538
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Grupo.cpp
* Mauricio Paletta
*/
#include <typeinfo>
#include Grupo.hpp
#include Campo.hpp
#include Conquista.hpp
namespace ConquistaNM {
// Mtodos de la clase Unidad
//
Unidad::Unidad(pConquista J, TipoUnidad T, int Id)
: QFrame(J->ObtFormulario()) {
QPalette *palette = new QPalette();
refJuego = J;
Tipo = T;
// Para la generacin de nmeros aleatorios
//
time_t segundos;
time(&segundos);
srand((unsigned)segundos);
EnBase = true;
if (Tipo != Infante) Vida = 4;
else
if (Tipo != Caballeria) Vida = 5;
539
VOLVER A MEN
else
Vida = 6;
Normalizar();
IdBase = Id;
graphicsView = new QGraphicsView(this);
graphicsView->setGeometry(0, 0, 45, 45);
graphicsView->setVisible(true);
graphicsView->setCursor(Qt::PointingHandCursor);
ImagenUnidad = new QGraphicsScene();
graphicsView->setScene(ImagenUnidad);
graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
labelVida = new QLabel(this);
labelVida->setGeometry(2, 2, 10, 12);
labelVida->setText(QString(%1).arg(Vida));
palette->setColor(QPalette::Background, Qt::white);
labelVida->setPalette(*palette);
labelVida->setLayoutDirection(Qt::RightToLeft);
labelVida->setVisible(true);
this->setGeometry(0, 0, 45, 45);
this->setFrameShape(Panel);
this->setFrameShadow(Plain);
this->setLineWidth(1);
this->setVisible(true);
}
Unidad::~Unidad() {
if (labelVida != NULL) delete labelVida;
if (ImagenUnidad != NULL) delete ImagenUnidad;
if (graphicsView != NULL) delete graphicsView;
540
VOLVER A MEN
}
void Unidad::Mover() {
refJuego->ReproducirSonido(5);
HizoOp = true;
}
// Para seleccionar la unidad
// Solo es vlido para las unidades que se manejan manualmente
//
void Unidad::mousePressEvent(QMouseEvent *M) {
QPalette *palette = new QPalette();
// Si ya hizo una operacin, nada que hacer
//
if (HizoOp || !refJuego->JuegoIniciado()) return;
pUnidad U, S = this;
if (M->button() == Qt::LeftButton) {
// Si hay alguien seleccionado para atacar y se trata de
// bandos diferentes, entonces se concreta el ataque;
// si son del mismo bando o ya hay
// alguien seleccionado para mover,
// se cancela esta seleccin; si se trata de la misma
// unidad se cancela el inicio de la operacin
//
U = refJuego->ObtUnidadSeleccionadaAtacar();
if (U != NULL) {
if (U->ObtIdBase() != S->ObtIdBase()) {
refJuego->ConcretarAtaque(S);
return;
}
U->Normalizar();
541
VOLVER A MEN
refJuego->SeleccionarUnidadAtacar(NULL);
}
U = refJuego->ObtUnidadSeleccionadaMover();
if (U != NULL) {
if (U->ObtIdBase() != S->ObtIdBase()) return;
U->Normalizar();
refJuego->SeleccionarUnidadMover(NULL);
}
if (U != S) {
if (!refJuego->ValidarMovimientoManual(S)) return;
palette->setColor(QPalette::Foreground, Qt::blue);
S->setPalette(*palette);
refJuego->SeleccionarUnidadMover(S);
}
}
else
if (M->button() == Qt::RightButton) {
// Seleccionado para atacar
//
// Si hay alguien seleccionado para mover o ya hay
// alguien seleccionado para atacar,
// se cancela esta seleccin; si se trata de la misma
// unidad se cancela el inicio de la operacin
//
U = refJuego->ObtUnidadSeleccionadaMover();
if (U != NULL) {
U->Normalizar();
refJuego->SeleccionarUnidadMover(NULL);
}
U = refJuego->ObtUnidadSeleccionadaAtacar();
if (U != NULL) {
U->Normalizar();
refJuego->SeleccionarUnidadAtacar(NULL);
542
VOLVER A MEN
}
if (U != S) {
palette->setColor(QPalette::Foreground, Qt::red);
S->setPalette(*palette);
refJuego->SeleccionarUnidadAtacar(S);
}
}
}
void Unidad::Herir() {
if (EstaVivo()) Vida--;
labelVida->setText(QString(%1).arg(Vida));
if (!EstaVivo()) {
refJuego->ReproducirSonido(1);
this->setVisible(false);
}
else {
refJuego->ReproducirSonido(2);
}
labelVida->repaint();
repaint();
}
bool Unidad::Atacar(int A) {
if (HizoOp) return false;
HizoOp = true;
if (Tipo == Artilleria)
refJuego->ReproducirSonido(3);
else
refJuego->ReproducirSonido(4);
return ObtPunteria(A);
}
543
VOLVER A MEN
void Unidad::RefrescarImagen() {
std::string strImagen;
if (Tipo == Infante) strImagen = Infante;
else
if (Tipo == Caballeria) strImagen = Caballeria;
else
strImagen = Artilleria;
if (IdBase == 2) strImagen = strImagen + C.jpg;
else strImagen = strImagen + N.jpg;
ImagenUnidad->clear();
ImagenUnidad->addPixmap(QPixmap(strImagen.c_str()));
repaint();
}
// Mtodos de la clase Grupo
//
int Grupo::ObtCantidadVivos() {
int S = 0;
for (unsigned i=0; i < this->size(); i++) {
pUnidad U = (*this)[i];
if (U->EstaVivo() && U->isVisible()) S++;
}
return S;
}
void Grupo::ColocarEnBase() {
for (unsigned i=0; i < this->size(); i++)
(*this)[i]->EntrarBase();
}
void Grupo::Refrescar() {
for (unsigned i=0; i < this->size(); i++)
544
VOLVER A MEN
(*this)[i]->RefrescarImagen();
}
void Grupo::Normalizar() {
for (unsigned i=0; i < this->size(); i++)
(*this)[i]->Normalizar();
}
bool Grupo::TodosEnBase() {
for (unsigned i=0; i < this->size(); i++)
if (!((*this)[i]->EnSuBase())) return false;
return true;
}
void Grupo::Jugar() {
// El juego automtico se fundamente en las siguientes acciones:
// 1 - ganar ocupando la base del enemigo
// 2 - evitar que el enemigo gane abarcando territorio
// 3 - retirada si estn muy heridos
// 4 - abarcar territorio
//
// Para todas las unidades de este grupo
//
for (unsigned i=0; i < this->size(); i++) {
pUnidad U = (*this)[i], Ue;
pEspacio E;
if (U->isVisible() && U->EstaVivo()) {
E = refJuego->AbarcarTerritorio(U);
if (E != NULL && dynamic_cast<pBase>(E)) {
refJuego->SeleccionarUnidadMover(U);
refJuego->SeleccionarEspacioMover(E);
continue;
}
Ue = refJuego->DefenderTerritorio(U);
if (Ue != NULL) {
545
VOLVER A MEN
refJuego->SeleccionarUnidadAtacar(U);
refJuego->ConcretarAtaque(Ue);
continue;
}
if (U->ObtNivelVida() == 1) {
E = refJuego->Retirada(U);
if (E != NULL) {
refJuego->SeleccionarUnidadMover(U);
refJuego->SeleccionarEspacioMover(E);
continue;
}
}
E = refJuego->AbarcarTerritorio(U);
if (E != NULL) {
// Se tiene previsin de dejar un infante en la base
//
Base *B = refJuego->ObtBase(U->ObtIdBase());
if (!(U->EnSuBase() && U->ObtTipo() == Infante &&
B->ObtNumeroUnidades(Infante) == 1)) {
refJuego->SeleccionarUnidadMover(U);
refJuego->SeleccionarEspacioMover(E);
}
}
}
}
Normalizar();
}
}
546
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Conquista.hpp
* Mauricio Paletta
*/
#ifndef CONQUISTA_HPP
#define CONQUISTA_HPP
#include <QSound>
#include DeclaracionesBase.hpp
namespace ConquistaNM {
class Sonidos {
public:
void ReproducirSonidoMorir() {
QSound::play(Morir.wav);
}
void ReproducirSonidoHerido() {
QSound::play(Herido.wav);
}
void ReproducirSonidoDisparo1() {
QSound::play(Can.wav);
}
void ReproducirSonidoDisparo2() {
QSound::play(Disparo.wav);
}
void ReproducirSonidoAvance() {
QSound::play(Avance.wav);
}
};
547
VOLVER A MEN
class Conquista {
private:
pGrupo Conquistadores, Nativos;
bool LosNativos, Iniciado;
int Ganador;
pConquistaForm Frame;
pUnidad USeleccionadaMover, USeleccionadaAtacar;
Sonidos LosSonidos;
pCampo ElCampo;
public:
Conquista(pConquistaForm);
~Conquista();
QWidget *ObtFormulario();
void ConfigurarJuego();
void ConfigurarCampo(int f, int c);
void AsignarJuegoNativos() { LosNativos = true; }
void AsignarJuegoConquistadores() { LosNativos = false; }
bool EsJuegoNativos() { return LosNativos; }
bool EsJuegoConquistadores() { return !LosNativos; }
void AgregarConquistador(TipoUnidad T) {
Conquistadores->AgregarUnidad(T);
}
void AgregarConquistadores(int C, TipoUnidad T) {
Conquistadores->AgregarUnidades(C, T);
}
void AgregarNativo(TipoUnidad T) {
if (T == Artilleria) return;
Nativos->AgregarUnidad(T);
}
void AgregarNativos(int C, TipoUnidad T) {
if (T == Artilleria) return;
Nativos->AgregarUnidades(C, T);
548
VOLVER A MEN
}
int ObtNumeroConquistadores() { return Conquistadores->ObtCantidad(); }
int ObtNumeroNativos() { return Nativos->ObtCantidad(); }
Base *ObtBase(int IdBase);
void Limpiar();
void IniciarJuego() { Iniciado = true; }
bool JuegoIniciado() { return Iniciado; }
void SeleccionarUnidadMover(pUnidad U) {
if (Iniciado) USeleccionadaMover = U;
}
Unidad *ObtUnidadSeleccionadaMover() {
return USeleccionadaMover;
}
void SeleccionarUnidadAtacar(pUnidad U) {
if (Iniciado) USeleccionadaAtacar = U;
}
pUnidad ObtUnidadSeleccionadaAtacar() {
return USeleccionadaAtacar;
}
bool ValidarMovimientoManual() {
if (USeleccionadaMover == NULL) return false;
return (USeleccionadaMover->ObtIdBase() == 1 && !LosNativos) ||
(USeleccionadaMover->ObtIdBase() == 2 && LosNativos);
}
bool ValidarMovimientoManual(pUnidad U) {
return (U->ObtIdBase() == 1 && !LosNativos) ||
(U->ObtIdBase() == 2 && LosNativos);
}
bool ValidarAtaqueManual(pUnidad U) {
return (U->ObtIdBase() == 1 && !LosNativos) ||
(U->ObtIdBase() == 2 && LosNativos);
}
void SeleccionarEspacioMover(pEspacio E);
549
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
Ganador = 0;
Iniciado = false;
}
Conquista::~Conquista() {
if (Conquistadores != NULL) delete Conquistadores;
if (Nativos != NULL) delete Nativos;
if (ElCampo != NULL) delete ElCampo;
}
QWidget *Conquista::ObtFormulario() {
return Frame->centralWidget();
}
void Conquista::ConfigurarJuego() {
// Las unidades se colocan en la base
//
int i;
// Se limpia el campo
//
if (ElCampo != NULL) ElCampo->Limpiar();
// Se ubican las unidades en sus bases respectivas
// Nativos a la izquierda (base 1) y conquistadores a la derecha (base 2)
//
for (i=0; i < Nativos->ObtCantidad(); i++)
ElCampo->UbicarUnidad((*Nativos)[i], 1);
Nativos->ColocarEnBase();
for (i=0; i < Conquistadores->ObtCantidad(); i++)
ElCampo->UbicarUnidad((*Conquistadores)[i], 2);
Conquistadores->ColocarEnBase();
NormalizarGrupos();
552
VOLVER A MEN
Ganador = 0;
Frame->resize(ElCampo->width() + 20, ElCampo->height() + 110);
}
void Conquista::ConfigurarCampo(int f, int c) {
if (f <= 0) f = 1;
if (c <= 0) c = 1;
ElCampo = new Campo(this, f, c, ObtNumeroNativos(), ObtNumeroConquistadores());
Frame->resize(ElCampo->width() + 36, ElCampo->height() + 150);
ConfigurarJuego();
}
Base *Conquista::ObtBase(int IdBase) {
return dynamic_cast<pBase>(ElCampo->ObtBase(IdBase));
}
void Conquista::Limpiar() {
QObjectList L = Frame->children();
Conquistadores->clear();
Nativos->clear();
if (ElCampo != NULL) ElCampo->Limpiar();
L.removeAt(L.indexOf(ElCampo, 0));
USeleccionadaMover = USeleccionadaAtacar = NULL;
}
void Conquista::SeleccionarEspacioMover(pEspacio E) {
int IdBase, NCuadros;
bool Valido;
QPoint *Pact, *Pnue;
if (E == NULL || !Iniciado) return;
553
VOLVER A MEN
IdBase = E->ObtIdBase();
// Solo tiene sentido si actualmente hay una unidad para moverse
//
if (USeleccionadaMover == NULL || USeleccionadaMover->HizoOperacion()) return;
// El movimiento es posible si el espacio seleccionado no tiene una unidad
// enemiga y hay disponibilidad
//
if (IdBase > 0 && IdBase != USeleccionadaMover->ObtIdBase()) return;
// Se busca el espacio actual de la unidad seleccionada
//
pEspacio EUn = ElCampo->BuscarUnidad(USeleccionadaMover);
if (EUn == NULL || EUn == E) return;
// Se valida si el movimiento es posible; depende del tipo de unidad
//
NCuadros = (USeleccionadaMover->ObtTipo() == Infante) ? 1 : 2;
if (NCuadros > E->ObtDisponibilidad()) return;
if (USeleccionadaMover->EnSuBase()) {
Pnue = dynamic_cast<pCuadro>(E)->ObtPosicion();
if (Pnue == NULL) return;
Valido = (USeleccionadaMover->ObtIdBase() == 1 && Pnue->x() <= NCuadros - 1) ||
(USeleccionadaMover->ObtIdBase() == 2 && Pnue->x() >=
ElCampo->ObtNumColumnas() - NCuadros);
delete Pnue;
}
else {
if (E == ElCampo->ObtBase(1)) {
Pact = dynamic_cast<pCuadro>(EUn)->ObtPosicion();
if (Pact == NULL) return;
Valido = Pact->x() <= NCuadros - 1;
554
VOLVER A MEN
delete Pact;
}
else
if (E == ElCampo->ObtBase(2)) {
Pact = dynamic_cast<pCuadro>(EUn)->ObtPosicion();
if (Pact == NULL) return;
Valido = Pact->x() >= ElCampo->ObtNumColumnas() - NCuadros;
delete Pact;
}
else {
// Hay cuatro movimientos posibles: >, ^, v y <
//
Pact = dynamic_cast<pCuadro>(EUn)->ObtPosicion();
Pnue = dynamic_cast<pCuadro>(E)->ObtPosicion();
Valido = (Pact->y() == Pnue->y() && abs(Pact->x() - Pnue->x()) <= NCuadros) ||
(Pact->x() == Pnue->x() && abs(Pact->y() - Pnue->y()) <= NCuadros);
VOLVER A MEN
}
}
delete Pact;
delete Pnue;
}
}
// Si el movimiento es vlido se procede
//
if (Valido) {
// Se saca la unidad del espacio en la cual est actualmente
//
EUn->SacarUnidad(USeleccionadaMover);
// Se agrega la unidad al nuevo espacio
//
E->UbicarUnidad(USeleccionadaMover);
// Se normaliza la unidad movida
//
USeleccionadaMover->NormalizarSeleccion();
USeleccionadaMover = NULL;
}
}
// Concretar ataque (si es el caso)
//
void Conquista::ConcretarAtaque(pUnidad U) {
if (USeleccionadaAtacar == NULL || U == NULL || !Iniciado) return;
// Se valida que el ataque es posible
//
pEspacio E1 = ElCampo->BuscarUnidad(USeleccionadaAtacar),
E2 = ElCampo->BuscarUnidad(U);
556
VOLVER A MEN
VOLVER A MEN
if (!U->EstaVivo()) E2->SacarUnidad(U);
}
USeleccionadaAtacar->NormalizarSeleccion();
}
delete P1;
delete P2;
}
void Conquista::VerificarFinalizacion() {
if (!Iniciado) return;
// Ganan los nativos
//
if (Conquistadores->ObtCantidadVivos() == 0 || Conquistadores->TodosEnBase() ||
ElCampo->HayNativosBaseConquistadores()) Ganador = 1;
else
// Ganan los conquistadores
//
if (Nativos->ObtCantidadVivos() == 0 || Nativos->TodosEnBase() ||
ElCampo->HayConquistadoresBaseNativos()) Ganador = 2;
if (Ganador > 0) Iniciado = false;
}
pEspacio Conquista::AbarcarTerritorio(pUnidad U) {
// Buscar un espacio con la cual la unidad dada puede abarcar territorio
//
pEspacio E, Eaux, Emin = NULL;
QPoint *P;
int Max = 0;
bool Asignar;
if (U == NULL) return NULL;
E = ElCampo->BuscarUnidad(U);
558
VOLVER A MEN
ElCampo->ObtNumColumnas()-2);
if (Eaux->Vacio() || Eaux->ObtIdBase() == U->ObtIdBase()) {
if (Eaux->ObtDisponibilidad() > Max) Asignar = true;
else
if (Eaux->ObtDisponibilidad() == Max) Asignar = rand() >= RAND_MAX / 2;
}
}
if (!Asignar) {
Eaux = ElCampo->ObtCuadro(i, U->ObtIdBase() == 1 ? 0 :
ElCampo->ObtNumColumnas()-1);
if (Eaux->Vacio() || Eaux->ObtIdBase() == U->ObtIdBase()) {
if (Eaux->ObtDisponibilidad() > Max) Asignar = true;
else
if (Eaux->ObtDisponibilidad() == Max) Asignar = rand() >= RAND_MAX / 2;
}
}
if (Asignar && Eaux != NULL) {
Max = Eaux->ObtDisponibilidad();
Emin = Eaux;
}
}
if (Emin != NULL) return Emin;
}
P = E->ObtPosicion();
if (U->ObtIdBase() == 1) {
559
VOLVER A MEN
if (ElCampo->ObtBase(2)->Vacio() &&
((P->x() == ElCampo->ObtNumColumnas() - 1) ||
(P->x() == ElCampo->ObtNumColumnas() - 2 && U->ObtTipo() == Caballeria))) {
delete P;
return ElCampo->ObtBase(2);
}
if (U->ObtTipo() == Caballeria) {
Eaux = ElCampo->ObtCuadro(P->y(), P->x()+2);
if (Eaux != NULL && Eaux->Vacio()) {
delete P;
return Eaux;
}
}
Eaux = ElCampo->ObtCuadro(P->y(), P->x()+1);
if (Eaux != NULL && (Eaux->Vacio() || Eaux->ObtIdBase() == U->ObtIdBase())) {
delete P;
return Eaux;
}
}
else {
if (ElCampo->ObtBase(1)->Vacio() &&
((P->x() == 0) ||
(P->x() == 1 && U->ObtTipo() == Caballeria)))
return ElCampo->ObtBase(1);
if (U->ObtTipo() == Caballeria) {
Eaux = ElCampo->ObtCuadro(P->y(), P->x()-2);
if (Eaux != NULL && Eaux->Vacio()) {
delete P;
return Eaux;
}
}
Eaux = ElCampo->ObtCuadro(P->y(), P->x()-1);
if (Eaux != NULL && (Eaux->Vacio() || Eaux->ObtIdBase() == U->ObtIdBase())) {
560
VOLVER A MEN
delete P;
return Eaux;
}
}
delete P;
return NULL;
}
pUnidad Conquista::DefenderTerritorio(pUnidad U) {
// Verificar si los espacios adyacentes a la unidad dada hay un enemigo
// a fin de atacarlo. Se ataca el ms dbil
//
pEspacio E, Eaux;
QPoint *P;
if (U == NULL) return NULL;
E = ElCampo->BuscarUnidad(U);
if (E == NULL) return NULL;
P = E->ObtPosicion();
if (U->ObtIdBase() == 1) {
Eaux = ElCampo->ObtCuadro(P->y(), P->x()-1);
if (Eaux != NULL && !Eaux->Vacio() && Eaux->ObtIdBase() != U->ObtIdBase())
return Eaux->ObtMasDebil();
}
else {
Eaux = ElCampo->ObtCuadro(P->y(), P->x()+1);
if (Eaux != NULL && !Eaux->Vacio() && Eaux->ObtIdBase() != U->ObtIdBase())
return Eaux->ObtMasDebil();
}
Eaux = ElCampo->ObtCuadro(P->y()-1, P->x());
if (Eaux != NULL && !Eaux->Vacio() && Eaux->ObtIdBase() != U->ObtIdBase())
return Eaux->ObtMasDebil();
561
VOLVER A MEN
VOLVER A MEN
return Eaux;
}
else {
if (P->x() == ElCampo->ObtNumColumnas()-1) return ElCampo->ObtBase(2);
Eaux = ElCampo->ObtCuadro(P->y(), P->x()+1);
if (Eaux != NULL && (Eaux->Vacio() || Eaux->ObtIdBase() == U->ObtIdBase()))
return Eaux;
}
delete P;
return NULL;
}
void Conquista::ReproducirSonido(int S) {
switch (S) {
case 1:
LosSonidos.ReproducirSonidoMorir();
break;
case 2:
LosSonidos.ReproducirSonidoHerido();
break;
case 3:
LosSonidos.ReproducirSonidoDisparo1();
break;
case 4:
LosSonidos.ReproducirSonidoDisparo2();
break;
case 5:
LosSonidos.ReproducirSonidoAvance();
break;
}
}
}
563
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* DeclaracionesBase.hpp
* Mauricio Paletta
*/
#ifndef DECLARACIONESBASE_HPP
#define DECLARACIONESBASE_HPP
namespace ConquistaNM {
enum TipoUnidad {
Infante, Caballeria, Artilleria
};
class Unidad;
typedef Unidad *pUnidad;
class Grupo;
typedef Grupo *pGrupo;
class Espacio;
typedef Espacio *pEspacio;
class Base;
typedef Base *pBase;
class Cuadro;
typedef Cuadro *pCuadro;
class Campo;
typedef Campo *pCampo;
class Conquista;
564
VOLVER A MEN
El cdigo Java elaborado para este problema se muestra a continuacin. Tal como se indica
en la Figura 6.61, se tienen los archivos fuente Campo.java, Grupo.java y Conquista.java.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Campo.java
* Mauricio Paletta
*/
package ConquistaNuevoMundo;
import java.awt.*;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class Campo extends JPanel {
// Representa un espacio del campo donde van las unidades
//
protected abstract class Espacio extends JPanel {
private class EspacioMouseListener implements java.awt.event.MouseListener {
EspacioMouseListener() {
super();
565
VOLVER A MEN
}
@Override
public void mouseClicked(MouseEvent e) {
// Seleccionado para intentar ubicar una unidad
// Slo cuando se tratan de unidades manejadas por el jugador humano
//
if (e.getButton() == 1) {
JPanel P = (JPanel)e.getComponent();
Espacio E = P != null ? (Espacio)P.getParent() : null;
if (E != null &&
E.refJuego.ValidarMovimientoManual()) E.refJuego.SeleccionarEspacioMover(E);
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
protected int Disponibilidad;
protected Conquista refJuego;
protected JPanel panelCol1, panelCol2;
public Espacio(Conquista J, String n, int x, int y, int u, int f) {
566
VOLVER A MEN
super();
refJuego = J;
Dimension D = new Dimension(90, 135 * f);
if (u <= 0) u = 1;
Disponibilidad = u;
setPreferredSize(D);
setMinimumSize(D);
setMaximumSize(D);
setSize(D);
setName(n);
setLocation(x, y);
setBorder(BorderFactory.createLineBorder(Color.black));
setLayout(new GridLayout(1, 2));
setCursor(new Cursor(Cursor.HAND_CURSOR));
D = new Dimension(45, 135 * f);
panelCol1 = new JPanel();
panelCol1.setName(n + -Col1);
panelCol1.setPreferredSize(D);
panelCol1.setMinimumSize(D);
panelCol1.setMaximumSize(D);
panelCol1.setSize(D);
panelCol1.setLocation(0, 0);
panelCol1.setLayout(new GridLayout(3 * f, 1));
panelCol1.addMouseListener(new EspacioMouseListener());
panelCol1.setCursor(new Cursor(Cursor.HAND_CURSOR));
panelCol1.setVisible(true);
add(panelCol1);
panelCol2 = new JPanel();
panelCol2.setName(n + -Col2);
panelCol2.setPreferredSize(D);
panelCol2.setMinimumSize(D);
567
VOLVER A MEN
panelCol2.setMaximumSize(D);
panelCol2.setSize(D);
panelCol2.setLocation(45, 0);
panelCol2.setLayout(new GridLayout(3 * f, 1));
panelCol2.addMouseListener(new EspacioMouseListener());
panelCol2.setCursor(new Cursor(Cursor.HAND_CURSOR));
panelCol2.setVisible(true);
add(panelCol2);
// Para seleccionar el espacio
//
addMouseListener(new EspacioMouseListener());
setVisible(true);
repaint();
}
public final void Limpiar() {
if (panelCol1 != null) panelCol1.removeAll();
if (panelCol2 != null) panelCol2.removeAll();
}
public int ObtDisponibilidad() { return Disponibilidad; }
// Ubicar una unidad en el cuadro siempre y cuando no supere
// el mximo permitido: equivalente a 6 infantes
//
public abstract boolean UbicarUnidad(Grupo.Unidad U);
public abstract boolean SacarUnidad(Grupo.Unidad U);
public abstract Point ObtPosicion();
public JPanel EstaUnidad(Grupo.Unidad U) {
int i;
Component []C;
568
VOLVER A MEN
569
VOLVER A MEN
C = panelCol1.getComponents();
for (i=0; i < panelCol1.getComponentCount(); i++) {
U = (Grupo.Unidad)C[i];
if (U.ObtTipo().compareTo(T) == 0) S++;
}
C = panelCol2.getComponents();
for (i=0; i < panelCol2.getComponentCount(); i++) {
U = (Grupo.Unidad)C[i];
if (U.ObtTipo().compareTo(T) == 0) S++;
}
return S;
}
protected Grupo.Unidad ObtMasDebil() {
Grupo.Unidad U, MasDebil = null;
int i;
Component []C;
C = panelCol1.getComponents();
for (i=0; i < panelCol1.getComponentCount(); i++) {
U = (Grupo.Unidad)C[i];
if (MasDebil == null || U.ObtNivelVida() < MasDebil.ObtNivelVida())
MasDebil = U;
}
C = panelCol2.getComponents();
for (i=0; i < panelCol2.getComponentCount(); i++) {
U = (Grupo.Unidad)C[i];
if (MasDebil == null || U.ObtNivelVida() < MasDebil.ObtNivelVida())
MasDebil = U;
}
return MasDebil;
}
}
570
VOLVER A MEN
VOLVER A MEN
Disponibilidad--;
repaint();
return true;
}
public boolean SacarUnidad(Grupo.Unidad U) {
JPanel P = EstaUnidad(U);
if (U == null || P == null || U.HizoOperacion()) return false;
U.SalirBase();
P.remove(U);
Disponibilidad++;
P.repaint();
repaint();
return true;
}
public Point ObtPosicion() {
return new Point(getX(), getY());
}
public boolean HayUnidadEnemiga() {
Grupo.Unidad U;
int i, EstaBase = getX() <= 1 ? 1 : 2;
for (i=0; i < panelCol1.getComponentCount(); i++) {
U = (Grupo.Unidad)(panelCol1.getComponents()[i]);
if (U.ObtIdBase() != EstaBase) return true;
}
for (i=0; i < panelCol2.getComponentCount(); i++) {
U = (Grupo.Unidad)(panelCol2.getComponents()[i]);
if (U.ObtIdBase() != EstaBase) return true;
}
return false;
}
}
// Representa un cuadro/celda del campo
//
572
VOLVER A MEN
VOLVER A MEN
U.Refrescar();
Disponibilidad -= Requerido;
repaint();
return true;
}
public boolean SacarUnidad(Grupo.Unidad U) {
int Ocupado;
JPanel P = EstaUnidad(U);
if (U == null || P == null || U.HizoOperacion()) return false;
Ocupado = U.ObtTipo().compareTo(Grupo.TipoUnidad.Infante) == 0 ? 1 : 2;
P.remove(U);
Disponibilidad += Ocupado;
P.repaint();
repaint();
return true;
}
public Point ObtPosicion() {
return new Point(getX() / getWidth(), getY() / getHeight());
}
public boolean HayUnidad(int IdBase) {
Grupo.Unidad U;
if (IdBase < 1 || IdBase > 2) return false;
if (panelCol1.getComponentCount() > 0) {
U = (Grupo.Unidad)panelCol1.getComponents()[0];
return U.ObtIdBase() == IdBase;
}
if (panelCol2.getComponentCount() > 0) {
U = (Grupo.Unidad)panelCol2.getComponents()[0];
return U.ObtIdBase() == IdBase;
}
return false;
574
VOLVER A MEN
}
}
// Tamao del campo de batalla
//
private int F, C;
private Cuadro Cuadros[][];
private Base Bases[];
private JPanel gridPanel;
private Conquista refJuego;
public Campo(Conquista J, int f, int c, int uB1, int uB2) {
super();
if (f <= 0) f = 1;
if (c <= 0) c = 1;
F = f; C = c;
refJuego = J;
setSize(90 * (C + 2), 135 * F);
setLocation(10, 10);
setName(jPanelCampo);
setVisible(true);
setBorder(BorderFactory.createLineBorder(Color.black));
setLayout(new BorderLayout());
gridPanel = new JPanel(new GridLayout(F, C));
gridPanel.setSize(90 * C, 135 * F);
Bases = new Base[2];
Bases[0] = new Base(refJuego, Base0, 0, 0, uB1, F);
Bases[1] = new Base(refJuego, Base1, 90 * (C + 1), 0, uB2, F);
add(Bases[0], BorderLayout.WEST);
add(Bases[1], BorderLayout.EAST);
575
VOLVER A MEN
add(gridPanel, FlowLayout.CENTER);
Cuadros = new Cuadro[F][C];
for (int i=0; i < F; i++) {
for (int j=0; j < C; j++) {
Cuadros[i][j] = new Cuadro(refJuego, Cuadro + Integer.toString(i) + Integer.toString(j),
j * 90, i * 135);
gridPanel.add(Cuadros[i][j]);
}
}
}
public boolean UbicarUnidad(Grupo.Unidad U, int f, int c) {
if (U == null || f < 0 || f >= F || c < 0 || c >= C) return false;
return Cuadros[f][c].UbicarUnidad(U);
}
public boolean SacarUnidad(Grupo.Unidad U, int f, int c) {
if (U == null || f < 0 || f >= F || c < 0 || c >= C) return false;
return Cuadros[f][c].SacarUnidad(U);
}
public boolean UbicarUnidad(Grupo.Unidad U, int b) {
if (U == null || b < 1 || b > 2) return false;
return Bases[b-1].UbicarUnidad(U);
}
public boolean SacarUnidad(Grupo.Unidad U, int b) {
if (U == null || b < 1 || b > 2) return false;
return Bases[b-1].SacarUnidad(U);
}
public Point ObtPosicionUnidad(Grupo.Unidad U) {
for (int i=0; i < F; i++) {
for (int j=0; j < C; j++) {
if (Cuadros[i][j].EstaUnidad(U) != null)
return new Point(i, j);
}
576
VOLVER A MEN
}
return null;
}
public void Limpiar() {
for (int i=0; i < F; i++)
for (int j=0; j < C; j++)
Cuadros[i][j].Limpiar();
Bases[0].Limpiar();
Bases[1].Limpiar();
}
public Espacio BuscarUnidad(Grupo.Unidad U) {
int IdBase;
if (U == null) return null;
IdBase = U.ObtIdBase();
if (IdBase < 1 || IdBase > 2) return null;
// Primero se busca en alguna de las bases
//
if (Bases[IdBase - 1].EstaUnidad(U) != null) return Bases[IdBase - 1];
// Si no est en las bases se busca en alguno de los cuadros
//
for (int i=0; i < F; i++)
for (int j=0; j < C; j++)
if (Cuadros[i][j].EstaUnidad(U) != null) return Cuadros[i][j];
return null;
}
public boolean HayUnidad(int IdBase, Point P) {
if (IdBase < 1 || IdBase > 2) return false;
if (P.X < 0 || P.X >= C || P.Y < 0 || P.Y >= F) return false;
return Cuadros[P.Y][P.X].HayUnidad(IdBase);
}
577
VOLVER A MEN
VOLVER A MEN
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Grupo extends ArrayList<Grupo.Unidad> {
public enum TipoUnidad {
Infante, Caballeria, Artilleria
}
protected class Unidad extends JPanel {
private TipoUnidad Tipo;
private int Vida, IdBase;
private Random R;
private boolean EnBase, HizoOp;
private Conquista refJuego;
private BufferedImage Imagen;
private JLabel labelImagen, labelVida;
public Unidad(Conquista J, TipoUnidad T, int Id) {
super();
refJuego = J;
Dimension D;
Tipo = T;
R = new Random();
579
VOLVER A MEN
R.setSeed((new Date()).getTime());
EnBase = true;
if (Tipo.compareTo(TipoUnidad.Infante) != 0) Vida = 4;
else
if (Tipo.compareTo(TipoUnidad.Caballeria) != 0) Vida = 5;
else
Vida = 6;
Normalizar();
IdBase = Id;
labelImagen = new JLabel();
D = new Dimension(45, 45);
labelImagen.setSize(D);
labelImagen.setPreferredSize(D);
labelImagen.setMinimumSize(D);
labelImagen.setMaximumSize(D);
labelImagen.setBorder(BorderFactory.createLineBorder(Color.black));
labelImagen.setVisible(true);
labelVida = new JLabel();
D = new Dimension(14, 14);
labelVida.setText(Integer.toString(Vida));
labelVida.setSize(D);
labelVida.setPreferredSize(D);
labelVida.setMinimumSize(D);
labelVida.setMaximumSize(D);
labelVida.setVisible(true);
D = new Dimension(labelImagen.getWidth(), labelVida.getHeight() + labelImagen.getHeight());
setSize(D);
setPreferredSize(D);
setMinimumSize(D);
setMaximumSize(D);
setLayout(new BorderLayout());
580
VOLVER A MEN
setBorder(BorderFactory.createLineBorder(Color.black));
add(labelVida, BorderLayout.PAGE_START);
add(labelImagen, BorderLayout.PAGE_END);
setCursor(new Cursor(Cursor.HAND_CURSOR));
// Para seleccionar la unidad
// Solo es vlido para las unidades que se manejan manualmente
//
addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
// Si ya hizo una operacin, nada que hacer
//
if (HizoOp || !refJuego.JuegoIniciado()) return;
Unidad U, S = (Unidad)e.getComponent();
switch (e.getButton()) {
// Seleccionado para moverse
//
case 1:
// Si hay alguien seleccionado para atacar y se trata de
// bandos diferentes, entonces se concreta el ataque;
// si son del mismo bando o ya hay
// alguien seleccionado para mover,
// se cancela esta seleccin; si se trata de la misma
// unidad se cancela el inicio de la operacin
//
U = refJuego.ObtUnidadSeleccionadaAtacar();
if (U != null) {
if (U.ObtIdBase() != S.ObtIdBase()) {
refJuego.ConcretarAtaque(S);
return;
581
VOLVER A MEN
}
U.Normalizar();
refJuego.SeleccionarUnidadAtacar(null);
}
U = refJuego.ObtUnidadSeleccionadaMover();
if (U != null) {
if (U.ObtIdBase() != S.ObtIdBase()) {
return;
}
U.Normalizar();
refJuego.SeleccionarUnidadMover(null);
}
if (U != S) {
if (!refJuego.ValidarMovimientoManual(S)) return;
setBorder(BorderFactory.createLineBorder(Color.blue));
refJuego.SeleccionarUnidadMover(S);
}
break;
// Seleccionado para atacar
//
case 3:
// Si hay alguien seleccionado para mover o ya hay
// alguien seleccionado para atacar,
// se cancela esta seleccin; si se trata de la misma
// unidad se cancela el inicio de la operacin
//
U = refJuego.ObtUnidadSeleccionadaMover();
if (U != null) {
U.Normalizar();
refJuego.SeleccionarUnidadMover(null);
}
U = refJuego.ObtUnidadSeleccionadaAtacar();
if (U != null) {
582
VOLVER A MEN
U.Normalizar();
refJuego.SeleccionarUnidadAtacar(null);
}
if (U != S) {
setBorder(BorderFactory.createLineBorder(Color.red));
refJuego.SeleccionarUnidadAtacar(S);
}
break;
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
});
setVisible(false);
}
public TipoUnidad ObtTipo() { return Tipo; }
public int ObtNivelVida() { return Vida; }
public boolean ObtPunteria(int A) {
double p;
switch (Tipo) {
case Infante:
583
VOLVER A MEN
p = 0.6;
break;
case Caballeria:
p = 0.75;
break;
default:
p = A == 2 ? 0.5 : 0.95;
break;
}
return R.nextDouble() <= p;
}
// En el caso de la caballera se asume primer nivel de
// visibilidad o alcance
//
public int ObtAlcance() {
return Tipo.compareTo(TipoUnidad.Caballeria) == 0 ? 2 : 1;
}
public boolean EstaVivo() { return Vida > 0; }
public void Herir() {
if (EstaVivo()) Vida--;
labelVida.setText(Integer.toString(Vida));
if (!EstaVivo()) {
refJuego.ReproducirSonido(1);
setVisible(false);
}
else {
refJuego.ReproducirSonido(2);
}
labelVida.repaint();
repaint();
}
public boolean Atacar(int A) {
584
VOLVER A MEN
VOLVER A MEN
else
strImagen = Artilleria;
if (IdBase == 2) strImagen = strImagen + C.jpg;
else strImagen = strImagen + N.jpg;
Imagen = ImageIO.read(new File(strImagen));
labelImagen.setIcon(new ImageIcon(Imagen));
repaint();
} catch (IOException ex) { }
}
public void Refrescar() {
RefrescarImagen();
setVisible(true);
}
}
private int Id;
private Conquista refJuego;
public Grupo(Conquista J, int id) {
super();
refJuego = J;
Id = id;
}
public void AgregarUnidad(TipoUnidad T) {
add(new Unidad(refJuego, T, Id));
}
public void AgregarUnidades(int C, TipoUnidad T) {
for (int i=0; i < C; i++) AgregarUnidad(T);
}
public int ObtCantidad() { return size(); }
public int ObtCantidadVivos() {
586
VOLVER A MEN
int S = 0;
for (int i=0; i < size(); i++) {
Unidad U = get(i);
if (U.EstaVivo() && U.isVisible()) S++;
}
return S;
}
public void ColocarEnBase() {
for (int i=0; i < size(); i++) {
get(i).EntrarBase();
}
}
public int ObtId() { return Id; }
public void Refrescar() {
for (int i=0; i < size(); i++) {
get(i).RefrescarImagen();
}
}
public void Normalizar() {
for (int i=0; i < size(); i++) {
get(i).Normalizar();
}
}
public boolean TodosEnBase() {
for (int i=0; i < size(); i++) {
if (!(get(i).EnSuBase())) return false;
}
return true;
}
protected void Jugar() {
// El juego automtico se fundamente en las siguientes acciones:
// 1 - ganar ocupando la base del enemigo
587
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
}
}
public void ReproducirSonidoHerido() {
try {
SonidoHerido.setFramePosition(0);
SonidoHerido.start();
while (SonidoHerido.isRunning()) Thread.sleep(Retardo);
} catch (InterruptedException ex) {
Logger.getLogger(Grupo.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void ReproducirSonidoDisparo1() {
try {
SonidoDisparo1.setFramePosition(0);
SonidoDisparo1.start();
while (SonidoDisparo1.isRunning()) Thread.sleep(Retardo);
} catch (InterruptedException ex) {
Logger.getLogger(Grupo.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void ReproducirSonidoDisparo2() {
try {
SonidoDisparo2.setFramePosition(0);
SonidoDisparo2.start();
while (SonidoDisparo2.isRunning()) Thread.sleep(Retardo);
} catch (InterruptedException ex) {
Logger.getLogger(Grupo.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void ReproducirSonidoAvance() {
try {
SonidoAvance.setFramePosition(0);
SonidoAvance.start();
591
VOLVER A MEN
592
VOLVER A MEN
// Se limpia el campo
//
if (ElCampo != null) ElCampo.Limpiar();
// Se ubican las unidades en sus bases respectivas
// Nativos a la izquierda (base 1) y conquistadores a la derecha (base 2)
//
for (i=0; i < Nativos.ObtCantidad(); i++)
ElCampo.UbicarUnidad(Nativos.get(i), 1);
Nativos.ColocarEnBase();
for (i=0; i < Conquistadores.ObtCantidad(); i++)
ElCampo.UbicarUnidad(Conquistadores.get(i), 2);
Conquistadores.ColocarEnBase();
NormalizarGrupos();
Ganador = 0;
}
public void ConfigurarCampo(int f, int c) {
if (f <= 0) f = 1;
if (c <= 0) c = 1;
ElCampo = new Campo(this, f, c, ObtNumeroNativos(), ObtNumeroConquistadores());
Frame.add(ElCampo);
Frame.setSize(ElCampo.getWidth() + 36, ElCampo.getHeight() + 150);
ConfigurarJuego();
}
public void AsignarJuegoNativos() { LosNativos = true; }
public void AsignarJuegoConquistadores() { LosNativos = false; }
public boolean EsJuegoNativos() { return LosNativos; }
public boolean EsJuegoConquistadores() { return !LosNativos; }
public void AgregarConquistador(Grupo.TipoUnidad T) {
Conquistadores.AgregarUnidad(T);
593
VOLVER A MEN
}
public void AgregarConquistadores(int C, Grupo.TipoUnidad T) {
Conquistadores.AgregarUnidades(C, T);
}
public void AgregarNativo(Grupo.TipoUnidad T) {
if (T.compareTo(TipoUnidad.Artilleria) == 0) return;
Nativos.AgregarUnidad(T);
}
public void AgregarNativos(int C, Grupo.TipoUnidad T) {
if (T.compareTo(TipoUnidad.Artilleria) == 0) return;
Nativos.AgregarUnidades(C, T);
}
public int ObtNumeroConquistadores() { return Conquistadores.ObtCantidad(); }
public int ObtNumeroNativos() { return Nativos.ObtCantidad(); }
public void Limpiar() {
Conquistadores.clear();
Nativos.clear();
if (ElCampo != null) ElCampo.Limpiar();
Frame.remove(ElCampo);
USeleccionadaMover = USeleccionadaAtacar = null;
}
public void IniciarJuego() { Iniciado = true; }
public boolean JuegoIniciado() { return Iniciado; }
protected void SeleccionarUnidadMover(Grupo.Unidad U) {
if (Iniciado) USeleccionadaMover = U;
}
protected Grupo.Unidad ObtUnidadSeleccionadaMover() {
return USeleccionadaMover;
}
protected void SeleccionarUnidadAtacar(Grupo.Unidad U) {
if (Iniciado) USeleccionadaAtacar = U;
594
VOLVER A MEN
}
protected Grupo.Unidad ObtUnidadSeleccionadaAtacar() {
return USeleccionadaAtacar;
}
public boolean ValidarMovimientoManual() {
if (USeleccionadaMover == null) return false;
return (USeleccionadaMover.ObtIdBase() == 1 && !LosNativos) ||
(USeleccionadaMover.ObtIdBase() == 2 && LosNativos);
}
public boolean ValidarMovimientoManual(Grupo.Unidad U) {
return (U.ObtIdBase() == 1 && !LosNativos) ||
(U.ObtIdBase() == 2 && LosNativos);
}
public boolean ValidarAtaqueManual(Grupo.Unidad U) {
return (U.ObtIdBase() == 1 && !LosNativos) ||
(U.ObtIdBase() == 2 && LosNativos);
}
protected void SeleccionarEspacioMover(Campo.Espacio E) {
int IdBase, NCuadros;
boolean Valido;
Point Pact, Pnue;
if (E == null || !Iniciado) return;
IdBase = E.ObtIdBase();
// Solo tiene sentido si actualmente hay una unidad para moverse
//
if (USeleccionadaMover == null || USeleccionadaMover.HizoOperacion()) return;
// El movimiento es posible si el espacio seleccionado no tiene una unidad
// enemiga y hay disponibilidad
//
595
VOLVER A MEN
NCuadros = (USeleccionadaMover.ObtTipo().compareTo(Grupo.TipoUnidad.Infante) == 0) ? 1 :
VOLVER A MEN
VOLVER A MEN
EUn.SacarUnidad(USeleccionadaMover);
// Se agrega la unidad al nuevo espacio
//
E.UbicarUnidad(USeleccionadaMover);
// Se normaliza la unidad movida
//
USeleccionadaMover.NormalizarSeleccion();
USeleccionadaMover = null;
}
}
// Concretar ataque (si es el caso)
//
protected void ConcretarAtaque(Grupo.Unidad U) {
if (USeleccionadaAtacar == null || U == null || !Iniciado) return;
Campo.Espacio E1 = ElCampo.BuscarUnidad(USeleccionadaAtacar),
E2 = ElCampo.BuscarUnidad(U);
Point P1 = E1.ObtPosicion(), P2 = E2.ObtPosicion();
boolean Valido;
if (USeleccionadaAtacar.EnSuBase()) {
Valido = (USeleccionadaAtacar.ObtIdBase() == 1 && P2.x == 0) ||
(USeleccionadaAtacar.ObtIdBase() == 1 &&
USeleccionadaAtacar.ObtTipo().compareTo(Grupo.TipoUnidad.Artilleria) == 0 &&
P2.x <= 1) ||
(USeleccionadaAtacar.ObtIdBase() == 2 &&
P2.x == ElCampo.ObtNumColumnas() - 1) ||
(USeleccionadaAtacar.ObtIdBase() == 2 &&
USeleccionadaAtacar.ObtTipo().compareTo(Grupo.TipoUnidad.Artilleria) == 0 &&
P2.x >= ElCampo.ObtNumColumnas() - 2);
}
598
VOLVER A MEN
else
if (U.EnSuBase()) {
Valido = (U.ObtIdBase() == 1 && P1.x == 0) || (U.ObtIdBase() == 1 &&
USeleccionadaAtacar.ObtTipo().compareTo(Grupo.TipoUnidad.Artilleria) == 0 &&
P1.x <= 1) ||
(U.ObtIdBase() == 2 && P1.x == ElCampo.ObtNumColumnas() - 1) ||
(U.ObtIdBase() == 2 &&
USeleccionadaAtacar.ObtTipo().compareTo(Grupo.TipoUnidad.Artilleria) == 0 &&
P1.x >= ElCampo.ObtNumColumnas() - 2);
}
else {
Valido = (P1.y == P2.y && Math.abs(P1.x - P2.x) == 1) ||
(P1.y == P2.y &&
USeleccionadaAtacar.ObtTipo().compareTo(Grupo.TipoUnidad.Artilleria) == 0 &&
Math.abs(P1.x - P2.x) == 2) ||
(P1.x == P2.x &&
USeleccionadaAtacar.ObtTipo().compareTo(Grupo.TipoUnidad.Artilleria) != 0 &&
Math.abs(P1.y - P2.y) == 1);
}
if (Valido) {
int A = 1;
if (P1.y == P2.y &&
USeleccionadaAtacar.ObtTipo().compareTo(Grupo.TipoUnidad.Artilleria) == 0 &&
Math.abs(P1.x - P2.x) == 2) A = 2;
if (USeleccionadaAtacar.Atacar(A)) {
U.Herir();
if (!U.EstaVivo()) E2.SacarUnidad(U);
}
USeleccionadaAtacar.NormalizarSeleccion();
}
}
// Normalizar los grupos
//
599
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
if (U.ObtIdBase() == 1) {
Eaux = ElCampo.ObtCuadro(P.y, P.x+1);
if (Eaux != null && !Eaux.Vacio() && Eaux.ObtIdBase() != U.ObtIdBase())
return Eaux.ObtMasDebil();
}
else {
Eaux = ElCampo.ObtCuadro(P.y, P.x-1);
if (Eaux != null && !Eaux.Vacio() && Eaux.ObtIdBase() != U.ObtIdBase())
return Eaux.ObtMasDebil();
}
return null;
}
protected Campo.Espacio Retirada(Grupo.Unidad U) {
// Provocar la retirada de la unidad
//
if (U == null || U.EnSuBase()) return null;
Campo.Espacio E, Eaux;
Point P;
E = ElCampo.BuscarUnidad(U);
if (E == null) return null;
P = E.ObtPosicion();
if (U.ObtIdBase() == 1) {
if (P.x == 0) return ElCampo.ObtBase(1);
Eaux = ElCampo.ObtCuadro(P.y, P.x-1);
if (Eaux != null && (Eaux.Vacio() || Eaux.ObtIdBase() == U.ObtIdBase()))
return Eaux;
}
else {
if (P.x == ElCampo.ObtNumColumnas()-1) return ElCampo.ObtBase(2);
Eaux = ElCampo.ObtCuadro(P.y, P.x+1);
if (Eaux != null && (Eaux.Vacio() || Eaux.ObtIdBase() == U.ObtIdBase()))
604
VOLVER A MEN
return Eaux;
}
return null;
}
protected void ReproducirSonido(int S) {
switch (S) {
case 1:
LosSonidos.ReproducirSonidoMorir();
break;
case 2:
LosSonidos.ReproducirSonidoHerido();
break;
case 3:
LosSonidos.ReproducirSonidoDisparo1();
break;
case 4:
LosSonidos.ReproducirSonidoDisparo2();
break;
case 5:
LosSonidos.ReproducirSonidoAvance();
break;
}
}
}
605
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Campo.cs
* Mauricio Paletta
*/
using System;
using System.Windows.Forms;
using System.Drawing;
namespace Conquista
{
// Representa un espacio del campo donde van las unidades
//
public abstract class Espacio : Panel
{
protected int Disponibilidad;
protected Conquista refJuego;
protected Panel panelCol1, panelCol2;
public Espacio(Conquista J, string n, int x, int y, int u, int f) : base()
{
refJuego = J;
if (u <= 0) u = 1;
Disponibilidad = u;
this.Width = 90;
this.Height = 135 * f;
this.Name = n;
this.Location = new Point(x, y);
this.BorderStyle = BorderStyle.FixedSingle;
this.Cursor = Cursors.Hand;
606
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
return null;
}
public int ObtIdBase()
{
if (panelCol1.Controls.Count != 0)
return ((Unidad)(panelCol1.Controls[0])).ObtIdBase();
if (panelCol2.Controls.Count != 0)
return ((Unidad)(panelCol2.Controls[0])).ObtIdBase();
return 0;
}
public bool Vacio()
{
return panelCol1.Controls.Count == 0 && panelCol2.Controls.Count == 0;
}
public int ObtNumeroUnidades()
{
return panelCol1.Controls.Count + panelCol2.Controls.Count;
}
public int ObtNumeroUnidades(TipoUnidad T)
{
int i, S = 0;
Unidad U;
for (i=0; i < panelCol1.Controls.Count; i++)
{
U = (Unidad)panelCol1.Controls[i];
if (U.ObtTipo() == T) S++;
}
for (i=0; i < panelCol2.Controls.Count; i++)
{
U = (Unidad)panelCol2.Controls[i];
if (U.ObtTipo() == T) S++;
}
609
VOLVER A MEN
return S;
}
public Unidad ObtMasDebil()
{
Unidad U, MasDebil = null;
int i;
for (i=0; i < panelCol1.Controls.Count; i++)
{
U = (Unidad)panelCol1.Controls[i];
if (MasDebil == null || U.ObtNivelVida() < MasDebil.ObtNivelVida())
MasDebil = U;
}
for (i=0; i < panelCol2.Controls.Count; i++)
{
U = (Unidad)panelCol2.Controls[i];
if (MasDebil == null || U.ObtNivelVida() < MasDebil.ObtNivelVida())
MasDebil = U;
}
return MasDebil;
}
}
// Representa una base
//
public class Base : Espacio
{
public Base(Conquista J, String n, int x, int y, int u, int f) :
base(J, n, x, y, u, f) { }
// Ubicar una unidad en la base
//
public override bool UbicarUnidad(Unidad U)
610
VOLVER A MEN
{
int i, u;
if (U == null || Disponibilidad == 0 || U.HizoOperacion()) return false;
i = panelCol1.Controls.Count;
u = panelCol1.Height / 45;
if (i < u)
{
panelCol1.Controls.Add(U);
panelCol1.Refresh();
}
else
{
i = panelCol2.Controls.Count;
u = panelCol2.Height / 45;
if (i < u)
{
panelCol2.Controls.Add(U);
panelCol2.Refresh();
}
else
return false;
}
U.EntrarBase();
U.Refrescar();
Disponibilidad--;
Refresh();
return true;
}
public override bool SacarUnidad(Unidad U)
{
Panel P = EstaUnidad(U);
if (U == null || P == null || U.HizoOperacion()) return false;
611
VOLVER A MEN
U.SalirBase();
P.Controls.Remove(U);
Disponibilidad++;
P.Refresh();
Refresh();
return true;
}
public override Point ObtPosicion()
{
return new Point(this.Location.X, this.Location.Y);
}
public bool HayUnidadEnemiga()
{
Unidad U;
int i, EstaBase = Location.X <= 1 ? 1 : 2;
for (i=0; i < panelCol1.Controls.Count; i++)
{
U = (Unidad)(panelCol1.Controls[i]);
if (U.ObtIdBase() != EstaBase) return true;
}
for (i=0; i < panelCol2.Controls.Count; i++)
{
U = (Unidad)(panelCol2.Controls[i]);
if (U.ObtIdBase() != EstaBase) return true;
}
return false;
}
}
// Representa un cuadro/celda del campo
//
public class Cuadro : Espacio
{
612
VOLVER A MEN
VOLVER A MEN
U.Refrescar();
Disponibilidad -= Requerido;
Refresh();
return true;
}
public override bool SacarUnidad(Unidad U)
{
int Ocupado;
Panel P = EstaUnidad(U);
if (U == null || P == null || U.HizoOperacion()) return false;
Ocupado = U.ObtTipo() == TipoUnidad.Infante ? 1 : 2;
P.Controls.Remove(U);
Disponibilidad += Ocupado;
P.Refresh();
Refresh();
return true;
}
public override Point ObtPosicion()
{
return new Point(Location.X / Width, Location.Y / Height);
}
public bool HayUnidad(int IdBase)
{
Unidad U;
if (IdBase < 1 || IdBase > 2) return false;
if (panelCol1.Controls.Count > 0)
{
U = (Unidad)panelCol1.Controls[0];
return U.ObtIdBase() == IdBase;
}
if (panelCol2.Controls.Count > 0)
614
VOLVER A MEN
{
U = (Unidad)panelCol2.Controls[0];
return U.ObtIdBase() == IdBase;
}
return false;
}
}
public class Campo : Panel
{
// Tamao del campo de batalla
//
private int F, C;
private Cuadro [,]Cuadros;
private Base []Bases;
private Panel gridPanel;
private Conquista refJuego;
public Campo(Conquista J, int f, int c, int uB1, int uB2) : base()
{
if (f <= 0) f = 1;
if (c <= 0) c = 1;
F = f; C = c;
refJuego = J;
Width = 90 * (C + 2) + 1;
Height = 135 * F + F;
Location = new Point(20, 40);
Name = PanelCampo;
Visible = true;
BorderStyle = BorderStyle.FixedSingle;
gridPanel = new Panel();
615
VOLVER A MEN
gridPanel.Width = 90 * C;
gridPanel.Height = 135 * F + 10;
gridPanel.Dock = DockStyle.Left;
Controls.Add(gridPanel);
Bases = new Base[2];
Bases[0] = new Base(refJuego, Base0, 0, 0, uB1, F);
Bases[0].Dock = DockStyle.Left;
Bases[1] = new Base(refJuego, Base1, 90 * (C + 1), 0, uB2, F);
Bases[1].Dock = DockStyle.Right;
Controls.Add(Bases[0]);
Controls.Add(Bases[1]);
Cuadros = new Cuadro[F, C];
for (int i=0; i < F; i++) {
for (int j=0; j < C; j++) {
Cuadros[i, j] = new Cuadro(refJuego, Cuadro + Convert.ToString(i) +
Convert.ToString(j), j * 90, i * 135);
gridPanel.Controls.Add(Cuadros[i, j]);
}
}
}
public bool UbicarUnidad(Unidad U, int f, int c)
{
if (U == null || f < 0 || f >= F || c < 0 || c >= C) return false;
return Cuadros[f, c].UbicarUnidad(U);
}
public bool SacarUnidad(Unidad U, int f, int c)
{
if (U == null || f < 0 || f >= F || c < 0 || c >= C) return false;
return Cuadros[f, c].SacarUnidad(U);
}
public bool UbicarUnidad(Unidad U, int b)
616
VOLVER A MEN
{
if (U == null || b < 1 || b > 2) return false;
return Bases[b-1].UbicarUnidad(U);
}
public bool SacarUnidad(Unidad U, int b)
{
if (U == null || b < 1 || b > 2) return false;
return Bases[b-1].SacarUnidad(U);
}
public Point ObtPosicionUnidad(Unidad U)
{
for (int i=0; i < F; i++)
{
for (int j=0; j < C; j++)
{
if (Cuadros[i, j].EstaUnidad(U) != null)
return new Point(i, j);
}
}
return new Point(-1, -1);
}
public void Limpiar()
{
for (int i=0; i < F; i++)
for (int j=0; j < C; j++)
Cuadros[i, j].Limpiar();
Bases[0].Limpiar();
Bases[1].Limpiar();
}
public Espacio BuscarUnidad(Unidad U)
{
int IdBase;
617
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
U = refJuego.ObtUnidadSeleccionadaAtacar();
if (U != null)
{
if (U.ObtIdBase() != S.ObtIdBase())
{
refJuego.ConcretarAtaque(S);
return;
}
U.Normalizar();
refJuego.SeleccionarUnidadAtacar(null);
}
U = refJuego.ObtUnidadSeleccionadaMover();
if (U != null)
{
if (U.ObtIdBase() != S.ObtIdBase()) return;
U.Normalizar();
refJuego.SeleccionarUnidadMover(null);
}
if (U != S)
{
if (!refJuego.ValidarMovimientoManual(S)) return;
S.BackColor = Color.Blue;
refJuego.SeleccionarUnidadMover(S);
}
break;
// Seleccionado para atacar
//
case MouseButtons.Right:
// Si hay alguien seleccionado para mover o ya hay
// alguien seleccionado para atacar,
// se cancela esta seleccin; si se trata de la misma
// unidad se cancela el inicio de la operacin
//
622
VOLVER A MEN
U = refJuego.ObtUnidadSeleccionadaMover();
if (U != null)
{
U.Normalizar();
refJuego.SeleccionarUnidadMover(null);
}
U = refJuego.ObtUnidadSeleccionadaAtacar();
if (U != null)
{
U.Normalizar();
refJuego.SeleccionarUnidadAtacar(null);
}
if (U != S)
{
S.BackColor = Color.Red;
refJuego.SeleccionarUnidadAtacar(S);
}
break;
}
}
public TipoUnidad ObtTipo() { return Tipo; }
public int ObtNivelVida() { return Vida; }
public bool ObtPunteria(int A)
{
double p;
switch (Tipo) {
case TipoUnidad.Infante:
p = 0.6;
break;
case TipoUnidad.Caballeria:
p = 0.75;
623
VOLVER A MEN
break;
default:
p = A == 2 ? 0.5 : 0.95;
break;
}
return R.NextDouble() <= p;
}
// En el caso de la caballera se asume primer nivel de
// visibilidad o alcance
//
public int ObtAlcance()
{
return Tipo == TipoUnidad.Caballeria ? 2 : 1;
}
public bool EstaVivo() { return Vida > 0; }
public void Herir()
{
if (EstaVivo()) Vida--;
labelVida.Text = Convert.ToString(Vida);
if (!EstaVivo())
{
refJuego.ReproducirSonido(1);
Visible = false;
}
else
{
refJuego.ReproducirSonido(2);
}
labelVida.Refresh();
Refresh();
}
public bool Atacar(int A)
624
VOLVER A MEN
{
if (HizoOp) return false;
HizoOp = true;
if (Tipo == TipoUnidad.Artilleria)
refJuego.ReproducirSonido(3);
else
refJuego.ReproducirSonido(4);
return ObtPunteria(A);
}
public void Mover()
{
refJuego.ReproducirSonido(5);
HizoOp = true;
}
public bool HizoOperacion() { return HizoOp; }
public bool EnSuBase() { return EnBase; }
public void SalirBase() { EnBase = false; }
public void EntrarBase() { EnBase = true; Mover(); }
public void Normalizar()
{
HizoOp = false;
NormalizarSeleccion();
}
public void NormalizarSeleccion()
{
BackColor = Color.Black;
}
public int ObtIdBase() { return IdBase; }
public void RefrescarImagen()
{
string strImagen;
625
VOLVER A MEN
VOLVER A MEN
{
for (int i=0; i < C; i++) AgregarUnidad(T);
}
public int ObtCantidad() { return Count; }
public int ObtCantidadVivos()
{
int S = 0;
for (int i=0; i < Count; i++)
{
Unidad U = this[i];
if (U.EstaVivo() && U.Visible) S++;
}
return S;
}
public void ColocarEnBase()
{
for (int i=0; i < Count; i++)
this[i].EntrarBase();
}
public int ObtId() { return Id; }
public void Refrescar()
{
for (int i=0; i < Count; i++)
this[i].RefrescarImagen();
}
public void Normalizar()
{
for (int i=0; i < Count; i++)
this[i].Normalizar();
}
public bool TodosEnBase()
{
627
VOLVER A MEN
VOLVER A MEN
refJuego.ConcretarAtaque(Ue);
continue;
}
if (U.ObtNivelVida() == 1)
{
E = refJuego.Retirada(U);
if (E != null)
{
refJuego.SeleccionarUnidadMover(U);
refJuego.SeleccionarEspacioMover(E);
continue;
}
}
E = refJuego.AbarcarTerritorio(U);
if (E != null)
{
// Se tiene previsin de dejar un infante en la base
//
if (!(U.EnSuBase() && U.ObtTipo() == TipoUnidad.Infante &&
refJuego.ObtBase(U.ObtIdBase()).ObtNumeroUnidades(TipoUnidad.Infante) ==
1))
{
refJuego.SeleccionarUnidadMover(U);
refJuego.SeleccionarEspacioMover(E);
}
}
}
}
Normalizar();
}
}
}
629
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Conquista.cs
* Mauricio Paletta
*/
using System;
using System.Windows.Forms;
using System.Drawing;
namespace Conquista
{
public class Sonidos
{
private System.Media.SoundPlayer SonidoMorir, SonidoHerido,
SonidoDisparo1, SonidoDisparo2, SonidoAvance;
public Sonidos()
{
SonidoMorir = new System.Media.SoundPlayer();
SonidoHerido = new System.Media.SoundPlayer();
SonidoDisparo1 = new System.Media.SoundPlayer();
SonidoDisparo2 = new System.Media.SoundPlayer();
SonidoAvance = new System.Media.SoundPlayer();
SonidoMorir.SoundLocation = @Morir.wav;
SonidoHerido.SoundLocation = @Herido.wav;
SonidoDisparo1.SoundLocation = @Can.wav;
SonidoDisparo2.SoundLocation = @Disparo.wav;
SonidoAvance.SoundLocation = @Avance.wav;
}
public void ReproducirSonidoMorir()
{
630
VOLVER A MEN
SonidoMorir.Play();
}
public void ReproducirSonidoHerido()
{
SonidoHerido.Play();
}
public void ReproducirSonidoDisparo1()
{
SonidoDisparo1.Play();
}
public void ReproducirSonidoDisparo2()
{
SonidoDisparo2.Play();
}
public void ReproducirSonidoAvance()
{
SonidoAvance.Play();
}
}
public class Conquista {
protected Campo ElCampo;
private Grupo Conquistadores, Nativos;
private bool LosNativos, Iniciado;
private int Ganador;
private Form Frame;
private Unidad USeleccionadaMover, USeleccionadaAtacar;
private Sonidos LosSonidos;
public Conquista(Form F)
{
LosSonidos = new Sonidos();
ElCampo = null;
631
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
635
VOLVER A MEN
VOLVER A MEN
{
Pact = ((Cuadro)EUn).ObtPosicion();
if (Pact.X == -1) return;
Valido = Pact.X >= ElCampo.ObtNumColumnas() - NCuadros;
}
else
{
// Hay cuatro movimientos posibles: >, ^, v y <
//
Pact = ((Cuadro)EUn).ObtPosicion();
Pnue = ((Cuadro)E).ObtPosicion();
Valido = (Pact.Y == Pnue.Y && Math.Abs(Pact.X - Pnue.X) <= NCuadros) ||
(Pact.X == Pnue.X && Math.Abs(Pact.Y - Pnue.Y) <= NCuadros);
// El caso diagonal es posible siempre y cuando el cuadro inmediato siguiente
// est ocupado por una unidad del bando contrario
//
if (!Valido)
{
if ((Pnue.Y == Pact.Y - 1 && Pnue.X == Pact.X + 1) ||
(Pnue.Y == Pact.Y + 1 && Pnue.X == Pact.X + 1))
{
Valido = ElCampo.HayUnidad(USeleccionadaMover.ObtIdBase() == 1 ? 2 : 1,
new Point(Pact.X + 1, Pact.Y));
}
else
if ((Pnue.Y == Pact.Y - 1 && Pnue.X == Pact.X - 1) ||
(Pnue.Y == Pact.Y + 1 && Pnue.X == Pact.X - 1))
{
Valido = ElCampo.HayUnidad(USeleccionadaMover.ObtIdBase() == 1 ? 2 : 1,
new Point(Pact.X - 1, Pact.Y));
}
637
VOLVER A MEN
}
}
}
// Si el movimiento es vlido se procede
//
if (Valido)
{
// Se saca la unidad del espacio en la cual est actualmente
//
EUn.SacarUnidad(USeleccionadaMover);
// Se agrega la unidad al nuevo espacio
//
E.UbicarUnidad(USeleccionadaMover);
// Se normaliza la unidad movida
//
USeleccionadaMover.NormalizarSeleccion();
USeleccionadaMover = null;
}
}
// Concretar ataque (si es el caso)
//
public void ConcretarAtaque(Unidad U)
{
if (USeleccionadaAtacar == null || U == null || !Iniciado) return;
// Se valida que el ataque es posible
//
Espacio E1 = ElCampo.BuscarUnidad(USeleccionadaAtacar),
E2 = ElCampo.BuscarUnidad(U);
Point P1 = E1.ObtPosicion(), P2 = E2.ObtPosicion();
638
VOLVER A MEN
bool Valido;
if (USeleccionadaAtacar.EnSuBase())
{
Valido = (USeleccionadaAtacar.ObtIdBase() == 1 && P2.X == 0) ||
(USeleccionadaAtacar.ObtIdBase() == 1 &&
USeleccionadaAtacar.ObtTipo() == TipoUnidad.Artilleria && P2.X <= 1) ||
(USeleccionadaAtacar.ObtIdBase() == 2 &&
P2.X == ElCampo.ObtNumColumnas() - 1) ||
(USeleccionadaAtacar.ObtIdBase() == 2 &&
USeleccionadaAtacar.ObtTipo() == TipoUnidad.Artilleria &&
P2.X >= ElCampo.ObtNumColumnas() - 2);
}
else
if (U.EnSuBase())
{
Valido = (U.ObtIdBase() == 1 && P1.X == 0) || (U.ObtIdBase() == 1 &&
USeleccionadaAtacar.ObtTipo() == TipoUnidad.Artilleria && P1.X <= 1) ||
(U.ObtIdBase() == 2 && P1.X == ElCampo.ObtNumColumnas() - 1) ||
(U.ObtIdBase() == 2 && USeleccionadaAtacar.ObtTipo() == TipoUnidad.Artilleria
&&
VOLVER A MEN
int A = 1;
if (P1.Y == P2.Y && USeleccionadaAtacar.ObtTipo() == TipoUnidad.Artilleria &&
Math.Abs(P1.X - P2.X) == 2) A = 2;
if (USeleccionadaAtacar.Atacar(A))
{
U.Herir();
if (!U.EstaVivo()) E2.SacarUnidad(U);
}
USeleccionadaAtacar.NormalizarSeleccion();
}
}
// Normalizar los grupos
//
public void NormalizarConquistadores() { Conquistadores.Normalizar(); }
public void NormalizarNativos() { Nativos.Normalizar(); }
public void NormalizarGrupos()
{
NormalizarConquistadores();
NormalizarNativos();
}
public void NormalizarBase(int IdB)
{
if (IdB == 1) NormalizarNativos();
else NormalizarConquistadores();
}
private void VerificarFinalizacion()
{
if (!Iniciado) return;
// Ganan los nativos
//
640
VOLVER A MEN
if (Conquistadores.ObtCantidadVivos() == 0 || Conquistadores.TodosEnBase() ||
ElCampo.HayNativosBaseConquistadores()) Ganador = 1;
else
// Ganan los conquistadores
//
if (Nativos.ObtCantidadVivos() == 0 || Nativos.TodosEnBase() ||
ElCampo.HayConquistadoresBaseNativos()) Ganador = 2;
if (Ganador > 0) Iniciado = false;
}
public int ObtGanador()
{
VerificarFinalizacion();
return Ganador;
}
// Para el juego automtico
//
public void Jugar()
{
if (!Iniciado) return;
if (LosNativos) Nativos.Jugar();
else Conquistadores.Jugar();
}
public Espacio AbarcarTerritorio(Unidad U)
{
// Buscar un espacio con la cual la unidad dada puede abarcar territorio
//
Espacio E, Eaux, Emin = null;
Point P;
int Max = 0;
bool Asignar;
Random R = new Random();
641
VOLVER A MEN
VOLVER A MEN
Max = Eaux.ObtDisponibilidad();
Emin = Eaux;
}
}
if (Emin != null) return Emin;
}
P = E.ObtPosicion();
if (U.ObtIdBase() == 1)
{
if (ElCampo.ObtBase(2).Vacio() && (P.X == ElCampo.ObtNumColumnas() - 1) ||
(P.X == ElCampo.ObtNumColumnas() - 2 && U.ObtTipo() == TipoUnidad.Caballeria))
return ElCampo.ObtBase(2);
if (U.ObtTipo() == TipoUnidad.Caballeria)
{
Eaux = ElCampo.ObtCuadro(P.Y, P.X+2);
if (Eaux.Vacio()) return Eaux;
}
Eaux = ElCampo.ObtCuadro(P.Y, P.X+1);
if (Eaux.Vacio() || Eaux.ObtIdBase() == U.ObtIdBase()) return Eaux;
}
else
{
if (ElCampo.ObtBase(1).Vacio() &&
(P.X == 0) || (P.X == 1 && U.ObtTipo() == TipoUnidad.Caballeria))
return ElCampo.ObtBase(1);
if (U.ObtTipo() == TipoUnidad.Caballeria)
{
Eaux = ElCampo.ObtCuadro(P.Y, P.X-2);
if (Eaux.Vacio()) return Eaux;
}
Eaux = ElCampo.ObtCuadro(P.Y, P.X-1);
if (Eaux.Vacio() || Eaux.ObtIdBase() == U.ObtIdBase()) return Eaux;
}
643
VOLVER A MEN
return null;
}
public Unidad DefenderTerritorio(Unidad U)
{
// Verificar si los espacios adyacentes a la unidad dada hay un enemigo
// a fin de atacarlo. Se ataca el ms dbil
//
Espacio E, Eaux;
Point P;
if (U == null) return null;
E = ElCampo.BuscarUnidad(U);
if (E == null) return null;
P = E.ObtPosicion();
if (U.ObtIdBase() == 1)
{
Eaux = ElCampo.ObtCuadro(P.Y, P.X-1);
if (Eaux != null && !Eaux.Vacio() && Eaux.ObtIdBase() != U.ObtIdBase())
return Eaux.ObtMasDebil();
}
else
{
Eaux = ElCampo.ObtCuadro(P.Y, P.X+1);
if (Eaux != null && !Eaux.Vacio() && Eaux.ObtIdBase() != U.ObtIdBase())
return Eaux.ObtMasDebil();
}
Eaux = ElCampo.ObtCuadro(P.Y-1, P.X);
if (Eaux != null && !Eaux.Vacio() && Eaux.ObtIdBase() != U.ObtIdBase())
return Eaux.ObtMasDebil();
Eaux = ElCampo.ObtCuadro(P.Y+1, P.X);
if (Eaux != null && !Eaux.Vacio() && Eaux.ObtIdBase() != U.ObtIdBase())
return Eaux.ObtMasDebil();
644
VOLVER A MEN
if (U.ObtIdBase() == 1)
{
Eaux = ElCampo.ObtCuadro(P.Y, P.X+1);
if (Eaux != null && !Eaux.Vacio() && Eaux.ObtIdBase() != U.ObtIdBase())
return Eaux.ObtMasDebil();
}
else
{
Eaux = ElCampo.ObtCuadro(P.Y, P.X-1);
if (Eaux != null && !Eaux.Vacio() && Eaux.ObtIdBase() != U.ObtIdBase())
return Eaux.ObtMasDebil();
}
return null;
}
public Espacio Retirada(Unidad U)
{
// Provocar la retirada de la unidad
//
if (U == null || U.EnSuBase()) return null;
Espacio E, Eaux;
Point P;
E = ElCampo.BuscarUnidad(U);
if (E == null) return null;
P = E.ObtPosicion();
if (U.ObtIdBase() == 1)
{
if (P.X == 0) return ElCampo.ObtBase(1);
Eaux = ElCampo.ObtCuadro(P.Y, P.X-1);
if (Eaux != null && (Eaux.Vacio() || Eaux.ObtIdBase() == U.ObtIdBase()))
return Eaux;
}
645
VOLVER A MEN
else
{
if (P.X == ElCampo.ObtNumColumnas()-1) return ElCampo.ObtBase(2);
Eaux = ElCampo.ObtCuadro(P.Y, P.X+1);
if (Eaux != null && (Eaux.Vacio() || Eaux.ObtIdBase() == U.ObtIdBase()))
return Eaux;
}
return null;
}
public void ReproducirSonido(int S)
{
switch (S) {
case 1:
LosSonidos.ReproducirSonidoMorir();
break;
case 2:
LosSonidos.ReproducirSonidoHerido();
break;
case 3:
LosSonidos.ReproducirSonidoDisparo1();
break;
case 4:
LosSonidos.ReproducirSonidoDisparo2();
break;
case 5:
LosSonidos.ReproducirSonidoAvance();
break;
}
}
}
}
646
VOLVER A MEN
VOLVER A MEN
La condicin que activa una accin ai (i = 2, 3, ..., m) no es simplemente Ki, sino que
viene dada por la conjuncin de Ki con la negacin de la condicin Ki-1. Basta con que
exista un j menor que i tal que Kj sea verdadera para que se inhiba la ejecucin de ai.
2. Se dice que ai es una accin durativa si ai se ejecuta en forma continua hasta que la
condicin que la activa sea falsa.
3. Las acciones ai pueden ser acciones primitivas o bien otras ST.
4. En el caso de programas organizados en forma jerrquica, todas las condiciones a todos
los niveles de la jerarqua deben ser evaluadas continuamente.
5. Al plantear una ST, hay que pensar de la meta a lograr hacia atrs:
Lograr la meta corresponde a K1 verdadera y a1 es la accin nula.
La accin a2 debe conducir eventualmente a que K2 se haga verdadera
sucesivamente.
y as
En general, una accin no nula aj debe conducir a que alguna condicin Ki (i < j) se haga
verdadera.
6. Se dice que las condiciones Ki (i > 1) son regresiones de otras condiciones de mayor
jerarqua, a travs de las acciones ai que activan esas otras condiciones.
7. Una ST satisface la propiedad de regresin si cada condicin Ki (i > 1) es la regresin de
alguna otra condicin Kj (j < i) de mayor jerarqua en la secuencia a travs de la accin ai.
8. Se dice que una ST es universal si satisface la propiedad de regresin y es completa.
9. Una ST universal siempre alcanzar su meta, si hay perfecta percepcin del ambiente.
10. En ocasiones una accin no tiene el efecto anticipado por el diseador o bien agentes
exgenos cambian el ambiente en forma inesperada; por ello se requiere la retroalimentacin
(feedback) continua.
11. Las ST universales parecen robustas frente a desviaciones ocasionales de la ejecucin
normal.
12. Los agentes se disean para hacer algo en ambientes dinmicos, por lo que deben poseer
capacidad de reaccin (reactividad).
13. Un agente puede tener que atender varias metas en forma simultnea (como por ejemplo
mantenerse a s mismo y cumplir su misin). Estas metas pueden tener diversos niveles de
importancia, a su vez el orden de importancia puede cambiar en el tiempo.
14. Cada meta puede ser atendida por una ST, la cual es activada siguiendo una biblioteca de
648
VOLVER A MEN
El problema a resolver en esta seccin tiene que ver con la simulacin de un conjunto de
agentes recolectores de desperdicio. Los agentes recolectores son entidades autnomas cuya
meta es limpiar el ambiente de todos los desperdicios que en l haya, cooperando con los otros
recolectores. Para ello se deben respetar los siguientes criterios:
1. Hay dos tipos de desperdicio en el ambiente: livianos y pesados. Inicialmente y durante la dinmica
del modelo los desperdicios aparecen segn una probabilidad de 0.25 para los livianos y 0.10
para los pesados. Cada desperdicio tiene un peso asociado que se mide en funcin de unidades
discretas de peso. Los desperdicios livianos pueden estar entre 1 y 4 unidades de peso, mientras
que los pesados pueden estar entre 6 y 10 unidades de peso. La posicin de los desperdicios en
el ambiente as como su peso es seleccionado al azar.
2. Los bordes o lmites del ambiente pueden ser cerrados (pared) o de circulacin cclica (salida por
un lado y entrada por el lado contrario).
3. Un agente recolector debe tener sentido de orientacin (ojos) y slo cuando el desperdicio est en
su visin es que puede ser recogido. Sus nicos movimientos posibles son: ir hacia adelante, rotar
a la izquierda rotar a la derecha. Slo se permite una accin o movimiento por unidad de tiempo.
649
VOLVER A MEN
4. Hay dos tipos de recolectores: carga liviana y carga pesada. Los recolectores de carga liviana slo
pueden recoger desperdicios livianos y hasta un mximo de 10 unidades de peso, mientras que los
recolectores de carga pesada pueden recoger tanto desperdicios livianos como pesados y hasta un
mximo de 30 unidades de peso. La cantidad de recolectores livianos es un parmetro cuyo valor
debe ser dado previo a la ejecucin del modelo y por cada 3 recolectores de carga liviana hay un
recolector de carga pesada. La posicin inicial de estos recolectores se selecciona al azar.
5. Los recolectores funcionan con energa propia que se va consumiendo a medida que avanza
la dinmica. Los recolectores de carga liviana tienen una fuente de energa de 30 unidades y
consumen su energa segn los siguientes criterios:
Una unidad por cada movimiento.
Una unidad para recolectar desperdicio.
Dos unidades para vaciar su carga.
Los recolectores de carga pesada tienen una fuente de energa de 50 unidades y su consumo se
rige segn los siguientes criterios:
Una unidad por cada movimiento.
Una unidad para recolectar desperdicio liviano.
Dos unidades para recolectar desperdicio pesado.
Cuatro unidades para vaciar su carga.
Inicialmente la cantidad de energa de cada recolector se asigna al azar.
6. En el ambiente debe existir un centro de recarga de energa donde los recolectores se deben dirigir
para recargar su fuente de energa cuando sea necesario. La posicin de este centro puede ser
fija y conocida por los recolectores y debe contar con una entrada y una salida independiente. Slo
es posible albergar un recolector a la vez por lo que se requiere un manejo de cola para satisfacer
la necesidad de varios recolectores. Los recolectores de carga liviana requieren dos unidades de
tiempo para recargar su energa mientras que los de carga pesada lo hacen en cuatro unidades de
tiempo. En caso de que un recolector se quede sin energa antes de llegar al centro de recarga,
se convierte en un desperdicio de carga pesada de 10 unidades de peso y debe ser tratado igual.
7. En el ambiente debe existir un depsito de desperdicios donde los recolectores se deben dirigir para
vaciar su carga cuando sea necesario. La posicin de este depsito puede ser fija y conocida por
los recolectores y debe contar con una entrada y una salida independiente. Slo es posible albergar
un recolector a la vez por lo que se requiere un manejo de cola para satisfacer la necesidad de
varios recolectores. Los recolectores de carga liviana requieren una unidad de tiempo para vaciar
su carga mientras que los de carga pesada lo hacen en dos unidades de tiempo. Para cada instante
de tiempo se requiere conocer la cantidad de desperdicio de cada tipo almacenado en el depsito.
650
VOLVER A MEN
8. La dinmica de cambio de la simulacin se mide mediante un valor discreto de tiempo que puede
ser medidad en segundos. La simulacin empieza y termina por orden del usuario. Se debe poder
ver el estado actual del ambiente en todo momento. El tamao del ambiente pede ser fijo acorde a
las caractersticas escogidas para la interfaz.
9. La implementacin debe tener en cuenta la autonoma de los agentes.
6.10.2 Anlisis
Paso 1 (Identificar la idea y objetivos bsicos del sistema): La Figura 6.63 presenta un mapa
mental realizado con base al enunciado del problema. Se identifican tres elementos bsicos:
los agentes recolectores, los desperdicios y el ambiente.
Figura 6.63. Mapa mental relativo al problema de los agentes recolectores de desperdicio.
Paso 2 (Identificar actores / nombres): Al revisar el mapa mental de la Figura 6.62 se tiene la
siguiente lista de nombres: simulador, agente recolector, ojo, movimiento, desperdicio, unidad
de peso, unidad de tiempo, carga, energa, posicin, ambiente, centro de recarga de energa,
centro de descarga de desperdicio, cola de atencin, entrada, salida, tamao, autonoma,
agente.
Paso 3 (Identificar procesos / requerimientos): La implementacin de este problema consiste
en mostrar una simulacin; un usuario debe poder configurar algunos parmetros requeridos
y realizar las acciones de iniciar/detener el proceso. En este sentido se tiene el diagrama de
casos de uso que se muestra en la Figura 6.64.
651
VOLVER A MEN
Figura 6.64. Diagrama de casos de uso relativo al problema de los agentes recolectores de desperdicio.
VOLVER A MEN
Figura 6.65. Diagrama no detallado de clases relativo al problema de los agentes recolectores de desperdicio.
6.10.3 Diseo
Paso 1 (Definir la arquitectura de la solucin): Para este problema es conveniente tener un
formulario con interfaz grfica que comprenda un panel para la configuracin y acciones y otro
panel para visualizar el estado actual. Una de las mayores complejidades en la implementacin
de este problema viene dado por la autonoma que se le debe dar a los agentes recolectores.
Para ello es recomendable el uso de hilos de ejecucin independientes para cada agente. En
este sentido, el ambiente se convierte en un rea de uso compartido y por ende en una regin
en conflicto.
Paso 2 (Detallar las clases): La Figura 6.66 muestra el diagrama de clases detallado previamente
presentado en la Figura 6.65. Se pueden notar algunas variantes, lo cual es normal que ocurra
en estas etapas de la resolucin del problema. Ya no se tiene una clase Simulador la cual fue
integrada con el Ambiente. De los conceptos de Desperdicio y Recolector se identificaron
aspectos comunes relacionados principalmente con el manejo de la parte grfica que originaron
la inclusin en el diagrama de la clase abstracta ElementoGrafico. Adicionalmente, en el
diagrama de la Figura 6.66 se incluyen los enumerados: TipoDesperdicio, Orientacion,
TipoRecolector y Estados.
Figura 6.66. Diagrama detallado de clases relativo al problema de los agentes recolectores de desperdicio.
653
VOLVER A MEN
Paso 3 (Desarrollar los modelos de estado): En la Figura 6.67 se observan los diagramas
de estado de las clases relativas a este problema. Se obvia la clase Ambiente ya que los
cambios de estado correspondientes dependen de los cambios de estado de los centros y de
la implementacin de las listas de desperdicios y recolectores. Al igual que se ha hecho con
los diagramas de estado de los problemas previos, se omiten tanto las transiciones entre los
estados as como tambin las auto-transiciones a fin de eliminar complejidad a la lectura del
diagrama.
Figura 6.67. Diagramas de estado relativos al problema de los agentes recolectores de desperdicio.
Paso 4 (Elaborar los modelos de colaboracin): A fin de mostrar la colaboracin entre los
objetos involucrados en este problema, la Figura 6.68 muestra el diagrama de colaboracin
correspondiente. Ntese la presencia de los dos objetos especficos que representan al centro
de recarga de energa y centro de descarga de desperdicio respectivamente.
Figura 6.68. Diagrama de colaboracin relativo al problema de los agentes recolectores de desperdicio.
654
VOLVER A MEN
Figura 6.69. Diagrama de componentes relativo al problema de los agentes recolectores de desperdicio.
6.10.4 Programacin
Con respecto a la implementacin en C++ se tienen los archivos fuente identificados como
Ambiente.hpp, Ambiente.cpp, Elementos.hpp y Elementos.cpp. Los mismos se muestran
a continuacin. Se utiliza el espacio de nombres identificado como RecoleccionDesperdicios.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.10
* Ambiente.hpp
* Mauricio Paletta
*/
#ifndef AMBIENTE_HPP
#define AMBIENTE_HPP
#include <QTimer>
#include <QQueue>
#include <QObject>
#include Elementos.hpp
655
VOLVER A MEN
namespace RecoleccionDesperdicios {
class Centro {
private:
bool Ocupado;
QQueue<pRecolector> *ColaAtencion;
pRecolector EnAtencion;
int UnidadesTiempo;
public:
Centro();
~Centro();
void Atender(pRecolector R, bool CargarEnergia);
void TaskAtencion();
bool EstaOcupado() { return Ocupado; }
int CantidadColaAtencion() { return ColaAtencion->count(); }
};
typedef Centro *pCentro;
class Ambiente {
private:
pCentro RecargaEnergia, DescargaDesperdicio;
QList<pDesperdicio> *Desperdicios;
QList<pRecolector> *Recolectores;
QList<pRecolector> *ParaDesperdicios;
void TaskDesperdicios();
public:
Ambiente();
~Ambiente();
void Limpiar();
656
VOLVER A MEN
VOLVER A MEN
R->AtenderEnDescarga();
DescargaDesperdicio->Atender(R, false);
}
void Detener();
void RefrescarRecolectores();
void RealizarTareas();
};
}
#endif /* AMBIENTE_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.10
* Ambiente.cpp
* Mauricio Paletta
*/
#include <QDialog>
#include Ambiente.hpp
namespace RecoleccionDesperdicios {
// Mtodos de la clase Centro
//
Centro::Centro() {
ColaAtencion = new QQueue<pRecolector>();
Ocupado = false;
EnAtencion = NULL;
UnidadesTiempo = 0;
}
Centro::~Centro() {
ColaAtencion->clear();
658
VOLVER A MEN
delete ColaAtencion;
}
void Centro::TaskAtencion() {
if (EnAtencion == NULL) return;
// Se verifica si se venci el tiempo de atencin
//
UnidadesTiempo++;
if (UnidadesTiempo < EnAtencion->ObtTpoAtencion()) return;
// El recolector actual ha sido atendido
// Se verifica alguien ms en cola para su atencin
//
EnAtencion->AtendidoEnCentro();
Ocupado = false;
EnAtencion = NULL;
UnidadesTiempo = 0;
if (ColaAtencion->count() > 0) {
EnAtencion = ColaAtencion->dequeue();
Ocupado = true;
}
}
void Centro::Atender(pRecolector R, bool CargarEnergia) {
// Permite llevar registro del tiempo de atencin
//
if (CargarEnergia)
R->AsgTpoAtencion(R->EsLiviano() ? 2 : 4);
else
R->AsgTpoAtencion(R->EsLiviano() ? 1 : 2);
if (Ocupado) {
ColaAtencion->enqueue(R);
659
VOLVER A MEN
return;
}
Ocupado = true;
EnAtencion = R;
UnidadesTiempo = 0;
}
// Mtodos de la clase Ambiente
//
Ambiente::Ambiente() {
RecargaEnergia = new Centro();
DescargaDesperdicio = new Centro();
Desperdicios = new QList<pDesperdicio>();
Recolectores = new QList<pRecolector>();
ParaDesperdicios = new QList<pRecolector>();
}
Ambiente::~Ambiente() {
delete RecargaEnergia;
delete DescargaDesperdicio;
Limpiar();
ParaDesperdicios->clear();
delete ParaDesperdicios;
}
void Ambiente::Limpiar() {
while (Desperdicios->size() > 0) {
delete Desperdicios->at(0);
Desperdicios->removeAt(0);
}
Desperdicios->clear();
while (Recolectores->size() > 0) {
delete Recolectores->at(0);
Recolectores->removeAt(0);
}
Recolectores->clear();
660
VOLVER A MEN
}
void Ambiente::TaskDesperdicios() {
pDesperdicio D;
pRecolector R;
if (ParaDesperdicios->isEmpty()) return;
R = ParaDesperdicios->at(0);
R->setVisible(false);
D = new Desperdicio((QFrame *)(R->parent()), Pesado, 10);
D->setVisible(false);
D->setGeometry(R->x(), R->y(), R->LaDimension(), R->LaDimension());
D->setVisible(true);
Desperdicios->push_back(D);
Recolectores->removeAt(Recolectores->indexOf(R, 0));
ParaDesperdicios->removeAt(0);
}
void Ambiente::Detener() {
for (int i = 0; i < Recolectores->size(); i++)
(*Recolectores)[i]->Parar();
}
void Ambiente::RefrescarRecolectores() {
for (int i = 0; i < Recolectores->size(); i++)
(*Recolectores)[i]->RefrescarMovimientos();
}
void Ambiente::RealizarTareas() {
TaskDesperdicios();
RecargaEnergia->TaskAtencion();
DescargaDesperdicio->TaskAtencion();
}
}
661
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.10
* Elementos.hpp
* Mauricio Paletta
*/
#ifndef ELEMENTOS_HPP
#define ELEMENTOS_HPP
#include <QtGui>
namespace RecoleccionDesperdicios {
enum TipoOperacion {
Avance, Rotacion, Apagar, Mostrar, Recoger
};
class Desperdicio;
class Movimiento {
private:
QPoint Pt;
QString Img;
Desperdicio *D;
TipoOperacion Operacion;
public:
Movimiento(QPoint P) { Pt = P; Img = ; Operacion = Avance; }
Movimiento(QString I) { Img = I; Operacion = Rotacion; }
Movimiento(bool F) { Operacion = F ? Mostrar : Apagar; }
Movimiento(Desperdicio *pD) { Operacion = Recoger; D = pD; }
QPoint ObtAvance() { return Pt; }
QString ObtRotacion() { return Img; }
662
VOLVER A MEN
VOLVER A MEN
SemLista->acquire();
ListaMovimientos->append(new Movimiento(P));
SemLista->release();
}
void AgregarMovimiento(bool B) {
SemLista->acquire();
ListaMovimientos->append(new Movimiento(B));
SemLista->release();
}
void AgregarMovimiento(Desperdicio *D) {
SemLista->acquire();
ListaMovimientos->append(new Movimiento(D));
SemLista->release();
}
};
enum TipoDesperdicio {
Liviano, Pesado
};
class Desperdicio : public ElementoGrafico {
private:
TipoDesperdicio Tipo;
int Peso;
public:
Desperdicio(QFrame *F, TipoDesperdicio T);
Desperdicio(QFrame *F, TipoDesperdicio T, int Ps);
void Recoger();
int ObtPeso() { return Peso; }
bool EsLiviano() { return Tipo == Liviano; }
};
typedef Desperdicio *pDesperdicio;
664
VOLVER A MEN
enum TipoRecolector {
RLiviano, RPesado
};
enum Orientacion {
Aba, Izq, Arr, Der
};
enum Estados {
Normal, EnRecarga, EnDescarga
};
class Recolector;
class ThreadAgente : public QThread {
Q_OBJECT
private:
Recolector *R;
bool Continuar;
protected:
void run();
public:
ThreadAgente(Recolector *r) {
Continuar = true;
R = r;
}
void Stop() { Continuar = false; }
};
class Ambiente;
class Recolector : public ElementoGrafico {
665
VOLVER A MEN
private:
static QSemaphore Sem;
ThreadAgente *Agente;
TipoRecolector Tipo;
int Carga, Energia, Capacidad, TpoAtencion;
Orientacion Ojos;
Estados Estado;
Ambiente *ElAmbiente;
void Refrescar();
void PuntoVisual(QPoint &Pt);
pDesperdicio BuscarDesperdicio(QPoint Pt);
bool VerificarRecogerDesperdicio();
public:
Recolector(Ambiente *A, QFrame *P, TipoRecolector T);
~Recolector() { delete Agente; }
bool Avanzar();
void RotarIzquierda();
void RotarDerecha();
bool EsLiviano() {
return Tipo == RLiviano;
}
void AtenderEnRecarga() {
Estado = EnRecarga;
AgregarMovimiento(false);
}
void AtenderEnDescarga() {
Estado = EnDescarga;
AgregarMovimiento(false);
}
666
VOLVER A MEN
void AtendidoEnCentro();
void SecuenciaTeleoreactiva();
void Parar();
void AsgTpoAtencion(int Tpo) { if (Tpo >= 0) TpoAtencion = Tpo; }
int ObtTpoAtencion() { return TpoAtencion; }
};
typedef Recolector *pRecolector;
}
#endif /* ELEMENTOS_HPP */
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en C++; caso prctico Seccin 6.10
* Elementos.cpp
* Mauricio Paletta
*/
#include <stdlib.h>
#include <time.h>
#include Elementos.hpp
#include Ambiente.hpp
namespace RecoleccionDesperdicios {
// Mtodos de la clase ElementoGrafico
//
ElementoGrafico::ElementoGrafico(QFrame *F, bool D) : QGraphicsView((QWidget *)F) {
QPoint Pt;
ImagenAgente = new QGraphicsScene();
setScene(ImagenAgente);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
667
VOLVER A MEN
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setProperty(Tipo, D);
do {
Pt.setX((rand() % (F->width() / Dimension)) * Dimension);
Pt.setY((rand() % (F->height() / Dimension)) * Dimension);
} while (!VerificarOcupacion(Pt));
setGeometry(Pt.x(), Pt.y(), Dimension, Dimension);
setVisible(true);
setFrameShape(NoFrame);
PtActual = pos();
SemLista = new QSemaphore(1);
ListaMovimientos = new QList<pMovimiento>();
}
ElementoGrafico::~ElementoGrafico() {
delete ImagenAgente;
for (int i=0; i < ListaMovimientos->count(); i++) {
pMovimiento Aux = (*ListaMovimientos)[i];
if (Aux != NULL) delete Aux;
}
ListaMovimientos->clear();
delete ListaMovimientos;
delete SemLista;
}
bool ElementoGrafico::VerificarOcupacion(QPoint Pt) {
QFrame *P = (QFrame *)parentWidget();
if (Pt.x() < 0 || Pt.x() + Dimension > P->width() || Pt.y() < 0 || Pt.y() + Dimension > P->height())
return false;
for (int i = 0; i < P->children().count(); i++) {
668
VOLVER A MEN
VOLVER A MEN
break;
}
repaint();
delete M;
SemLista->release();
}
// Mtodos de la clase Desperdicio
//
Desperdicio::Desperdicio(QFrame *P, TipoDesperdicio T) : ElementoGrafico(P, true) {
Tipo = T;
if (Tipo == Liviano) {
Peso = 1 + (rand() % 4);
ImagenAgente->addPixmap(QPixmap(DesperdicioL.bmp));
}
else {
Peso = 6 + (rand() % 5);
ImagenAgente->addPixmap(QPixmap(DesperdicioP.bmp));
}
repaint();
}
Desperdicio::Desperdicio(QFrame *P, TipoDesperdicio T, int Ps) : ElementoGrafico(P, true) {
Tipo = T;
if (Ps < 0) Ps = 1;
if (Tipo == Liviano) {
if (Ps > 5) Ps = 5;
ImagenAgente->addPixmap(QPixmap(DesperdicioL.bmp));
}
else {
if (Ps > 10) Ps = 10;
ImagenAgente->addPixmap(QPixmap(DesperdicioP.bmp));
}
Peso = Ps;
670
VOLVER A MEN
repaint();
}
void Desperdicio::Recoger() {
QFrame *P = (QFrame *)parentWidget();
QList<QObject *> L = P->children();
L.removeAt(L.indexOf(this, 0));
}
// Mtodos de la clase Recolector
//
void ThreadAgente::run() {
while (Continuar) {
R->SecuenciaTeleoreactiva();
// Se espera entre 500 y 2000 mseg
//
usleep(500 + rand() % 2000);
}
}
QSemaphore Recolector::Sem(1);
Recolector::Recolector(Ambiente *A, QFrame *P, TipoRecolector T) : ElementoGrafico(P, false) {
Tipo = T;
Carga = 0;
ElAmbiente = A;
if (Tipo == RLiviano) {
Energia = 50 + (rand() % 51);
Capacidad = 10;
}
else {
Energia = 150 + (rand() % 51);
Capacidad = 30;
671
VOLVER A MEN
}
Estado = Normal;
PtActual = this->pos();
TpoAtencion = 0;
// Se decide al azar la posicin inicial y
// localizacin inicial del recolector
//
switch (Tipo) {
case Liviano:
switch (rand() % 4) {
case 0:
Ojos = Aba;
break;
case 1:
Ojos = Izq;
break;
case 2:
Ojos = Arr;
break;
case 3:
Ojos = Der;
break;
}
break;
case Pesado:
switch (rand() % 4) {
case 0:
Ojos = Aba;
break;
case 1:
Ojos = Izq;
break;
672
VOLVER A MEN
case 2:
Ojos = Arr;
break;
case 3:
Ojos = Der;
break;
}
break;
}
Refrescar();
// Hilo de ejecucin
//
Agente = new ThreadAgente(this);
Agente->start();
}
void Recolector::Refrescar() {
std::string Img = ;
switch (Tipo) {
case Liviano:
switch (Ojos) {
case Aba:
Img = LivianoD.bmp;
break;
case Izq:
Img = LivianoL.bmp;
break;
case Arr:
Img = LivianoU.bmp;
break;
case Der:
673
VOLVER A MEN
Img = LivianoR.bmp;
break;
}
break;
case Pesado:
switch (Ojos) {
case Aba:
Img = PesadoD.bmp;
break;
case Izq:
Img = PesadoL.bmp;
break;
case Arr:
Img = PesadoU.bmp;
break;
case Der:
Img = PesadoR.bmp;
break;
}
break;
}
if (Img != ) {
AgregarMovimiento(QString(Img.c_str()));
}
}
void Recolector::PuntoVisual(QPoint &Pt) {
switch (Ojos) {
case Aba:
Pt.setY(Pt.y() + LaDimension());
break;
case Izq:
Pt.setX(Pt.x() - LaDimension());
674
VOLVER A MEN
break;
case Arr:
Pt.setY(Pt.y() - LaDimension());
break;
case Der:
Pt.setX(Pt.x() + LaDimension());
break;
}
}
bool Recolector::Avanzar() {
QPoint Pt = PtActual;
if (Energia <= 0) return false;
PuntoVisual(Pt);
if (!VerificarOcupacion(Pt)) {
return false;
}
PtActual = Pt;
AgregarMovimiento(Pt);
Energia--;
return true;
}
void Recolector::RotarIzquierda() {
if (Energia <= 0) return;
switch (Ojos) {
case Aba:
Ojos = Der;
break;
case Der:
Ojos = Arr;
break;
675
VOLVER A MEN
case Arr:
Ojos = Izq;
break;
case Izq:
Ojos = Aba;
break;
}
Energia--;
Refrescar();
}
void Recolector::RotarDerecha() {
if (Energia <= 0) return;
switch (Ojos) {
case Aba:
Ojos = Izq;
break;
case Izq:
Ojos = Arr;
break;
case Arr:
Ojos = Der;
break;
case Der:
Ojos = Aba;
break;
}
Energia--;
Refrescar();
}
676
VOLVER A MEN
void Recolector::AtendidoEnCentro() {
if (Estado == Normal) return;
if (Estado == EnRecarga)
Energia = Tipo == RLiviano ? 100 : 200;
else {
Carga = 0;
Energia -= Tipo == RLiviano ? 2 : 4;
}
TpoAtencion = 0;
// Hay que ubicar nuevamente el recolector en el rea de simulacin
//
QFrame *P = (QFrame *)parentWidget();
QPoint Pt(0, Estado == EnRecarga ? 0 : P->height() - LaDimension());
while (!VerificarOcupacion(Pt)) Pt.setX(Pt.x() + LaDimension());
Ojos = (Estado == EnRecarga ? Aba : Arr);
Estado = Normal;
PtActual = Pt;
AgregarMovimiento(Pt);
AgregarMovimiento(true);
}
pDesperdicio Recolector::BuscarDesperdicio(QPoint Pt) {
QFrame *P = (QFrame *)parentWidget();
QList<QObject *> L = P->children();
for (int i=0; i < L.count(); i++) {
ElementoGrafico *C = (ElementoGrafico *)L[i];
bool D = C->property(Tipo).toBool();
if (D && C->ObtX() == Pt.x() && C->ObtY() == Pt.y())
return (pDesperdicio)C;
}
677
VOLVER A MEN
return NULL;
}
bool Recolector::VerificarRecogerDesperdicio() {
// Primero se busca la posible presencia de un desperdicio en la
// lnea visual del recolector
//
QPoint Pt = PtActual;
pDesperdicio D;
PuntoVisual(Pt);
D = BuscarDesperdicio(Pt);
if (D == NULL) return false;
// Se tiene un desperdicio, se verifica si el recolector lo puede recoger
//
if (((EsLiviano() && D->EsLiviano()) || !EsLiviano()) && Carga + D->ObtPeso() <= Capacidad) {
// Ver si hay energa suficiente
//
if ((D->EsLiviano() && Energia > 0) || Energia - 1 > 0) {
// Se procede a la recoleccin del desperdicio
//
Carga += D->ObtPeso();
Energia -= D->EsLiviano() ? 1 : 2;
D->Recoger();
AgregarMovimiento(D);
return true;
}
}
return false;
}
678
VOLVER A MEN
void Recolector::Parar() {
Agente->Stop();
AgregarMovimiento(false);
}
void Recolector::SecuenciaTeleoreactiva() {
QFrame *P = (QFrame *)parentWidget();
// Si est siendo atendido en algn centro se duerme
//
if (Estado != Normal) return;
Sem.acquire();
// Si se acab la energa el recolector se convierte en un desperdicio
// pesado de 10 unidades de peso
//
if (Energia <= 0) {
ElAmbiente->ConvertirRecolectorDesperdicio(this);
Parar();
Sem.release();
return;
}
// Lo primero es revisar la energa, de haber problemas hay que
// dirigirse al centro de recarga que est en la coordenada (0, 0)
//
if (Energia <= 25) {
if (PtActual.x() == 0 && PtActual.y() == 0) {
if (Ojos == Arr) {
// Puede entrar al centro de recarga
//
ElAmbiente->RecargarEnergia(this);
679
VOLVER A MEN
}
else {
if (Ojos == Der || Ojos == Aba)
RotarIzquierda();
else
RotarDerecha();
}
}
else {
QPoint Pt = PtActual;
if (PtActual.x() == 0 && Ojos == Izq) {
RotarDerecha();
Sem.release();
return;
}
if (PtActual.y() == 0 && Ojos == Arr) {
RotarIzquierda();
Sem.release();
return;
}
if ((Ojos == Aba || Ojos == Der)) {
RotarIzquierda();
Sem.release();
return;
}
if (!Avanzar()) {
if (rand() < RAND_MAX / 2)
RotarIzquierda();
else
RotarDerecha();
Avanzar();
}
}
680
VOLVER A MEN
Sem.release();
return;
}
// Lo segundo es verificar la carga, de estar casi lleno hay que ir
// al centro de descarga que est en la coordenada (0, H)
//
if (Capacidad - Carga <= 5) {
if (PtActual.x() == 0 && P->height() - (PtActual.y() + LaDimension()) < LaDimension()) {
if (Ojos == Aba) {
// Puede entrar al centro de recarga
//
ElAmbiente->DescargarDesperdicio(this);
}
else {
if (Ojos == Der || Ojos == Arr)
RotarDerecha();
else
RotarIzquierda();
}
}
else {
if (PtActual.x() == 0 && Ojos == Izq) {
RotarIzquierda();
Sem.release();
return;
}
if (P->height() - (PtActual.y() + LaDimension()) < LaDimension() && Ojos == Arr) {
RotarDerecha();
Sem.release();
return;
}
if (Ojos == Arr || Ojos == Der) {
681
VOLVER A MEN
RotarDerecha();
Sem.release();
return;
}
if (!Avanzar()) {
if (rand() < RAND_MAX / 2)
RotarDerecha();
else
RotarIzquierda();
Avanzar();
}
}
Sem.release();
return;
}
// Lo tercero es verificar si tiene un desperdicio en su foco visual
// para recogerlo
//
if (VerificarRecogerDesperdicio()) {
Sem.release();
return;
}
// Lo cuarto es decidir aleatoriamente si avanzar o rotar
//
switch (rand() % 6) {
case 0:
RotarIzquierda();
break;
case 1:
RotarDerecha();
break;
682
VOLVER A MEN
default:
if (!Avanzar()) {
if (rand() < RAND_MAX / 2)
RotarIzquierda();
else
RotarDerecha();
}
break;
}
Sem.release();
}
}
Para la implementacin en Java se tienen los archivos fuente Ambiente.java, Centro.java,
ElementoGrafico.java, Desperdicio.java y Recolector.java. Todas las clases fueron definidas en
el paquete identificado como RecoleccionDesperdicios. A continuacin el listado de estos archivos.
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.10
* Ambiete.java
* Mauricio Paletta
*/
package RecoleccionDesperdicios;
import java.awt.Container;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class Ambiente {
class TaskDesperdicio extends TimerTask {
public void run() {
683
VOLVER A MEN
Desperdicio D;
Recolector R;
if (ParaDesperdicios.isEmpty()) return;
R = ParaDesperdicios.get(0);
R.setVisible(false);
D = new Desperdicio(R.getParent(), Desperdicio.TipoDesperdicio.Pesado, 10);
D.setVisible(false);
D.setLocation(R.getX(), R.getY());
D.setVisible(true);
Desperdicios.add(D);
Recolectores.remove(R);
ParaDesperdicios.remove(0);
R.Parar();
}
}
private Centro RecargaEnergia, DescargaDesperdicio;
private List<Desperdicio> Desperdicios;
private List<Recolector> Recolectores;
private List<Recolector> ParaDesperdicios;
private Timer timerD = new Timer();
private TaskDesperdicio TiempoParaDesperdicios = new TaskDesperdicio();
public Ambiente() {
RecargaEnergia = new Centro();
DescargaDesperdicio = new Centro();
Desperdicios = new LinkedList<Desperdicio>();
Recolectores = new LinkedList<Recolector>();
ParaDesperdicios = new LinkedList<Recolector>();
timerD.schedule(TiempoParaDesperdicios, 0, 250);
}
684
VOLVER A MEN
VOLVER A MEN
}
public int NumRecolectoresColaDescarga() {
return DescargaDesperdicio.CantidadColaAtencion();
}
public void RecargarEnergia(Recolector R) {
R.AtenderEnRecarga();
RecargaEnergia.Atender(R, true);
}
public void DescargarDesperdicio(Recolector R) {
R.AtenderEnDescarga();
DescargaDesperdicio.Atender(R, false);
}
public void Detener() {
for (int i = 0; i < Recolectores.size(); i++)
Recolectores.get(i).Parar();
}
}
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.10
* Centro.java
* Mauricio Paletta
*/
package RecoleccionDesperdicios;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
686
VOLVER A MEN
VOLVER A MEN
Ocupado = false;
EnAtencion = null;
ColaAtencion = new LinkedList<Recolector>();
UnidadesTiempo = 0;
timerA.schedule(TiempoAtencion, 0, 1000);
}
public void Atender(Recolector R, boolean CargarEnergia) {
// Permite llevar registro del tiempo de atencin
//
if (CargarEnergia)
R.setToolTipText(R.EsLiviano() ? 2 : 4);
else
R.setToolTipText(R.EsLiviano() ? 1 : 2);
if (Ocupado) {
ColaAtencion.add(R);
return;
}
Ocupado = true;
EnAtencion = R;
UnidadesTiempo = 0;
}
public boolean EstaOcupado() { return Ocupado; }
public int CantidadColaAtencion() { return ColaAtencion.size(); }
}
688
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.10
* ElementoGrafico.java
* Mauricio Paletta
*/
package RecoleccionDesperdicios;
import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import java.util.Random;
import javax.swing.JLabel;
public abstract class ElementoGrafico extends JLabel {
private final int Dimension = 11;
public ElementoGrafico(Container P) {
super();
Random R = new Random();
Point Pt = new Point();
this.setSize(Dimension, Dimension);
P.add(this);
do {
Pt.x = R.nextInt(P.getWidth() / Dimension) * Dimension;
Pt.y = R.nextInt(P.getHeight() / Dimension) * Dimension;
} while (!VerificarOcupacion(Pt));
this.setLocation(Pt);
}
689
VOLVER A MEN
VOLVER A MEN
691
VOLVER A MEN
try {
Tipo = T;
if (Ps < 0) Ps = 1;
if (Tipo == TipoDesperdicio.Liviano) {
if (Ps > 5) Ps = 5;
Imagen = ImageIO.read(new File(DesperdicioL.bmp));
}
else {
if (Ps > 10) Ps = 10;
Imagen = ImageIO.read(new File(DesperdicioP.bmp));
}
Peso = Ps;
this.setIcon(new ImageIcon(Imagen));
this.repaint();
} catch (IOException ex) { }
}
public void Recoger() {
Container P = getParent();
setVisible(false);
P.remove(this);
}
public int ObtPeso() { return Peso; }
public boolean EsLiviano() { return Tipo == TipoDesperdicio.Liviano; }
}
692
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.10
* Recolector.java
* Mauricio Paletta
*/
package RecoleccionDesperdicios;
import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
public class Recolector extends ElementoGrafico {
public enum TipoRecolector {
Liviano, Pesado
}
private enum Orientacion {
Aba, Izq, Arr, Der
}
private enum Estados {
Normal, EnRecarga, EnDescarga
693
VOLVER A MEN
}
private class ThreadAgente extends Thread {
protected Semaphore Sem = new Semaphore(1);
private boolean Continuar = true;
@Override
public void run() {
try {
while (Continuar) {
Sem.acquire();
SecuenciaTeleoreactiva();
Sem.release();
// Se espera entre 250 y 1000 mseg
//
Thread.sleep(250 + Rnd.nextInt(750));
}
} catch (InterruptedException ex) {
Logger.getLogger(Recolector.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void Stop() {
Continuar = false;
}
}
private final int Dimension = 11;
private TipoRecolector Tipo;
private int Carga, Energia, Capacidad;
694
VOLVER A MEN
VOLVER A MEN
case 2:
Ojos = Orientacion.Arr;
break;
case 3:
Ojos = Orientacion.Der;
break;
}
break;
case Pesado:
switch (Rnd.nextInt(4)) {
case 0:
Ojos = Orientacion.Aba;
break;
case 1:
Ojos = Orientacion.Izq;
break;
case 2:
Ojos = Orientacion.Arr;
break;
case 3:
Ojos = Orientacion.Der;
break;
}
break;
}
Refrescar();
// Hilo de ejecucin
//
Agente = new ThreadAgente();
Agente.start();
}
696
VOLVER A MEN
VOLVER A MEN
Img = PesadoR.bmp;
break;
}
break;
}
try {
if (Img.compareTo() != 0) {
Imagen = ImageIO.read(new File(Img));
this.setIcon(new ImageIcon(Imagen));
this.repaint();
}
} catch (IOException ex) { }
}
private Point PuntoVisual(Point Pt) {
switch (Ojos) {
case Aba:
Pt.y += LaDimension();
break;
case Izq:
Pt.x -= LaDimension();
break;
case Arr:
Pt.y -= LaDimension();
break;
case Der:
Pt.x += LaDimension();
break;
}
return new Point(Pt.x, Pt.y);
}
698
VOLVER A MEN
699
VOLVER A MEN
VOLVER A MEN
}
public void AtendidoEnCentro() {
if (Estado == Estados.Normal) return;
if (Estado == Estados.EnRecarga)
Energia = Tipo == TipoRecolector.Liviano ? 100 : 200;
else {
Carga = 0;
Energia -= Tipo == TipoRecolector.Liviano ? 2 : 4;
}
// Hay que ubicar nuevamente el recolector en el rea de simulacin
//
Container P = this.getParent();
Point Pt = new Point(0, Estado == Estados.EnRecarga ? 0 : P.getHeight() - LaDimension());
while (!VerificarOcupacion(Pt)) Pt.x += LaDimension();
Ojos = (Estado == Estados.EnRecarga ? Orientacion.Aba : Orientacion.Arr);
Estado = Estados.Normal;
setLocation(Pt);
setVisible(true);
}
private Desperdicio BuscarDesperdicio(Point Pt) {
Container P = this.getParent();
for (int i=0; i < P.getComponentCount(); i++) {
Component C = P.getComponent(i);
if (C.getClass().getName().compareTo(RecoleccionDesperdicios.Desperdicio) == 0 &&
C.getX() == Pt.x && C.getY() == Pt.y)
return (Desperdicio)C;
}
701
VOLVER A MEN
return null;
}
private boolean VerificarRecogerDesperdicio() {
// Primero se busca la posible presencia de un desperdicio en la
// lnea visual del recolector
//
Point Pt = new Point(this.getX(), this.getY());
Desperdicio D;
D = BuscarDesperdicio(PuntoVisual(Pt));
if (D == null) return false;
// Se tiene un desperdicio, se verifica si el recolector lo puede recoger
//
if (((EsLiviano() && D.EsLiviano()) || !EsLiviano()) && Carga + D.ObtPeso() <= Capacidad) {
// Ver si hay energa suficiente
//
if ((D.EsLiviano() && Energia > 0) || Energia - 1 > 0) {
// Se procede a la recoleccin del desperdicio
//
Carga += D.ObtPeso();
Energia -= D.EsLiviano() ? 1 : 2;
D.Recoger();
return true;
}
}
return false;
}
public void Parar() {
Agente.Stop();
702
VOLVER A MEN
setVisible(false);
}
private void SecuenciaTeleoreactiva() {
// Si est siendo atendido en algn centro se duerme
//
if (Estado != Estados.Normal) return;
// Si se acab la energa el recolector se convierte en un desperdicio
// pesado de 10 unidades de peso
//
if (Energia <= 0) {
ElAmbiente.ConvertirRecolectorDesperdicio(this);
return;
}
// Lo primero es revisar la energa, de haber problemas hay que
// dirigirse al centro de recarga que est en la coordenada (0, 0)
//
if (Energia <= 25) {
if (this.getX() == 0 && this.getY() == 0) {
if (Ojos == Orientacion.Arr) {
// Puede entrar al centro de recarga
//
ElAmbiente.RecargarEnergia(this);
}
else {
if (Ojos == Orientacion.Der || Ojos == Orientacion.Aba)
RotarIzquierda();
else
RotarDerecha();
}
}
703
VOLVER A MEN
else {
Point Pt = new Point(this.getX(), this.getY());
if (this.getX() == 0 && Ojos == Orientacion.Izq) {
RotarDerecha();
return;
}
if (this.getY() == 0 && Ojos == Orientacion.Arr) {
RotarIzquierda();
return;
}
if ((Ojos == Orientacion.Aba || Ojos == Orientacion.Der)) {
RotarIzquierda();
return;
}
if (!Avanzar()) {
if (Rnd.nextDouble() < 0.5)
RotarIzquierda();
else
RotarDerecha();
Avanzar();
}
}
return;
}
// Lo segundo es verificar la carga, de estar casi lleno hay que ir
// al centro de descarga que est en la coordenada (0, H)
//
if (Capacidad - Carga <= 5) {
if (this.getX() == 0 && this.getParent().getHeight() - (this.getY() + LaDimension()) <
LaDimension()) {
if (Ojos == Orientacion.Aba) {
704
VOLVER A MEN
VOLVER A MEN
return;
}
// Lo tercero es verificar si tiene un desperdicio en su foco visual
// para recogerlo
//
if (VerificarRecogerDesperdicio()) return;
// Lo cuarto es decidir aleatoriamente si avanzar o rotar
//
switch (Rnd.nextInt(6)) {
case 0:
RotarIzquierda();
break;
case 1:
RotarDerecha();
break;
default:
if (!Avanzar()) {
if (Rnd.nextDouble() < 0.5)
RotarIzquierda();
else
RotarDerecha();
}
break;
}
}
}
706
VOLVER A MEN
VOLVER A MEN
SetLocation(Pt);
}
public bool VerificarOcupacion(Point Pt)
{
Control P = this.Parent;
if (Pt.X < 0 || Pt.X + Dimension > P.Width || Pt.Y < 0 || Pt.Y + Dimension > P.Height)
return false;
for (int i = 0; i < P.Controls.Count; i++)
{
Control C = P.Controls[i];
if (C != this && C.Visible && Pt.X == C.Location.X && Pt.Y == C.Location.Y) return false;
}
return true;
}
public int LaDimension
{
get { return Dimension; }
}
private delegate void SetLocationDelegate(Point Pt);
protected void SetLocation(Point Pt)
{
if (this.InvokeRequired)
this.Invoke(new SetLocationDelegate(SetLocation), Pt);
else
this.Location = new Point(Pt.X, Pt.Y);
}
private delegate void SetVisibleDelegate(bool V);
708
VOLVER A MEN
VOLVER A MEN
VOLVER A MEN
}
Peso = Ps;
}
public void Recoger()
{
Control P = this.Parent;
SetVisible(false);
RemoveControl(P);
}
public int ObtPeso() { return Peso; }
public bool EsLiviano() { return Tipo == TipoDesperdicio.Liviano; }
}
public class Recolector : ElementoGrafico
{
public enum TipoRecolector
{
Liviano, Pesado
}
private enum Orientacion
{
Aba, Izq, Arr, Der
}
private enum Estados
{
Normal, EnRecarga, EnDescarga
}
private const int Dimension = 11;
private TipoRecolector Tipo;
711
VOLVER A MEN
VOLVER A MEN
Ojos = Orientacion.Aba;
break;
case 1:
Ojos = Orientacion.Izq;
break;
case 2:
Ojos = Orientacion.Arr;
break;
case 3:
Ojos = Orientacion.Der;
break;
}
break;
case TipoRecolector.Pesado:
switch (Rnd.Next(4))
{
case 0:
Ojos = Orientacion.Aba;
break;
case 1:
Ojos = Orientacion.Izq;
break;
case 2:
Ojos = Orientacion.Arr;
break;
case 3:
Ojos = Orientacion.Der;
break;
}
break;
}
Refrescar();
713
VOLVER A MEN
// Hilo de ejecucin
//
Agente = new Thread(SecuenciaTeleoreactiva);
Agente.Start();
}
private void Refrescar()
{
string Img = ;
switch (Tipo)
{
case TipoRecolector.Liviano:
switch (Ojos)
{
case Orientacion.Aba:
Img = LivianoD.bmp;
break;
case Orientacion.Izq:
Img = LivianoL.bmp;
break;
case Orientacion.Arr:
Img = LivianoU.bmp;
break;
case Orientacion.Der:
Img = LivianoR.bmp;
break;
}
break;
case TipoRecolector.Pesado:
switch (Ojos)
{
case Orientacion.Aba:
714
VOLVER A MEN
Img = PesadoD.bmp;
break;
case Orientacion.Izq:
Img = PesadoL.bmp;
break;
case Orientacion.Arr:
Img = PesadoU.bmp;
break;
case Orientacion.Der:
Img = PesadoR.bmp;
break;
}
break;
}
if (Img != ) this.Load(Img);
}
private Point PuntoVisual(Point Pt)
{
switch (Ojos)
{
case Orientacion.Aba:
Pt.Y += LaDimension;
break;
case Orientacion.Izq:
Pt.X -= LaDimension;
break;
case Orientacion.Arr:
Pt.Y -= LaDimension;
break;
case Orientacion.Der:
Pt.X += LaDimension;
715
VOLVER A MEN
break;
}
return new Point(Pt.X, Pt.Y);
}
public bool Avanzar()
{
Point Pt = new Point(this.Location.X, this.Location.Y);
if (Energia <= 0) return false;
Pt = PuntoVisual(Pt);
if (!VerificarOcupacion(Pt)) return false;
SetLocation(Pt);
Energia--;
return true;
}
public void RotarIzquierda()
{
if (Energia <= 0) return;
switch (Ojos)
{
case Orientacion.Aba:
Ojos = Orientacion.Der;
break;
case Orientacion.Der:
Ojos = Orientacion.Arr;
break;
case Orientacion.Arr:
Ojos = Orientacion.Izq;
break;
case Orientacion.Izq:
Ojos = Orientacion.Aba;
716
VOLVER A MEN
break;
}
Energia--;
Refrescar();
}
public void RotarDerecha()
{
if (Energia <= 0) return;
switch (Ojos)
{
case Orientacion.Aba:
Ojos = Orientacion.Izq;
break;
case Orientacion.Izq:
Ojos = Orientacion.Arr;
break;
case Orientacion.Arr:
Ojos = Orientacion.Der;
break;
case Orientacion.Der:
Ojos = Orientacion.Aba;
break;
}
Energia--;
Refrescar();
}
public bool EsLiviano()
{
return Tipo == TipoRecolector.Liviano;
717
VOLVER A MEN
}
public void AtenderEnRecarga()
{
Estado = Estados.EnRecarga;
SetVisible(false);
}
public void AtenderEnDescarga()
{
Estado = Estados.EnDescarga;
SetVisible(false);
}
public void AtendidoEnCentro()
{
if (Estado == Estados.Normal) return;
if (Estado == Estados.EnRecarga)
Energia = Tipo == TipoRecolector.Liviano ? 100 : 200;
else
{
Carga = 0;
Energia -= Tipo == TipoRecolector.Liviano ? 2 : 4;
}
// Hay que ubicar nuevamente el recolector en el rea de simulacin
//
Control P = this.Parent;
Point Pt = new Point(0, Estado == Estados.EnRecarga ? 0 : P.Height - LaDimension);
while (!VerificarOcupacion(Pt)) Pt.X += LaDimension;
Ojos = (Estado == Estados.EnRecarga ? Orientacion.Aba : Orientacion.Arr);
Estado = Estados.Normal;
718
VOLVER A MEN
SetLocation(Pt);
SetVisible(true);
}
private Desperdicio BuscarDesperdicio(Point Pt)
{
Control P = this.Parent;
for (int i=0; i < P.Controls.Count; i++)
{
Control C = P.Controls[i];
if (C is Desperdicio && C.Location.X == Pt.X && C.Location.Y == Pt.Y)
return C as Desperdicio;
}
return null;
}
private bool VerificarRecogerDesperdicio()
{
// Primero se busca la posible presencia de un desperdicio en la
// lnea visual del recolector
//
Point Pt = new Point(this.Location.X, this.Location.Y);
Desperdicio D;
D = BuscarDesperdicio(PuntoVisual(Pt));
if (D == null) return false;
// Se tiene un desperdicio, se verifica si el recolector lo puede recoger
//
if (((EsLiviano() && D.EsLiviano()) || !EsLiviano()) && Carga + D.ObtPeso() <= Capacidad)
{
719
VOLVER A MEN
720
VOLVER A MEN
Sem.WaitOne();
// Si se acab la energa el recolector se convierte en un desperdicio
// pesado de 10 unidades de peso
//
if (!Accion && Energia <= 0)
{
ElAmbiente.ConvertirRecolectorDesperdicio(this);
Sem.Release();
break;
}
// Lo primero es revisar la energa, de haber problemas hay que
// dirigirse al centro de recarga que est en la coordenada (0, 0)
//
if (!Accion && Energia <= 25)
{
if (this.Location.X == 0 && this.Location.Y == 0)
{
if (Ojos == Orientacion.Arr)
{
// Puede entrar al centro de recarga
//
ElAmbiente.RecargarEnergia(this);
}
else
{
if (Ojos == Orientacion.Der || Ojos == Orientacion.Aba)
RotarIzquierda();
else
RotarDerecha();
}
}
721
VOLVER A MEN
else
{
Point Pt = new Point(this.Location.X, this.Location.Y);
if (this.Location.X == 0 && Ojos == Orientacion.Izq)
{
RotarDerecha();
Accion = true;
}
if (!Accion && this.Location.Y == 0 && Ojos == Orientacion.Arr)
{
RotarIzquierda();
Accion = true;
}
if (!Accion && (Ojos == Orientacion.Aba || Ojos == Orientacion.Der))
{
RotarIzquierda();
Accion = true;
}
if (!Accion)
{
if (!Avanzar())
{
if (Rnd.NextDouble() < 0.5)
RotarIzquierda();
else
RotarDerecha();
Avanzar();
}
Accion = true;
}
}
Accion = true;
}
722
VOLVER A MEN
VOLVER A MEN
}
if (!Accion && (Ojos == Orientacion.Arr || Ojos == Orientacion.Der))
{
RotarDerecha();
Accion = true;
}
if (!Accion)
{
if (!Avanzar())
{
if (Rnd.NextDouble() < 0.5)
RotarDerecha();
else
RotarIzquierda();
Avanzar();
}
Accion = true;
}
}
Accion = true;
}
// Lo tercero es verificar si tiene un desperdicio en su foco visual
// para recogerlo
//
if (!Accion && VerificarRecogerDesperdicio()) Accion = true;
// Lo cuarto es decidir aleatoriamente si avanzar o rotar
//
if (!Accion)
{
switch (Rnd.Next(6))
724
VOLVER A MEN
{
case 0:
RotarIzquierda();
break;
case 1:
RotarDerecha();
break;
default:
if (!Avanzar())
{
if (Rnd.NextDouble() < 0.5)
RotarIzquierda();
else
RotarDerecha();
}
break;
}
}
// Se espera entre 250 y 1000 mseg
//
Sem.Release();
Thread.Sleep(250 + Rnd.Next(750));
}
}
}
}
725
VOLVER A MEN
/*
* Modelado y programacin Orientado a Objetos: Un enfoque prctico
* Desarrollo en Java; caso prctico Seccin 6.9
* Ambiente.cs
* Mauricio Paletta
*/
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
namespace RecoleccionDesperdicios
{
public class Centro
{
private bool Ocupado;
private Queue<Recolector> ColaAtencion;
private Recolector EnAtencion;
private Timer TiempoAtencion;
private int UnidadesTiempo;
public Centro()
{
Ocupado = false;
EnAtencion = null;
ColaAtencion = new Queue<Recolector>();
UnidadesTiempo = 0;
TiempoAtencion = new Timer();
TiempoAtencion.Interval = 1000;
TiempoAtencion.Tick += TiempoAtencionTick;
TiempoAtencion.Enabled = true;
}
726
VOLVER A MEN
VOLVER A MEN
EnAtencion = null;
UnidadesTiempo = 0;
if (ColaAtencion.Count > 0)
{
EnAtencion = ColaAtencion.Dequeue();
Ocupado = true;
}
}
public bool EstaOcupado() { return Ocupado; }
public int CantidadColaAtencion() { return ColaAtencion.Count; }
}
public class Ambiente
{
private Centro RecargaEnergia, DescargaDesperdicio;
private List<Desperdicio> Desperdicios;
private List<Recolector> Recolectores;
private List<Recolector> ParaDesperdicios;
private Timer TiempoParaDesperdicios;
public Ambiente()
{
RecargaEnergia = new Centro();
DescargaDesperdicio = new Centro();
Desperdicios = new List<Desperdicio>();
Recolectores = new List<Recolector>();
ParaDesperdicios = new List<Recolector>();
TiempoParaDesperdicios = new Timer();
TiempoParaDesperdicios.Interval = 250;
TiempoParaDesperdicios.Enabled = true;
TiempoParaDesperdicios.Tick += TiempoParaDesperdiciosTick;
}
728
VOLVER A MEN
VOLVER A MEN
}
public void ConvertirRecolectorDesperdicio(Recolector R)
{
if (R == null) return;
ParaDesperdicios.Add(R);
}
public bool CentroRecargaOcupado()
{
return RecargaEnergia.EstaOcupado();
}
public bool CentroDescargaOcupado()
{
return DescargaDesperdicio.EstaOcupado();
}
public int NumRecolectores()
{
return Recolectores.Count;
}
public int NumDesperdicios()
{
return Desperdicios.Count;
}
public int NumRecolectoresColaRecarga()
{
return RecargaEnergia.CantidadColaAtencion();
}
public int NumRecolectoresColaDescarga()
{
return DescargaDesperdicio.CantidadColaAtencion();
730
VOLVER A MEN
}
public void RecargarEnergia(Recolector R)
{
R.AtenderEnRecarga();
RecargaEnergia.Atender(R, true);
}
public void DescargarDesperdicio(Recolector R)
{
R.AtenderEnDescarga();
DescargaDesperdicio.Atender(R, false);
}
public void Detener()
{
for (int i = 0; i < Recolectores.Count; i++)
Recolectores[i].Parar();
}
}
}
731
VOLVER A MEN
6.11 Ejercicios
1) Manejo de redes semnticas. Se desea que desarrolle una aplicacin que permita
administrar la informacin relativa a una Red Semntica (RS). Una RS es una forma de
representacin de conocimiento lingstico en la cual, las interrelaciones entre diversos
conceptos o elementos semnticos, se les da la forma de un grafo. Las RSs pueden ser
mapas conceptuales y mentales y estn formadas por un conjunto de elementos semnticos
o conceptos (nodos) y relaciones semnticas (aristas) entre esos conceptos. Por ejemplo, si
se tienen los conceptos {Vrtebra, Gato, Pelo, Mamfero, Animal, Oso, Pez, Agua, Ballena}
y las relaciones {tiene, es un, vive en} un ejemplo de RS con estos conjuntos es la que
se muestra en la Figura 6.70.
VOLVER A MEN
VOLVER A MEN
i) Los robots tienen una fuente de energa limitada que viene dada inicialmente por una
cantidad aleatoria entre 50 y 100 unidades de energa. El robot gasta una unidad de energa
por cada movimiento que realiza, ya sea de desplazamiento o de posesin / liberacin de
pelotas. Un robot que llega a una fuente de energa baja (5 unidades de energa), cambia
su estado al de energa baja y queda condenado a permanecer esttico en su celda actual
hasta que sea recogido por un robot recolector. En el caso de que un robot que est en este
estado tenga posesin de alguna pelota, deber liberarla cuando pueda, en alguna de las
celdas vecinas que queden libres, haciendo uso de lo poco que le queda de energa.
j) Un robot recolector es un tipo especial de robot cuyo objetivo es limpiar el campo de robots
en estado de baja energa y sin posesin de pelotas. Tienen energa ilimitada y capacidad
de visin y desplazamiento de una celda de alcance en toda su vecindad de Von Neumann
(arriba, abajo, a la derecha y a la izquierda). Tienen una capacidad para albergar y transportar
hasta tres robots. El nmero de robots recolectores es variable para la simulacin y debe
estar entre un mnimo de 1 y un mximo de 4. Al igual que el resto de los robots, tienen
su oportunidad de accin en cada iteracin de tiempo de la simulacin, slo despus de
que todos los robots jugadores de ambos equipos hayan culminado su actividad por cada
iteracin ( a menos que se escoja el camino de implementacin por hilos de ejecucin).
k) Una vez que un robot recolector alcanza su cota mxima de carga, debe trasladarse a
uno de los centros de descarga que se encuentran en la parte central, a ambos lados
(superior e inferior) del rea de la simulacin. Se requiere 1 unidad de tiempo por cada
robot a descargar, es decir, 3 unidades de tiempo en total para liberarse completamente de
la carga. Cada centro de descarga puede albergar slo a un robot recolector y no admite
robots recolectores que no tengan un mximo de carga acumulada.
l) La posicin inicial de las pelotas y los robots se asignar de forma aleatoria previo al inicio
de la simulacin.
m) Los depsitos de pelotas de los equipos tienen un tamao equivalente a tres celdas colocadas
en lnea recta. Los centros de descarga tienen un tamao equivalente a una celda.
n) La competencia termina cuando se alcanza el tiempo mximo de iteraciones indicado previo
al inicio de la simulacin, se hayan recolectado y ubicado en los depsitos todas las pelotas
en juego o, no queden robots para ninguno de los equipos.
734
VOLVER A MEN
La Figura 6.71 muestra un ejemplo con un rea de juego en una matriz de 9 x 15 celdas.
VOLVER A MEN
VOLVER A MEN
a) Agregar / suprimir bicicletas y estaciones de bicicletas. Hay que tomar en cuenta que
no todas las bicicletas deben estar necesariamente ubicadas en una estacin. Pueden
estar tambin en un depsito de almacenamiento y/o en mntenimiento.
b) Dar el servicio de alta / baja a los usuarios. Las renovaciones del servicio se realizan de
manera automtica siempre y cuando sea posible hacer el cobro de la anualidad en la
tarjeta de crdito inicialmente dada por el usuario en el momento de su inscripcin. Los
usuarios pueden darse de baja en el servicio en cualquier momento.
c) Prestar el servicio segn lo explicado anteriormente.
d) Calcular los montos que cada usuario debe pagar mensualmente con base a las
penalidades que se tengan por romper las reglas del servicio.
4) Sistema metro. La Unidad de Planificacin Urbana de la Comunidad Econmica Europea
(UPUCEE) ha decidido instalar sistemas automatizados que permitan a los usuarios del
metro de una ciudad, conocer la forma ms rpida de llegar de una estacin a otra. El
plan es instalar en cada estacin un terminal corriendo un programa que permita ingresar
la estacin de destino y suministre como salida las indicaciones necesarias para que el
usuario pueda llegar rpida y felizmente a sus destino.
La UPUCEE ha solicitado sus servicios como analista para el diseo y elaboracin del
programa que debe correr en cada estacin. Dicho programa debe ser lo ms general
posible para que pueda ser adaptado sin dificultad a las configuraciones particulares del
sistema de metro de cualquier ciudad.
La UPUCEE ha suministrado el siguiente extracto de un informe, resumiendo las
caractersticas ms importantes de los sistemas de metro de los pases de la CEE:
El metro es un sistema de transporte urbano diseado especialmente para proveer un
servicio confiable y eficaz para la movilizacin masiva de personas. El metro est constituido
bsicamente por vas y estaciones dedicadas, que permiten el desplazamiento de trenes
a una velocidad constante, lo cual hace que el tiempo de viaje entre estaciones vare muy
poco. Una lnea es un conjunto de vas de estaciones que son recorridas nicamente
por determinados trenes. Para viajar entre dos estaciones que pertenecen a una misma
lnea, no es necesario cambiar de tren. En caso de que se quiera viajar entre estaciones
de dos lneas diferentes, ser necesario hacer un cambio de tren en alguna estacin de
transferencia. En ocasiones es posible que se deba hacer ms de una transferencia entre
lneas para alcanzar el destino.
Para ilustrar los conceptos, considere la Figura 6.72. En este caso el sistema de metro
tiene 23 estaciones, cuatro lneas A, B, C y D (ntese que la lnea D no para en todas
las estaciones de la lnea C). Cualquier estacin por la que pase ms de una lnea es
una estacin de transferencia (T1, T2 y T3 en la Figura 6.72). Por ejemplo, para ir de la
737
VOLVER A MEN
VOLVER A MEN
5) Grafo de flujo. Se define a continuacin un lenguaje intermedio para escribir cierto tipo de
programas. Un programa en este contexto consiste de una secuencia de instrucciones
cada una de las cuales puede estar etiquetada por un identificador. Existen cinco tipos
bsicos de instrucciones: asignacin, salto, condicional, entrada-salida y parar:
a) Una asignacin es una cadena de caracteres de la forma A f B1Br donde A es una
variable y B1, , Br son variables o constantes. es una operacin r-aria (una instruccin
de la forma A B cae dentro de esta categora).
b) Un salto es una instruccin de la forma SALTO <etiqueta> donde <etiqueta> es una
cadena de caracteres alfabticos. Si se usa la instruccin SALTO en un programa
entonces la etiqueta que precede a la palabra SALTO debe aparecer como etiqueta en
una instruccin en el programa.
c) Un condicional es de la forma SI A <relacin> B SALTO <etiqueta> donde A y B son
variables o constantes y <relacin> es una operacin relacional vlida del tipo: <=, =,
<>, >=, < y >.
d) Una instruccin entrada-salida es una instruccin de lectura de la forma LEER A donde
A es una variable o una instruccin de escritura, o una instruccin de escritura ESCRIBIR
B donde B es una variable o una constante.
e) PARAR es una instruccin que termina la ejecucin del programa.
739
VOLVER A MEN
BLOQUE 1
LEER p
LEER q
SI r = 0 SALTO listo
BLOQUE 3
pq
qr
SALTO lazo
PARAR
740
VOLVER A MEN
741
VOLVER A MEN
742
VOLVER A MEN
Referencias
y Bibliografa sugerida
Aho, A.V., Hopcroft, J.E. y Ullman, J.D. (1983). Data Structures & Algorithms. AddisonWesley, ISBN: 0201000237.
Atwood, T. (1985). An Object-Oriented DBMS for Design Support Applications. Proceedings of
the IEEE COMPINT 85, pp. 299-307.
Booch, G.(1993).Object-oriented Analysis and Design with Applications(2nd ed.). Redwood
City: Benjamin Cummings.ISBN:0-8053-5340-2.
Booch, G. (1996). Anlisis y Diseo Orientado a Objetos. Addison Wesley Longman 2da.
Edicin, ISBN: 978-9684443525.
Brassard, G. y Bratley, P. (1997). Fundamentos de Algoritmia. Prentice Hall, ISBN: 978-8489660-00-7.
Brooks, F. (1987). No Silver Bullet: Essence and Accidents of Software Engineering. IEEE
Computer, Vol. 20, Nro. 4, p. 1.
Burbeck, S. (1987). Applications Programming in Smalltalk-80(TM): How to use Model-ViewController (MVC). Disponible en http://st-www.cs.illinois.edu/users/ smarch/st-docs/mvc.html
(ltima vez consultado en junio de 2012).
Cockshott, P.,McCaskill, G.yBarrie, P. (1993). Realising massively concurrent systems on
the SPACE machine. En FPGAs for Custom Computing Machines, IEEE Workshop, pp. 26-32.
Cohoon, J. y Davidson, J. (2005). Programacin en Java 5.0. McGraw-Hill, ISBN: 84-4815061-9.
Corner, D.S. (2008). Deadlock Detection Using DTrace. CS 671 Project I, OS Observability
Tools. Disponible en http://cs.gmu.edu/~hfoxwell/ cs671projects/corner_DT.pdf (ltima vez
consultado en agosto de 2012).
Derrett, N., Kent, W. y Lyngbaek, P. (1985). Some Aspects of Operations in an Object-Oriented
Database.Database Engineering, Vol. 8, Nro. 4, IEEE Computer Society.
Dijkstra, E. (1979). Programming Considered as a Human activity. Classics in Software
Engineering, New York.
743
VOLVER A MEN
Ferguson, J., Patterson, B., Beres, J., Boutquin, P. y Gupta, M. (2003). La biblia de C#.
Anaya Multimedia. ISBN: 84-415-1484-4.
Goldberg, A., y Robson, D. (1983). Smalltalk-80: The Language and its Implementation.
Addison-Wesley, Readig, Massachusetts.
Goodrich, M.T. y Tammassia R. (2006). Data Structures & Algorithms in Java. John Wiley &
Sons, Inc., ISBN: 0-471-73884-0.
Grahan, I. (1996). Mtodos Orientados a Objetos. Addison-Wesley, ISBN: 0-201-65355-9.
Holt, R.C. (1972). Some Deadlock Properties of Computer Systems. Computing Surveys, Vol.
4, Nro. 3, pp. 179-196.
Jacobson, I. (1992). Object-Oriented Software Engineering: A Use Case Driven Approach.
Addison-Wesley, ISBN: 0-201-54435-0.
Koffman, E.B. y Wolfgang, P.A. (2008). Estructura de datos con C++. Objetos, abstracciones
y diseo. McGraw Hill. ISBN: 0-471-46755-3.
Lafore, R. (2003). Data Structures & Algorithms in Java. SAMS, ISBN: 0-672-32453-9.
Lewis, J. y Chase, J. (2006). Estructuras de datos con Java Diseo de estructuras y
algoritmos. Addison-Wesley, ISBN: 84-205-5034-5.
Maier, D., Otis, A. y Purdy, A. (1985). Object-Oriented Database Development at Servio
Logic.Database Engineering, Vol. 18, Nro.4, IEEE Computer Society.
Meyer,
B.
(1998).
Costruccin
de
Software
Orientado
Objetos.
Prentice-Hall,
ISBN:9788483220405.
Nilsson, N.J. (1994). Teleo-Reactive Programs for Agent Control, Journal of Artificial Intelligence
Research, 1 pp. 139158.
Oestereich, B. (2001). Developing Software with UML Object-Oriented Analysis and Design
in Practice. Addison-Wesley, ISBN: 0-201-75603-X.
Rumbaugh, J., Blaha, M., Premerlani, W., Eddy, F., y Lorensen, W. (1990).Object-Oriented
Modeling and Design. Prentice Hall.ISBN 0-13-629841-9.
Rumbaugh, J., Jacobson, I. y Booch, G. (1999). The Unified Modeling Language Reference
Manual. Addison-Wesley, ISBN: 0-201-30998-X.
Russell, N. (1995). Artificial Intelligence: A Modern Approach, Prentice Hall.
Seco, A.A., Gallego, J.J., Lafuente, E.E., Guzmn, J.G., Snchez, L.G., Fernndez, P.M.
744
VOLVER A MEN
745
VOLVER A MEN
ndice de Figuras
Figura 1.1. Hacer descomposicin, abstraccin y jerarqua para salir del caos
(imagen realizada por Juan C. Candelori / www.pietrogiordano.info).
13
20
23
24
38
41
42
45
46
49
49
57
58
58
59
59
60
60
61
62
63
746
64
65
VOLVER A MEN
66
66
66
67
68
68
69
69
69
70
70
71
71
72
72
73
74
75
76
77
78
79
80
80
81
81
83
747
83
93
VOLVER A MEN
94
94
95
96
97
97
Figura 4.8. Ejemplo del acceso de los elementos de una clase en C++.
98
Figura 4.9. Ejemplo del acceso de los elementos de una clase en Java / C#.
99
99
100
100
102
102
103
104
104
105
106
106
107
108
109
109
111
111
113
114
115
116
VOLVER A MEN
116
117
118
118
119
119
120
120
121
Figura 4.40. Ejemplo de cmo resolver ambigedades en una herencia mltiple en C++.
121
Figura 4.41. Ejemplo de cmo resolver redundancias en una herencia mltiple en C++.
122
123
123
124
124
125
125
126
126
Figura 4.50. Ejemplo de la definicin de una clase abstracta y un mtodo virtual en C++.
127
Figura 4.51. Ejemplo de la definicin de una clase abstracta y un mtodo virtual en Java.
127
Figura 4.52. Ejemplo de la definicin de una clase abstracta y un mtodo virtual en C#.
128
128
129
129
130
1130
132
132
749
de parmetros en un mtodo.
133
Figura 4.61. Ejemplo del uso de plantillas en C++ para la generalizacin de una clase.
133
VOLVER A MEN
Figura 4.62. Ejemplo del uso de plantillas en C++ para la especializacin de una clase.
134
134
135
135
136
136
136
137
138
139
140
140
141
141
142
143
144
144
146
149
Figura 5.2. Ejemplo de mapa mental realizado en XMind 2012, versin 3.3.0.
151
156
158
160
163
164
164
165
165
166
166
750
VOLVER A MEN
167
168
169
169
170
170
175
176
177
177
178
179
179
221
222
222
223
224
224
225
225
242
Figura 6.17. Diagrama de casos de uso relativo al problema del ambiente para el
manejo de conjuntos.
243
244
Figura 6.19. Diagrama detallado de clases relativo al problema del ambiente para
el manejo de conjuntos.
245
Figura 6.20. Diagramas de estado relativos al problema del ambiente para el manejo
de conjuntos.
245
VOLVER A MEN
246
246
Figura 6.23. Mapa mental relativo al problema del manejo inteligente de colas de atencin.
299
Figura 6.24. Diagrama de casos de uso relativo al problema del manejo inteligente
de colas de atencin.
300
301
303
304
305
306
390
390
Figura 6.32. Diagrama de casos de uso relativo al problema del generador de energa.
391
Figura 6.33. Diagrama no detallado de clases relativo al problema del generador de energa.
391
Figura 6.34. Diagrama detallado de clases relativo al problema del generador de energa.
392
393
393
394
417
417
418
419
420
421
422
422
VOLVER A MEN
460
Figura 6.47. Mapa mental relativo al problema del grafo de asignacin de recursos.
461
Figura 6.48. Diagrama de casos de uso relativo al problema del grafo de asignacin
de recursos.
462
463
463
464
464
465
513
515
515
516
517
518
519
519
549
Figura 6.63. Mapa mental relativo al problema de los agentes recolectores de desperdicio.
651
Figura 6.64. Diagrama de casos de uso relativo al problema de los agentes recolectores
de desperdicio.
753
VOLVER A MEN
652
653
653
654
654
655
732
754
de agentes en competencia.
735
739
741
VOLVER A MEN
ndice de Tablas
Tabla 1.1. Preguntas bsicas relativas a hacer OO.
18
20
21
22
44
84
85
162
173
755
de operaciones bsicas.
174
242
VOLVER A MEN
A
Abstraccin, 18, Vase Principios de la OO
Agente, 451
Agregacin, 49
Anlisis OO, 165
Archivo
Binario, 239
de eventos, 236
Manejo, 235
Asociaciones incorrectas o innecesarias, 169
Atributo, 43, 47
Introduccin, 22
Autmata celular, 218
B
Biblioteca de clases, 163
C
C#
Acceso a los elementos, 105
Atributo, 102
Atributos, 156
Clase abstracta, 138
Clases anidadas, 153
Clases y mtodos finales, 150
Constructor, 107
Constructor esttico, 151
Conversin entre clases, 154
Definicin de clase, 102
Delegados y eventos, 155
Elementos estticos, 117
756
VOLVER A MEN
ndice
VOLVER A MEN
Clase, 47
Abstracta, 53
Clase base. Vase superclase
clase derivada. Vase subclase
Detalle, 174
Diagrama. Vase diagrama de clases de UML
Incorrectas o innecesarias, 168
Interfaz, 48
Introduccin, 21
Redundante, 168
Complejidad del software, 14
Crisis del software, 13
D
Descomposicin, 16
Diseo OO, 173
Divide y vencers, 16
E
Encapsulamiento. Vase Principios de la OO
Enlace dinmico. Vase trmino tcnico de la orientacin a objetos
Espaguetis electrnico, 18
Especializacin, 50
Extend. Vase relacin de extensin de UML
G
GAR, 354
Generalizacin, 50
Grafo, 189
H
Herencia, 48, 50
Mltiple, 50
Simple, 50
758
VOLVER A MEN
Hilos
Manejo, 457
I
Include. Vase relacin de inclusin de UML
Instanciacin de objetos, 35
Interfaz
De la herencia, 54
Interfaz del objeto, 33
Interfaz grfica, 317
J
Java, 48
Acceso a los elementos, 105
Clase abstracta, 138
Clases anidadas, 149
Clases y mtodos finales, 149
Constructor, 107
Definicin de clase, 102
Elementos estticos, 116
Herencia, 132
Instanciacin de objetos, 104
Interfaces, 133
Mtodo de finalizacin, 113
Mtodo virtual, 138
Operador de asignacin o copia, 118
Paquetes, 141
Polimorfismo, 109
Referencia al objeto actual, 125
Jerarqua, 18
L
Lenguaje de modelado unificado
Actor, 62
759
VOLVER A MEN
Agregacin, 76
Asociacin cualificada, 74
Clase de utilidad, 78
Clase parametrizada, 78
Componentes, 60
Diagrama, 61
Diagrama de actividad, 68
Diagrama de cambio de estados, 82
Diagrama de casos de uso, 62
Diagrama de clases, 49, 70
Diagrama de colaboracin, 85
Diagrama de componentes, 84
Diagrama de distribucin, 88
Diagrama de objetos, 81
Diagrama de secuencia, 86
Elementos del modelo, 62
Estereotipos, 90
Generalizacin, 71
Interfaz, 77
Paquete, 79
Refinamiento, 72
Relacin de extensin, 64
Relacin de inclusin, 65
Restricciones, 89
Resumen de la sintaxis, 91
Valores etiquetados, 89
Vista, 60
Lenguaje de Modelado Unificado, 27
M
Mensaje, 45
Mtodo, 43, 45, 47
Introduccin, 22
Virtual, 53
760
VOLVER A MEN
O
Objeto, 43
Comportamiento, 45
Diagrama. Vase diagrama de objetos de UML
Estado, 43
Identidad, 44
Introduccin, 22
OO. Vase Orientacin a Objetos
Orientacin a Objetos
Beneficios, 21
Conceptos bsicos, 43
Definicin, 19
Diferencias con la descomposicin funcional, 22
Fundamentos, 31
Historia, 23
Origen, 13
761
VOLVER A MEN
Principios, 31
Trmino tcnico, 41
Paquete, 48
Plantilla
Manejo, 241
Polimorfismo
por inclusin, 52
Principios de la OO
Abstraccin, 31
Concurrencia, 39
Encapsulamiento, 33
Jerarqua, 37
Modularidad, 34
Persistencia, 39
Polimorfismo, 39
Tipos, 38
Problemas, 189
Agentes recolectores, 451
Conquista del nuevo mundo, 383
Fbrica de galletas, 330
Generador de energa, 314
Grafo de asignacin de recursos, 354
La calculadora de operaciones bsicas, 190
Manejo de conjuntos, 234
Manejo inteligente de colas, 266
Simulacin de trfico, 218
Protocolo de un objeto, 47
R
Reusabilidad de elementos, 21
S
Secuencias Teleoreactivas, 452
762
VOLVER A MEN
Simula, 23
Smalltalk, 23
Sonido
Manejo, 189
Subclase, 50
Superclase, 50
U
UML. Vase Lenguaje de Modelado Unificado
X
XML, 270
763
VOLVER A MEN