fundamentos de programacion orientada a objetos

114
Fundamentos de Programación Ing. En Sistemas Computacionales Realizados por: Ing. Jorge Eloy Toledo Coronel 1 Unidad I Conceptos básicos del modelo orientado a objetos 1.1.- Reconocimi9ento de los Objetos y Clases en el mundo real y la Iteración entre ellos. 1.2.- La Abstracción y el Encapsulamiento como proceso natural 1.3.- La POO y la complejidad del Software 1.4.- Conceptos del ciclo de vida del software 1.5.- Elementos primordiales en el modelo de objetos

Upload: peponmf-magallanes

Post on 15-Dec-2015

13 views

Category:

Documents


2 download

DESCRIPTION

fundamentos de programación orientada a objetos

TRANSCRIPT

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

1

Unidad I

Conceptos básicos del modelo orientado a objetos

1.1.- Reconocimi9ento de los Objetos y Clases en el mundo real y la Iteración entre ellos.

1.2.- La Abstracción y el Encapsulamiento como proceso natural

1.3.- La POO y la complejidad del Software

1.4.- Conceptos del ciclo de vida del software

1.5.- Elementos primordiales en el modelo de objetos

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

2

1.1.- Reconocimi9ento de los Objetos y Clases en el mundo real y la Iteración entre ellos.

Objeto

Las personas tienen una idea clara de lo que es un objeto: conceptos adquiridos que nos permiten sentir y razonar acerca de las cosas del mundo. Un objeto podría ser real o abstracto, por ejemplo una organización, una factura, una figura en un dibujador, una pantalla de usuario, un avión, un vuelo de avión, etc. En el análisis y diseño orientados a objetos (OO), interesa el comportamiento del objeto. Si se construye software, los módulos de software OO se basan en los tipos de objetos. El software que implanta el objeto contiene estructuras de datos y operaciones que expresan dicho comportamiento. Las operaciones se codifican como métodos. Las representación en software OO del objeto es entonces una colección de tipos de datos y objetos. Entonces, dentro del software orientado a objeto, un objeto es cualquier cosa, real o abstracta, acerca de la cual almacenamos datos y los métodos que controlan dichos datos. Un objeto puede estar compuesto por otros objetos. Estos últimos a su vez también pueden estar compuestos por otros objetos. Esta intrincada estructura es la que permite construir objetos muy complejos.

Tipo de Objeto

Los conceptos que poseemos se aplican a tipos determinados de objetos. Por ejemplo, empleado se aplica a los objetos que son personas empleadas por alguna organización. Algunas instancias de empleado podrían ser Juan Pérez, José Martínez, etc. En el análisis orientado a objetos, estos conceptos se llaman tipos de objetos; las instancias se llaman objetos. Así, un tipo de objeto es una categoría de objeto, mientras que un objeto es una instancia de un tipo de objeto. En el mundo de las bases de datos existen los tipos de entidad, como cliente o empleado. Existen muchas instancias de cada tipo de entidad (como Juan Pérez o José Martínez para el tipo de entidad empleado). Del mismo modo, en OO se define tipos de objetos e instancias de tipo de objeto. Sin embargo, el término objeto tiene diferencias fundamentales con el término entidad, ya que la entidad sólo se refiere a los datos, mientras que objeto se refiere a los datos y a los métodos mediante los cuales se controlan a los propios datos. En OO, la estructura de datos y los métodos de cada tipo de objeto se manejan juntos. No se puede tener acceso o control de la estructura de datos excepto mediante los métodos que forman parte del tipo de objeto.

Identificar los objetos. Para ello examine la aplicación e identifique las distintas estructuras de datos, algunos tips a tener en cuenta son los siguientes:

1.- El nombre de la aplicación a veces nos da la del nombre del objeto principal

2.- Los objetos software pueden imitar el mundo real, modelizando las propiedades de los objetos a través de variables Cualquier propiedad de un objeto puede ser identificada dentro del objeto correspondiente a través de variables.

3.- Los objetos no se han de corresponder siempre con objetos físicos, sino que también pueden ser entidades que se utilizan dentro de la construcción del programa.

4.- Piense en el objeto en <<primera persona>>. Este truco nos puede identificar claramente los atributos y sus operaciones asociadas: <<Soy un cuadrado y me muevo, giro, agrando y reduzco. Las partes que me componen son los puntos de mis vértices>>.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

3

5.- Una clase es un tipo de dato que puede ser usado para declarar objetos, de la misma forma que una estructura es un tipo definido por el usuario que puede utilizarse para declarar variables.

Interacción entre objetos

§ Los objetos interactúan para realizar colectivamente los servicios ofrecidos por las aplicaciones. Los diagramas de interacción muestran cómo se comunican los objetos en una interacción

§ Existen dos tipos de diagramas de interacción: el Ddiagrama de Ccolaboración y el Diagrama de Ssecuencia

Clase

El término clase se refiere a la implantación en software de un tipo de objeto. El tipo de objeto es una noción de concepto. Especifica una familia de objetos sin estipular la forma en que se implanten. Los tipos de objetos se especifican durante el análisis OO. Así, una clase es una implantación de un tipo de objeto. Especifica una estructura de datos y los métodos operativos permisibles que se aplican a cada uno de sus objetos. Características: § La clase define el ámbito de definición de un conjunto de objetos § Cada objeto pertenece a una clase § Los objetos se crean por instanciación de las clases

§ Cada clase se representa en un rectángulo con tres compartimientos:

• nombre de la clase • atributos de la clase • operaciones de la clase

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

4

Motocicletacolorcilindradavelocidad máxima

arrancar()acelerar()frenar()

lista

primero()ultimo()añadir()quitar()cardinalidad()

pila

apilar()desapilar()cardinalidad()

Representación Grafica de una clase

Otros ejemplos:

1.2.- Abstracción de Datos:

Introducción

Los tipos definidos por el usuario o tipos abstractos de datos (TAD) empaquetan elementos dato con las operaciones que se realizan sobre esos datos. C++ soporta los TAD con el tipo clase que puede ser implementado con estructuras, uniones y clases.

Abstracción de datos

Una característica importante de cualquier lenguaje de programación es la capacidad de crear tipos de datos definidos por el usuario. Aunque se pueden crear en C sus propios tipos, utilizando las palabras reservadas typedef y struct, los tipos resultantes no se pueden integrar fácilmente en el resto del programa. Además, en C, sólo se pueden definir los tipos en términos

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

5

de datos; es decir, las funciones utilizadas para manipular esos tipos no son parte de la definición del tipo.

Una definición de un tipo que incluye datos y funciones y el modo para encapsular los detalles, se conoce como tipo abstracto de dato. En C++ se implementa mediante el uso de tipos de datos definidos por el usuario, llamados clases. clase = datos + funciones

Una diferencia importante entre C y C++, es que en C++ se pueden declarar funciones dentro de una estructura (no se requiere declarar punteros a funciones). Las estructuras pueden tener también especificadas regiones de acceso (medios en que se puede controlar el acceso a los datos).

La abstracción de datos en C++ se obtiene con los tipos de datos estructura (struct) y clase (class).

Concepto de clase

Una clase es un tipo de dato que contiene uno o más elementos dato llamados miembros dato, y cero, una o más funciones que manipulan esos datos (llamadas funciones miembro). Una clase se puede definir con struct, union o class. La sintaxis de una clase es: class nombre_clase { miembro1; miembro2; ... funcion_miembro1(); funcion_miembro2(); ... };

Una clase es sintácticamente igual a una estructura, con la única diferencia de que en el tipo class todos los miembros son por defecto privados mientras que en el tipo struct son por defecto públicos.

Encapsulado de Datos

El empaque conjunto de datos y métodos se llama encapsulado. El objeto esconde sus datos de los demás objetos y permite el acceso a los datos mediante sus propios métodos. Esto recibe el nombre de ocultamiento de información. El encapsulamiento evita la corrupción de los datos de un objeto. Si todos los programas pudieran tener acceso a los datos de cualquier forma que quisieran los usuarios, los datos se podrían corromper o utilizar de mala manera. El encapsulado protege los datos del uso arbitrario y no pretendido. El encapsulado oculta los detalles de su implantación interna a los usuarios de un objeto. Los usuarios se dan cuenta de las operaciones que puede solicitar del objeto, pero desconocen los detalles de cómo se lleva a cabo la operación. Todos los detalles específicos de los datos del objeto y la codificación de sus operaciones están fuera del alcance del usuario. Así, encapsulado es el resultado (o acto) de ocultar los detalles de implantación de un objeto respecto de su usuario. El encapsulado, al separar el comportamiento del objeto de su implantación, permite la modificación de ésta sin que se tengan que modificar las aplicaciones que lo utilizan.

1.3.- La programación orientada a objetos (POO), intenta simular el mundo real a través del significado de objetos que contiene características y funciones. Los lenguajes orientados a objetos se clasifican como lenguajes de quinta generación.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

6

Como su mismo nombre indica, la programación orientada a objetos se basa en la idea de un objeto, que es una combinación de variables locales y procedimientos llamados métodos que juntos conforman una entidad de programación.

El termino encapsulación se usa para describir la combinación de estructuras de datos y de métodos que son manipulados por el objeto. La llamada a un objeto es lo que se denomina pasar un "aviso" a un objeto.

En la programación orientada a objetos, encapsular significa, reunir y controlar el grupo resultante como un todo y no individualmente.

En la programación orientada a objetos la abstracción es un termino externo al objeto, que controla la forma en que es visto por los demás.

En la programación orientada a objetos la modularidad se considera de la siguiente manera: Un programa grande siempre será más complicado que la suma de varios programas pequeños, con lo que se considera ventajoso dividir un gran sistema en diversos módulos.

En la programación orientada a objetos tenemos la jerarquía, la cual consiste en la clasificación y organización de las abstracciones según su naturaleza. El más claro ejemplo de jerarquía es la herencia.

En la programación orientada a objetos se define la herencia como una jerarquía de extracciones, y la relación entre clases, donde se comparte la estructura y el comportamiento de una o más clase considerada como clases superiores o una superclase, con lo cual se resume que la herencia es una unidad independiente por si misma heredada de una abstracción o superclase. Un ejemplo cotidiano lo encontramos en las aplicaciones que existen actualmente en el mercado, donde un formulario cualquiera hereda las características de uan ventana del sistema operativo Windows (Maximizar, Minimizar, Cerrar).

Introducción

l término de Programación Orientada a Objetos indica más una forma de diseño y una metodología de desarrollo de software que un lenguaje de programación, ya que en realidad se puede aplicar el Diseño Orientado a Objetos (En inglés abreviado OOD, Object Oriented Design), a cualquier tipo de lenguaje de programación.

El desarrollo de la OOP empieza a destacar durante la década de lo 80 tomando en cuenta la programación estructurada, a la que engloba y dotando al programador de nuevos elementos para el análisis y desarrollo de software.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

7

El propósito de este trabajo es explicar el diseño orientado a objeto y no una explicación de su programación, puesto que no nos alcanzaría toda la currícula y semestre para hacerlo.

Básicamente la OOP permite a los programadores escribir software, de forma que esté organizado en la misma manera que el problema que trata de modelizar. Los lenguajes de programación convencionales son poco más que una lista de acciones a realizar sobre un conjunto de datos en una determinada secuencia. Si en algún punto del programa modificamos la estructura de los datos o la acción realizada sobre ellos, el programa cambia.

La OOP aporta un enfoque nuevo, convirtiendo la estructura de datos en el centro sobre el que pivotan las operaciones. De esta forma, cualquier modificación de la estructura de datos tiene efecto inmediato sobre las acciones a realizar sobre ella, siendo esta una de la diferencias radicales respecto a la programación estructurada.

Para quienes no están familiarizados con la programación estructurada diré que una de las bases de esta escuela de programación parte del diseño arriba – abajo. En esta forma de diseño se descomponen los requerimientos del programa paso a paso, hasta llegar a un nivel que permite expresarlos mediante procedimientos y funciones. La OOP estructura los datos en objetos que pueden almacenar, manipular y combinar información.

En resumen, la programación estructurada presta atención al conjunto de acciones que manipulan el flujo de datos (desde la situación inicial a la final), mientras que la programación orientada a objetos presta atención a la interrelación que existe entre los datos y las acciones a realizar con ellos.

Muchos habrán oído comentarios sobre la incidencia de la OOP sobre la programación convencional. Se ha llegado a decir que el cambio introducido por la OOP es similar al producido por la aparición del ensamblador sobre el código de máquina.

La OOP proporciona las siguientes ventajas sobre otros lenguajes de programación

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

8

Uniformidad. Ya que la representación de los objetos lleva implica tanto el análisis como el diseño y la codificación de los mismos.

Comprensión. Tanto los datos que componen los objetos, como los procedimientos que los manipulan, están agrupados en clases, que se corresponden con las estructuras de información que el programa trata.

Flexibilidad. Al tener relacionados los procedimientos que manipulan los datos con los datos a tratar, cualquier cambio que se realice sobre ellos quedará reflejado automáticamente en cualquier lugar donde estos datos aparezcan.

Estabilidad. Dado que permite un tratamiento diferenciado de aquellos objetos que permanecen constantes en el tiempo sobre aquellos que cambian con frecuencia permite aislar las partes del programa que permanecen inalterables en el tiempo.

Reusabilidad. La noción de objeto permite que programas que traten las mismas estructuras de información reutilicen las definiciones de objetos empleadas en otros programas e incluso los procedimientos que los manipulan. De esta forma, el desarrollo de un programa puede llegar a ser una simple combinación de objetos ya definidos donde estos están relacionados de una manera particular.

Uno de los puntos clave a remarcar en esta introducción es que la programación orientada a objetos no sustituye a ninguna metodología ni lenguaje de programación anterior. Todos los programas que se realizan según OOD se pueden realizar igualmente mediante programación estructurada. Su uso en la actualidad se justifica porque el desarrollo de todas las nuevas herramientas basadas en un interfase de usuario gráfico como Windows, OS/2, x-Windows, etc. Es mucho más sencillo

1.3.- La POO y la complejidad del Software

A grandes rasgos significa que el software se organiza como una colección de objetos discretos que contienen tanto estructura de datos como un comportamiento. se mencionan cuatro características precisas que requiere un enfoque Orientado a Objetos: Identidad Clasificación Polimorfismo Herencia

IDENTIDAD: con esto queremos dar a entender que los datos están cuantificados en entidades llamadas comúnmente objetos. CLASIFICACION: significa que los objetos con la misma estructura de datos (atributos) y comportamiento (operaciones) se unen para formar una clase. POLIFORMISMO: nos indica que una misma operación puede comportarse de modos distintos en distintas clases. HERENCIA: esto es cuando se comparte atributos y operaciones entre dos o mas clases tomando como base una relación jerárquica. En la Programación Orientada a Objetos mas conocida como POO se le denomina programa a una colección de una sola entidad básica, el objeto, el cual combina los datos con los procedimientos que actúan sobre ellos. Durante la ejecución, los objetos reciben y envían mensajes a otros objetos para ejecutar las acciones requeridas. Por ultimo y para finalizar con este proceso; la organización jerárquica de los objetos en clases permite que datos y métodos de una clase sean heredados por sus descendientes.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

9

La POO puede llevarse a cabo con un lenguaje Orientado a Objetos. Para esto lo mas apropiado es utilizar directamente un lenguaje OO, ya que estos soportan los mecanismos y características que ya antes hemos expuesto tales como objetos, clases, métodos, mensajes, herencias constituyen uno de los mecanismos más potentes de la POO. El lenguaje de programación que hemos mencionado beneficia al desarrollo de software, ya que ofrece una forma mas natural de lograr el desarrollo de modelos utilizando clases, con esta programación los programas tienen menos líneas de código, menos sentencias de bifurcación y módulos son mas comprensibles por que reflejan de una forma clara la relación existentes entre cada concepto a desarrollar y cada objeto que interviene en dicho desarrollo, y por consecuencia hasta cierto punto hace mas fácil la programación. El software cuenta con : Dominio del problema: donde se junta la información y se crea un análisis del software. Dificultad del proceso de desarrollo: tiene que haber coordinación entre todos los objetos, entre mas programadores mas dificultad, por lo que deben haber unos cuantos , y estos deben estar coordinados. Flexibilidad del software: este debe de ser exacto y especifico con la información del programa, debe de tener un rendimiento, una flexibilidad y por lo tanto una funcionalidad requerida. Comportamiento de sistemas discretos: el software se pone a prueba de errores y los efectos secundarios que puedan surgir deben ser corregidos o eliminados. CONCLUSION DEL EQUIPO Con este tema queda entendido que un sistema complejo es aquel que a partir de una forma simple ha evolucionado de forma que se relaciona con otros sistemas simples y estos actúan para realizar una función general como si fuera de una sola unidad, hay que recordar que un sistema esta dividido en diferentes unidades.

1.4.-Conceptos del Ciclo de vida del Software.

Todo proyecto de ingeniería tiene unos fines ligados a la obtención de un producto, proceso o servicio que es necesario generar a través de diversas actividades. Algunas de estas actividades pueden agruparse en fases porque globalmente contribuyen a obtener un producto intermedio, necesario para continuar hacia el producto final y facilitar la gestión del proyecto. Al conjunto de las fases empleadas se le denomina “ciclo de vida”.

Sin embargo, la forma de agrupar las actividades, los objetivos de cada fase, los tipos de productos intermedios que se generan, etc. pueden ser muy diferentes dependiendo del tipo de producto o proceso a generar y de las tecnologías empleadas.

La complejidad de las relaciones entre las distintas actividades crece exponencialmente con el tamaño, con lo que rápidamente se haría inabordable si no fuera por la vieja táctica de “divide y vencerás”. De esta forma la división de los proyectos en fases sucesivas es un primer paso para la reducción de su complejidad, tratándose de escoger las partes de manera que sus relaciones entre sí sean lo más simples posibles.

La definición de un ciclo de vida facilita el control sobre los tiempos en que es necesario aplicar recursos de todo tipo (personal, equipos, suministros, etc.) al proyecto. Si el proyecto incluye subcontratación de partes a otras organizaciones, el control del trabajo subcontratado se facilita en la medida en que esas partes encajen bien en la estructura de las fases. El control de calidad también se ve facilitado si la separación entre fases se hace corresponder con puntos en los que ésta deba verificarse (mediante comprobaciones sobre los productos parciales obtenidos).

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

10

De la misma forma, la práctica acumulada en el diseño de modelos de ciclo de vida para situaciones muy diversas permite que nos beneficiemos de la experiencia adquirida utilizando el enfoque que mejor de adapte a nuestros requerimientos.

ELEMENTOS DEL CICLO DE VIDA

Un ciclo de vida para un proyecto se compone de fases sucesivas compuestas por tareas planificables. Según el modelo de ciclo de vida, la sucesión de fases puede ampliarse con bucles de realimentación, de manera que lo que conceptualmente se considera una misma fase se pueda ejecutar más de una vez a lo largo de un proyecto, recibiendo en cada pasada de ejecución aportaciones de los resultados intermedios que se van produciendo (realimentación).

Para un adecuado control de la progresión de las fases de un proyecto se hace necesario especificar con suficiente precisión los resultados evaluables, o sea, productos intermedios que deben resultar de las tareas incluidas en cada fase. Normalmente estos productos marcan los hitos entre fases.

A continuación presentamos los distintos elementos que integran un ciclo de vida:

• Fases. Una fase es un conjunto de actividades relacionadas con un objetivo en el desarrollo del proyecto. Se construye agrupando tareas (actividades elementales) que pueden compartir un tramo determinado del tiempo de vida de un proyecto. La agrupación temporal de tareas impone requisitos temporales correspondientes a la asignación de recursos (humanos, financieros o materiales). Cuanto más grande y complejo sea un proyecto, mayor detalle se necesitará en la definición de las fases para que el contenido de cada una siga siendo manejable. De esta forma, cada fase de un proyecto puede considerarse un “micro-proyecto” en sí mismo, compuesto por un conjunto de micro-fases.

Otro motivo para descomponer una fase en subfases menores puede ser el interés de separar partes temporales del proyecto que se subcontraten a otras organizaciones, requiriendo distintos procesos de gestión.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

11

Cada fase viene definida por un conjunto de elementos observables externamente, como son las actividades con las que se relaciona, los datos de entrada (resultados de la fase anterior, documentos o productos requeridos para la fase, experiencias de proyectos anteriores), los datos de salida (resultados a utilizar por la fase posterior, experiencia acumulada, pruebas o resultados efectuados) y la estructura interna de la fase.

Esquema general de operación de una fase

• Entregables ("deliverables"). Son los productos intermedios que generan las fases. Pueden ser materiales (componentes, equipos ) o inmateriales (documentos, software). Los entregables permiten evaluar la marcha del proyecto mediante comprobaciones de su adecuación o no a los requisitos funcionales y de condiciones de realización previamente establecidos. Cada una de estas evaluaciones puede servir, además, para la toma de decisiones a lo largo del desarrollo del proyecto.

TIPOS DE MODELO DE CICLO DE VIDA

Las principales diferencias entre distintos modelos de ciclo de vida están en:

o El alcance del ciclo dependiendo de hasta dónde llegue el proyecto correspondiente. Un proyecto puede comprender un simple estudio de viabilidad del desarrollo de un producto, o su desarrollo completo o, llevando la cosa al extremo, toda la historia del producto con su desarrollo, fabricación, y modificaciones posteriores hasta su retirada del mercado.

o Las características (contenidos) de las fases en que dividen el ciclo. Esto puede depender del propio tema al que se refiere el proyecto (no son lo mismo las tareas que deben realizarse para proyectar un avión que un puente), o de la organización (interés de reflejar en la división en fases aspectos de la división interna o externa del trabajo).

o La estructura de la sucesión de las fases que puede ser lineal, con prototipado, o en espiral. Veámoslo con más detalle:

Ciclo de vida lineal

Es el más utilizado, siempre que es posible, precisamente por ser el más sencillo. Consiste en descomponer la actividad global del proyecto en fases que se suceden de manera lineal, es decir, cada una se realiza una sola vez, cada una se realiza tras la anterior y antes que la siguiente . Con un ciclo lineal es fácil dividir las tareas entre equipos sucesivos, y prever los tiempos (sumando los de cada fase).

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

12

Requiere que la actividad del proyecto pueda descomponerse de manera que una fase no necesite resultados de las siguientes (realimentación), aunque pueden admitirse ciertos supuestos de realimentación correctiva. Desde el punto de vista de la gestión (para decisiones de planificación), requiere también que se sepa bien de antemano lo que va a ocurrir en cada fase antes de empezarla.

Ejemplo de ciclo lineal para un proyecto de construcción

Ciclo de vida con prototipado

A menudo ocurre en desarrollos de productos con innovaciones importantes, o cuando se prevé la utilización de tecnologías nuevas o poco probadas, que las incertidumbres sobre los resultados realmente alcanzables, o las ignorancias sobre el comportamiento de las tecnologías, impiden iniciar un proyecto lineal con especificaciones cerradas.

Si no se conoce exactamente cómo desarrollar un determinado producto o cuáles son las especificaciones de forma precisa, suele recurrirse a definir especificaciones iniciales para hacer un prototipo, o sea, un producto parcial (no hace falta que contenga funciones que se consideren triviales o suficientemente probadas) y provisional (no se va a fabricar realmente para clientes, por lo que tiene menos restricciones de coste y/o prestaciones). Este tipo de procedimiento es muy utilizado en desarrollo avanzado.

La experiencia del desarrollo del prototipo y su evaluación deben permitir la definición de las especificaciones más completas y seguras para el producto definitivo. A diferencia del modelo lineal, puede decirse que el ciclo de vida con prototipado repite las fases de definición, diseño y construcción dos veces: para el prototipo y para el producto real.

Ciclo de vida en espiral

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

13

El ciclo de vida en espiral puede considerarse como una generalización del anterior para los casos en que no basta con una sola evaluación de un prototipo para asegurar la desaparición de incertidumbres y/o ignorancias. El propio producto a lo largo de su desarrollo puede así considerarse como una sucesión de prototipos que progresan hasta llegar a alcanzar el estado deseado. En cada ciclo (espirales) las especificaciones del producto se van resolviendo paulatinamente.

A menudo la fuente de incertidumbres es el propio cliente, que aunque sepa en términos generales lo que quiere, no es capaz de definirlo en todos sus aspectos sin ver como unos influyen en otros. En estos casos la evaluación de los resultados por el cliente no puede esperar a la entrega final y puede ser necesaria repetidas veces.

El esquema del ciclo de vida para estos casos puede representarse por un bucle en espiral, donde los cuadrantes son, habitualmente, fases de especificación, diseño, realización y evaluación (o conceptos y términos análogos).

En cada vuelta el producto gana en “madurez” (aproximación al final deseado) hasta que en una vuelta la evaluación lo apruebe y el bucle pueda abandonarse.

OBJETIVOS DE CADA FASE

Dentro de cada fase general de un modelo de ciclo de vida, se pueden establecer una serie de objetivos y tareas que lo caracterizan.

Fase de definición (¿qué hacer?) o Estudio de viabilidad. o Conocer los requisitos que debe satisfacer el sistema (funciones y

limitaciones de contexto). o Asegurar que los requisitos son alcanzables. o Formalizar el acuerdo con los usuarios. o Realizar una planificación detallada.

Fase de diseño (¿cómo hacerlo? Soluciones en coste, tiempo y calidad) o Identificar soluciones tecnológicas para cada una de las funciones

del sistema. o Asignar recursos materiales para cada una de las funciones. o Proponer (identificar y seleccionar) subcontratas. o Establecer métodos de validación del diseño.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

14

o Ajustar las especificaciones del producto.

Fase de construcción o Generar el producto o servicio pretendido con el proyecto. o Integrar los elementos subcontratados o adquiridos externamente. o Validar que el producto obtenido satisface los requisitos de diseño

previamente definidos y realizar, si es necesario, los ajustes necesarios en dicho diseño para corregir posibles lagunas, errores o inconsistencias.

Fase de mantenimiento y operación o Operación: asegurar que el uso del proyecto es el pretendido. o Mantenimiento (nos referimos a un mantenimiento no habitual, es

decir, aquel que no se limita a reparar averías o desgastes habituales -este es el caso del mantenimiento en productos software, ya que en un programa no cabe hablar de averías o de desgaste):

LOS PROYECTOS DE I+D

En el caso de la investigación básica el resultado esperado son conocimientos científicos. No existe ninguna fase de construcción y sí fases que recojan las tareas de experimentación.

En la investigación aplicada el resultado esperado suele ser alguna tecnología aplicable para procesos o para productos. Dependiendo del grado de cercanía a la aplicación que llegue a alcanzarse el modelo puede ser básicamente como el anterior o incluir una fase de aplicación piloto.

En el desarrollo de productos o procesos nuevos o significativamente modificados sí aparece ya una fase de construcción, aunque normalmente se tratará de la realización de un prototipo. Normalmente el cliente no será el usuario final, sino los departamentos de ingeniería de producción de la propia empresa o de otra que contrata el desarrollo.

La I+D es costosa por depender de personal muy cualificado, por realizarse de modo generalmente artesanal y por requerir bucles de realimentación que multiplican, para hacer frente a incidencias, la duración del proyecto.

CICLO DE VIDA EN INTERNET

Con Internet de por medio, todo se transforma en algo más rápido. Internet ha conseguido en 5 o 6 años lo que televisión o teléfono han tardado décadas.

Tema: El ciclo de la vida en Internet Autor: Pilar Navas El conocido ciclo de vida, basado en considerar que cualquier producto tiene una duración limitada y que pasa por una serie de fases (nacimiento, crecimiento y maduración) se ha acortado notablemente.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

15

1.4.1.- Especificaciones de requerimientos.

Impacto del proceso: Especificación de Requerimientos de Software :define de forma precisa el producto de software que se va a construir. Las decisiones hechas están basados en información de los documentos de la propuesta del proyecto y requerimientos del usuario. El conjunto de requerimientos deben ser satisfechos en el diseño del sistema.

Requerimiento: Característica o Restricción de un Sistema. Ingeniería de Requerimientos: Proceso sistemático utilizado para derivar una definición del sistema de software a ser desarrollado.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

16

Especificación Análisis

Definición Solicitud

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

17

Errores de una mala Especificación de Requerimientos

• Por su origen: Funcionales: Comportamiento de los distintos

módulos. No Funcionales: Restricciones del sistema (tiempo

de respuesta, almacenamiento, casos de uso, logística).

• Por su aparición cronológica: De análisis (descubrimiento) y diseño. De mantenimiento.

• Encontrar soluciones sin haber entendido los problemas.

• Problemas de gran escala: Los sistemas multi-versión y multi-programador

deben tratarse diferente que sistemas pequeños.

• Teléfono descompuesto.

• Requerimientos cambiantes.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

18

• Frecuentemente el cliente no sabe que quiere; se le

inventan necesidades falsas. • Tareas mal identificadas.

• Establecimiento de requerimientos como mero trámite.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

19

1.4.2.- Análisis Orientada a Objetos.

1.4.3.- Diseño Orientado a Objetos Para el desarrollo de software orientado a objetos no basta usar un lenguaje orientado a objetos. También se necesitará realizar un análisis y diseño orientado a objetos.

El modelamiento visual es la clave para realizar el análisis OO. Desde los inicios del desarrollo de software OO han existido diferentes metodologías para hacer esto del modelamiento, pero sin lugar a duda, el Lenguaje de Modelamiento Unificado (UML) puso fin a la guerra de metodologías.

Según los mismos diseñadores del lenguaje UML, éste tiene como fin modelar cualquier tipo de sistemas (no solamente de software) usando los conceptos de la orientación a objetos. Y además, este lenguaje debe ser entendible para los humanos y máquinas.

Actualmente en la industria del desarrollo de software tenemos al UML como un estándar para el modelamiento de sistemas OO. Fue la empresa Racional que creó estas definiciones y especificaciones del estándar UML, y lo abrió al mercado. La misma empresa creó uno de los programas más conocidos hoy en día para este fin; el Racional Rose, pero también existen otros programas como el Poseidon que trae licencias del tipo community edition que permiten su uso libremente.

El UML consta de todos los elementos y diagramas que permiten modelar los sistemas en base al paradigma orientado a objetos.

• ¿Qué hacer para obtener una ER completa?

• ¿Cómo descomponer el problema en fragmentos manejables?

• ¿Cómo organizar la información para que sea entendida?

• ¿Cómo comunicarse con todas las partes involucradas?

• ¿Cómo se resolverán las necesidades en conflicto?

• ¿Cuándo detener el análisis?

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

20

Los modelos orientados a objetos cuando se construyen en forma correcta, son fáciles de comunicar, cambiar, expandir, validar y

verificar. Este modelamiento en UML es flexible al cambio y permite crear componentes plenamente reutilizables.

1.4.4.- POO, conceptos y Características

Programación orientada a objetos

La Programación Orientada a Objetos (POO u OOP según siglas en inglés) es un paradigma de programación que define los programas en términos de "clases de objetos", objetos que son entidades que combinan estado (es decir, datos), comportamiento (esto es, procedimientos o métodos ) e identidad (propiedad del objeto que lo diferencia del resto). La programación orientada a objetos expresa un programa como un conjunto de estos objetos, que colaboran entre ellos para realizar tareas. Esto permite hacer los programas y módulos más fáciles de escribir, mantener y reutilizar.

De esta forma, un objeto contiene toda la información, (los denominados atributos) que permite definirlo e identificarlo frente a otros objetos pertenecientes a otras clases (e incluso entre objetos de una misma clase, al poder tener valores bien diferenciados en sus atributos). A su vez, dispone de mecanismos de interacción (los llamados métodos) que favorecen la comunicación entre objetos (de una misma clase o de distintas), y en consecuencia, el cambio de estado en los propios objetos. Esta característica lleva a tratarlos como unidades indivisibles, en las que no se separan (ni deben separarse) información (datos) y procesamiento (métodos).

Dada esta propiedad de conjunto de una clase de objetos, que al contar con una serie de atributos definitorios, requiere de unos métodos para poder tratarlos (lo que hace que ambos conceptos están íntimamente entrelazados), el programador debe pensar indistintamente en ambos términos, ya que no debe nunca separar o dar mayor importancia a los atributos en favor de los métodos, ni viceversa. Hacerlo puede llevar al programador a seguir el hábito erróneo de crear clases contenedoras de información por un lado y clases con métodos que manejen esa información por otro (llegando a una programación estructurada camuflada en un lenguaje de programación orientado a objetos).

Esto difiere de los lenguajes imperativos tradicionales, en los que los datos y los procedimientos están separados y sin relación, ya que lo único que se busca es el procesamiento de unos datos de entrada para obtener otros de salida. La programación estructurada anima al programador a pensar sobre todo en términos de procedimientos o funciones, y en segundo lugar en las estructuras de datos que esos procedimientos manejan. Los programadores de lenguajes imperativos escriben funciones y después les pasan datos. Los programadores que emplean lenguajes orientados a objetos definen objetos con datos y métodos y después envían mensajes a los objetos diciendo qué realicen esos métodos en sí mismos.

Algunas personas también distinguen la POO sin clases, la cual es llamada a veces programación basada en objetos.

Origen

Los conceptos de la programación orientada a objetos tienen origen en Simula 67, un lenguaje diseñado para hacer simulaciones, creado por Ole-Johan Dahl y Kristen Nygaard del Centro de Cómputo Noruego en Oslo. Según se informa, la historia es que trabajaban en simulaciones de naves, y fueron confundidos por la explosión combinatoria de cómo las diversas cualidades de diversas naves podían afectar unas a las otras. La idea ocurrió para agrupar los diversos tipos

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

21

de naves en diversas clases de objetos, siendo responsable cada clase de objetos de definir sus propios datos y comportamiento. Fueron refinados más tarde en Smalltalk, que fue desarrollado en Simula en Xerox PARC (y cuya primera versión fue escrita sobre Basic) pero diseñado para ser un sistema completamente dinámico en el cual los objetos se podrían crear y modificar "en marcha" en lugar de tener un sistema basado en programas estáticos.

La programación orientada a objetos tomó posición como la metodología de programación dominante a mediados de los años ochenta, en gran parte debido a la influencia de C++ , una extensión del lenguaje de programación C. Su dominación fue consolidada gracias al auge de las Interfaces gráficas de usuario, para los cuales la programación orientada a objetos está particularmente bien adaptada. En este caso, se habla también de programación orientada a eventos.

Las características de orientación a objetos fueron agregadas a muchos lenguajes existentes durante ese tiempo, incluyendo Ada, BASIC, Lisp, Pascal, y otros. La adición de estas características a los lenguajes que no fueron diseñados inicialmente para ellas condujo a menudo a problemas de compatibilidad y a la capacidad de mantenimiento del código. Los lenguajes orientados a objetos "puros", por otra parte, carecían de las características de las cuales muchos programadores habían venido a depender. Para saltar este obstáculo, se hicieron muchas tentativas para crear nuevos lenguajes basados en métodos orientados a objetos, pero permitiendo algunas características imperativas de maneras "seguras". El Eiffel de Bertrand Meyer fue un temprano y moderadamente acertado lenguaje con esos objetivos pero ahora ha sido esencialmente reemplazado por Java, en gran parte debido a la aparición de Internet, y a la implementación de la máquina virtual de Java en la mayoría de navegadores.

Diferencias con la programación imperativa

Aunque la programación imperativa (a veces llamada procedural o procedimental) condujo a mejoras de la técnica de programación secuencial, tales como la programación estructurada y "refinamientos sucesivos", los métodos modernos de diseño de software orientado a objetos incluyen mejoras entre las que están el uso de los patrones de diseño, diseño por contrato, y lenguajes de modelado (ej: UML).

Las principales diferencias entre la programación imperativa y la orientada a objetos son:

• La programación orientada a objetos es más moderna, es una evolución de la programación imperativa que plasma en el diseño de una familia de lenguajes conceptos que existían previamente con algunos nuevos.

• La programación orientada a objetos se basa en lenguajes que soportan sintáctica y semánticamente la unión entre los tipos abstractos de datos y sus operaciones (a esta unión se la suele llamar clase).

• La programación orientada a objetos incorpora en su entorno de ejecución mecanismos tales como el polimorfismo y el envío de mensajes entre objetos.

Erróneamente se le adjudica a la programación imperativa clásica ciertos problemas como si fueran inherentes a la misma. Esos problemas fueron haciéndose cada vez más graves y antes de la programación orientada a objetos diversos autores (de los que podemos destacar a Jourdon) encontraron soluciones basadas en aplicar estrictas metodologías de trabajo. De esa época son los conceptos de cohesión y acoplamiento. De esos problemas se destacan los siguientes:

• Modelo mental anómalo. Nuestra imagen del mundo se apoya en los seres, a los que asignamos nombres sustantivos, mientras la programación clásica se basa en el comportamiento, representado usualmente por verbos.

• Es difícil modificar y extender los programas, pues suele haber datos compartidos por varios subprogramas, que introducen interacciones ocultas entre ellos.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

22

• Es difícil mantener los programas. Casi todos los sistemas informáticos grandes tienen errores ocultos, que no surgen a la luz hasta después de muchas horas de funcionamiento.

• Es difícil reutilizar los programas. Es prácticamente imposible aprovechar en una aplicación nueva las subrutinas que se diseñaron para otra.

• Es compleja la coordinación y organización entre programadores para la creación de aplicaciones de media y gran envergadura.

En la programación orientada a objetos pura no deben utilizarse llamadas de subrutinas, únicamente mensajes.

Por ello, a veces recibe el nombre de programación sin CALL, igual que la programación estructurada se llama también programación sin GOTO.

Sin embargo, no todos los lenguajes orientados a objetos prohíben la instrucción CALL (o su equivalente), permitiendo realizar programación híbrida, imperativa y orientada a objetos a la vez.

La Programación Orientada a Objetos (POO) como solución

La programación orientada a objetos es una nueva forma de programar que trata de encontrar solución a estos problemas. Introduce nuevos conceptos, que superan y amplían conceptos antiguos ya conocidos. Entre ellos destacan los siguientes:

• Objeto: entidad provista de un conjunto de propiedades o atributos (datos) y de comportamiento o funcionalidad ("métodos"). Corresponden a los objetos reales del mundo que nos rodea, o a objetos internos del sistema (del programa).

• Clase: definiciones de las propiedades y comportamiento de un tipo de objeto concreto. La instanciación es la lectura de estas definiciones y la creación de un objeto a partir de ellas.

• Método : algoritmo asociado a un objeto (o a una clase de objetos), cuya ejecución se desencadena tras la recepción de un "mensaje". Desde el punto de vista del comportamiento, es lo que el objeto puede hacer. Un método puede producir un cambio en las propiedades del objeto, y/o la generación de un "evento" con un nuevo mensaje para otro objeto del sis tema.

• Evento: un suceso en el sistema (tal como una interacción del usuario con la máquina, o un mensaje enviado por un objeto). El sistema maneja el evento enviando el mensaje adecuado al objeto pertinente.

• Mensaje : una comunicación dirigida a un objeto, que le ordena que ejecute uno de sus métodos con ciertos parámetros asociados al evento que lo generó.

• Propiedad o atributo: contenedor de un tipo de datos asociados a un objeto (o a una clase de objetos), que hace los datos visibles desde fuera del objeto, y cuyo valor puede ser alterado por la ejecución de algún método.

• Estado interno : es una propiedad invisible de los objetos, que puede ser únicamente accedida y alterada por un método del objeto, y que se utiliza para indicar distintas situaciones posibles para el objeto (o clase de objetos).

En comparación con un lenguaje imperativo, una "variable" no es más que un contenedor interno del atributo del objeto o de un estado interno, así como la "función" es un procedimiento interno del método del objeto.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

23

Características de la POO

Hay un cierto desacuerdo sobre exactamente qué características de un método de programación o lenguaje le definen como "orientado a objetos", pero hay un consenso general en que las características siguientes son las más importantes (para más información, seguir los enlaces respectivos):

• Abstracción: cada objeto en el sistema sirve como modelo de un "agente" abstracto que puede realizar trabajo, informar y cambiar su estado, y "comunicarse" con otros objetos en el sistema sin revelar cómo se implementan estas características. Los procesos, las funciones o los métodos pueden también ser abstraídos y cuando lo están, una variedad de técnicas son requeridas para ampliar una abstracción.

• Encapsulamiento: también llamado "ocultación de la información". Cada objeto está aislado del exterior, es un módulo natural, y cada tipo de objeto expone una interfaz a otros objetos que especifica cómo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas, solamente los propios métodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no pueden cambiar el estado interno de un objeto de maneras inesperadas, eliminando efectos secundarios e interacciones inesperadas. Algunos lenguajes relajan esto, permitiendo un acceso directo a los datos internos del objeto de una manera controlada y limitando el grado de abstracción. La aplicación entera se reduce a un agregado o rompecabezas de objetos.

• Polimorfismo: comportamientos diferentes, asociados a objetos distintos, pueden compartir el mismo nombre, al llamarlos por ese nombre se utilizará el comportamiento correspondiente al objeto que se esté usando. O dicho de otro modo, las referencias y las colecciones de objetos pueden contener objetos de diferentes tipos, y la invocación de un comportamiento en una referencia producirá el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto ocurre en "tiempo de ejecución", esta última característica se llama asignación tardía o asignación dinámica. Algunos lenguajes proporcionan medios más estáticos (en "tiempo de compilación") de polimorfismo, tales como las plantillas y la sobrecarga de operadores de C++.

• Herencia: las clases no están aisladas, sino que se relacionan entre sí, formando una jerarquía de clasificación. Los objetos heredan las propiedades y el comportamiento de todas las clases a las que pertenecen. La herencia organiza y facilita el polimorfismo y el encapsulamiento permitiendo a los objetos ser definidos y creados como tipos especializados de objetos preexistentes. Estos pueden compartir (y extender) su comportamiento sin tener que reimplementar su comportamiento. Esto suele hacerse habitualmente agrupando los objetos en clases y estas en árboles o enrejados que reflejan un comportamiento común. Cuando un objeto pertenece a más de una clase se llama herencia múltiple; esta característica no está soportada por algunos lenguajes (como Java).

1.5.- Elementos primordiales en el modelo de Objetos. La programación Orientada a Objetos trata de cumplir las necesidades de los usuarios finales,

estás tareas se realizan mediante la modelización del mundo real, el sopote fundamental es el

modelo objeto.

Los elementos más importantes de este modelo son:

*Abstracción

*Encapsulamiento

*Modularidad

*Jerarquía y Herencia

*Polimorfismo

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

24

1.5.1.- Abstracción.

Abstracción de Datos:

Introducción

Los tipos definidos por el usuario o tipos abstractos de datos (TAD) empaquetan elementos dato con las operaciones que se realizan sobre esos datos. C++ soporta los TAD con el tipo clase que puede ser implementado con estructuras, uniones y clases.

Abstracción de datos

Una característica importante de cualquier lenguaje de programación es la capacidad de crear tipos de datos definidos por el usuario. Aunque se pueden crear en C sus propios tipos, utilizando las palabras reservadas typedef y struct, los tipos resultantes no se pueden integrar fácilmente en el resto del programa. Además, en C, sólo se pueden definir los tipos en términos de datos; es decir, las funciones utilizadas para manipular esos tipos no son parte de la definición del tipo.

Una definición de un tipo que incluye datos y funciones y el modo para encapsular los detalles, se conoce como tipo abstracto de dato. En C++ se implementa mediante el uso de tipos de datos definidos por el usuario, llamados clases. clase = datos + funciones

Una diferencia importante entre C y C++, es que en C++ se pueden declarar funciones dentro de una estructura (no se requiere declarar punteros a funciones). Las estructuras pueden tener también especificadas regiones de acceso (medios en que se puede controlar el acceso a los datos).

La abstracción de datos en C++ se obtiene con los tipos de datos estructura (struct) y clase (class).

Concepto de clase

Una clase es un tipo de dato que contiene uno o más elementos dato llamados miembros dato, y cero, una o más funciones que manipulan esos datos (llamadas funciones miembro). Una clase se puede definir con struct, union o class. La sintaxis de una clase es: class nombre_clase { miembro1; miembro2; ... funcion_miembro1(); funcion_miembro2(); ... };

Una clase es sintácticamente igual a una estructura, con la única diferencia de que en el tipo class todos los miembros son por defecto privados mientras que en el tipo struct son por defecto públicos.

1.5.2.- Encapsulamiento. El empaque conjunto de datos y métodos se llama encapsulado. El objeto esconde sus datos de los demás objetos y permite el acceso a los datos mediante sus propios métodos. Esto recibe el nombre de ocultamiento de información. El encapsulamiento evita la corrupción de los datos de un objeto. Si todos los programas pudieran tener acceso a los datos de cualquier

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

25

forma que quisieran los usuarios, los datos se podrían corromper o utilizar de mala manera. El encapsulado protege los datos del uso arbitrario y no pretendido. El encapsulado oculta los detalles de su implantación interna a los usuarios de un objeto. Los usuarios se dan cuenta de las operaciones que puede solicitar del objeto, pero desconocen los detalles de cómo se lleva a cabo la operación. Todos los detalles específicos de los datos del objeto y la codificación de sus operaciones están fuera del alcance del usuario. Así, encapsulado es el resultado (o acto) de ocultar los detalles de implantación de un objeto respecto de su usuario. El encapsulado, al separar el comportamiento del objeto de su implantación, permite la modificación de ésta sin que se tengan que modificar las aplicaciones que lo utilizan.

1.3.- La programación orientada a objetos (POO), intenta simular el mundo real a través del significado de objetos que contiene características y funciones. Los lenguajes orientados a objetos se clasifican como lenguajes de quinta generación.

Como su mismo nombre indica, la programación orientada a objetos se basa en la idea de un objeto, que es una combinación de variables locales y procedimientos llamados métodos que juntos conforman una entidad de programación.

El termino encapsulación se usa para describir la combinación de estructuras de datos y de métodos que son manipulados por el objeto. La llamada a un objeto es lo que se denomina pasar un "aviso" a un objeto.

En la programación orientada a objetos, encapsular significa, reunir y controlar el grupo resultante como un todo y no individualmente.

En la programación orientada a objetos la abstracción es un termino externo al objeto, que controla la forma en que es visto por los demás.

1.5.3.- Modularidad

En la programación orientada a objetos la modularidad se considera de la siguiente manera: Un programa grande siempre será más complicado que la suma de varios programas pequeños, con lo que se considera ventajoso dividir un gran sistema en diversos módulos.

Ejemplos: Void altas() { Acción Acción } Void bajas() { Acción Acción } Void modificaciones() { Acción Acción

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

26

} Void mantenimiento() { Acción Acción } Void imprimir() { Acción Acción }

1.5.4.- Jerarquía y Herencia.

Jerarquía

La Jerarquía es una propiedad que permite la ordenación de las abstracciones. Las dos jerarquías más importantes de un sistema complejo son: estructura de clases (jerarquía “es-un” (is-a): generalización/especialización) y estructura de objetos (jerarquía “parte-de” (part-of): agregación).

Las jerarquías de generalización/especialización se conocen como herencia. Básicamente, la herencia define una relación entre clases, en donde una clase comparte la estructura o comportamiento definido en una o más clases (herencia simple y herencia múltiple, respectivamente).

La agregación es el concepto que permite el agrupamiento físico de estructuras relacionadas lógicamente. Así, un camión se compone de ruedas, motor, sistema de transmisión y chasis; en consecuencia, camión es una agregación, y ruedas, motor, transmisión y chasis son agregados de camión

Herencia

Un tipo de objeto de alto nivel puede especializarse en tipos de objeto de bajo nivel. Un tipo de objeto puede tener subtipos. Por ejemplo, el tipo de objeto persona puede tener subtipos estudiante y empleado. A su vez, el tipo de objeto estudiante puede tener como subtipo estudiante de pregrado y estudiante de postgrado, mientras que empleado puede tener como subtipo a académico y administrativo. Existe de este modo una jerarquía de tipos, subtipos, subsubtipos, etc. Una clase implanta el tipo de objeto. Una subclase hereda propiedades de su clase padre; una sub-subclase hereda propiedades de las subclases; etc. Una subclase puede heredar la estructura de datos y los métodos, o algunos de los métodos, de su superclase. También tiene sus métodos e incluso tipos de datos propios. Ejemplo de Herencia:

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

27

DISEÑAR UN SISTEMA ORIENTADO A OBJETOS CON HERENCIA PARA EL HOSPITAL

DEL ISSSTE TOMANDO EN CONSIDERACION TODOS LOS DATOS NECESARIOS DEL DERECHO-HABIENTE TOMANDO EN COSIDERACION LAS AREAS QUE OFRECE ESTE INSTITUTO DE SERVICIO MEDICO.

MI CLASE BASE ES:

HOSPITAL

MIS CLASES DERIVADAS

CONSUL_GENERAL, ESPECIALES Y HOSPITALIZACION

Consulta General Especialidades Hospitalización

Nombre Direccion Sexo trabajador edad dependencia edociv

Nombre Direccion Sexo trabajador edad dependencia edociv1 dep-tra especialidad

Nombre Direccion Sexo trabajador edad dependencia edociv2 area tratamiento

Leer()

Imprimir() Leer()

Imprimir() Leer()

Imprimir()

ARBOL DE HERENCIA

HOSPITAL

nom,dir,sexo,edad,dep LEER(),VISUALIZAR()

CONSULTA GENERAL ESPECIALIDADES HOSPITALIZACION edociv edociv1, dep_tra,especialidad edociv2,area,tratamiento, LEER() LEER() LEER() VISUALIZAR() VISUALIZAR() VISUALIZAR()

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

28

#include<iostream.h> #include<conio.h> #include<stdio.h> class hospital { protected: char nom[100][45],dir[100][45],sexo[100][45],trab[100][3]; int edad[100],i; char dep[100][3]; public: void leer(); void visualizar(); }; class consul_general:public hospital { protected: char edociv[100][10]; public: void leer(); void visualizar(); }; class especiales:public hospital { protected: char edociv1[100][10],dep_tra[100][45],especialidad[100][45]; public: void leer(); void visualizar(); }; class hospitalizacion:public hospital { protected: char area[100][30],tratamiento[100][45],edociv2[100][15]; public: void leer(); void visualizar(); }; void hospital::leer() {clrscr(); for (i=1;i<=10;i++) { cout<<"Nombre = "; gets(nom[i]); cout<<"Direccion = "; gets(dir[i]); cout<<"Edad = "; cin>>edad[i]; cout<<"Sexo = "; gets(sexo[i]); cout<<"Trabajador = "; gets(trab[i]); cout<<"Dependiente = "; gets(dep[i]); clrscr(); } } void hospital::visualizar() {clrscr(); for (i=1;i<=10;i++) { cout<<nom[i]; cout<<" "<<dir[i]; cout<<" "<<edad[i]; cout<<" "<<sexo[i]; cout<<" "<<trab[i];

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

29

cout<<" "<<dep[i]<<"\n"; getch(); } } void consul_general::leer() {clrscr(); for(i=1;i<=10;i++) { cout<<"Estado Civil = "; gets(edociv[i]); } } void consul_general::visualizar() {clrscr(); for(i=1;i<=10;i++) { cout<<edociv[i]<<"\n"; getch(); } } void especiales::leer() {clrscr(); for(i=1;i<=10;i++) { cout<<"Dependencia = "; gets(dep_tra[i]); cout<<"Estado Civil = "; gets(edociv1[i]); cout<<"Especialidad = "; gets(especialidad[i]); } } void especiales::visualizar() {clrscr(); for(i=1;i<=10;i++) { cout<<dep_tra[i]; cout<<" "<<edociv1[i]; cout<<" "<<especialidad[i]<<"\n"; getch(); } } void hospitalizacion::leer() {clrscr(); for(i=1;i<=10;i++) { cout<<"Area = "; gets(area[i]); cout<<"Estado Civil = "; gets(edociv2[i]); cout<<"Tratamiento = "; gets(tratamiento[i]); } } void hospitalizacion::visualizar() {clrscr(); for(i=1;i<=10;i++) { cout<<area[i]; cout<<" "<<edociv2[i]; cout<<" "<<tratamiento[i]<<"\n"; getch(); } }

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

30

//*PROGRAMA PRINCIPAL*// void main() {int op; clrscr(); do{clrscr(); cout<<"Opcion ="; cin>>op; switch(op) { case 1:{ hospital paciente; paciente.leer(); paciente.visualizar(); break; } case 2:{ consul_general paciente; paciente.leer(); paciente.visualizar(); break; } case 3:{ especiales paciente; paciente.leer(); paciente.visualizar(); break; } case 4:{ hospitalizacion paciente; paciente.leer(); paciente.visualizar(); break; } } } while(op<5); }

1.5.5.- Polimorfismo.

El polimorfismo es una nueva característica aportada por la OOP. Esta propiedad indica la posibilidad de definir varias operaciones con el mismo nombre, diferenciándolas únicamente en los parámetros de entrada. Dependiendo del objeto que se introduzca como parámetro de entrada, se elegirá automáticamente cual de las operaciones se va a realizar.

Ya está habituado al operador <<suma>> que está presente en todos los lenguajes de programación. Sin embargo, los operadores <<suma de fracciones>> y <<suma de números complejos>> no existen en casi ningún lenguaje de programación.

Los lenguajes OOP permiten definir un operador <<suma>> tal que reconozca que tipo de objeto se le está aplicando, a través de operaciones de objetos. Previamente deberá definir la fracción y el número complejo como una clase y la operación suma como una operación de una clase.

Definiendo adecuadamente las operaciones suma de fracciones y suma de números imaginarios, el operador suma devolverá, en el caso que los operandos sean fracciones, una fracción y , en el caso de los números imaginarios, otros número imaginario.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

31

Es posible extender el concepto e incluso definir operaciones como suma de bases de datos

El operador suma de base de datos. Aunque a primera vista la expresión C= A+B, siendo A y B bases de datos, nos pudiera parecer una extraordinaria simplificación, nos conduce a la pregunta: ¿Qué es la suma de una base d datos?

Consideremos varias posibilidades:

Introducción de registros: Lo que exige que A y B tengan la misma estructura.

Unión de campos: Aquellos campos que aparezcan en B pero no en A serán añadidos a C

¿Alguna de estas dos opciones es verdaderamente una suma? Es decir ¿Cumple las propiedades conmutativa, asociativa, de elemento neutro, etc.? ¿Qué ocurre si sumo dos bases de datos con estructuras distintas?

Como puede observar, la definición de un operador sobre un tipo complejo de datos, intentando utilizar identificadores de operadores de datos simples, puede tener resultados impredecibles.

Una de las ventajas más importantes, sin entrar en la redefinición de operadores es permitir la realización de las clases que definen un programa de forma totalmente independiente al programa donde se utilizan. Gracias a la encapsulación y el polimorfismo, aunque se utilicen los mismos nombre con las operaciones en dos clases distintas, el programa reconoce a que clase se aplica durante la ejecución.

Como se podrá observar el polimorfismo y la encapsulación de datos están íntimamente ligados y nos permiten un mayor grado de mantenibilidad y reusabilidad que los lenguajes tradicionales Esta ese precisamente una de las causas de la revolución que ha supuesto la introducción de los lenguajes orientados a objetos dentro de la programación.

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

32

Ejemplo de Polimorfismo

#include<iostream.h> #include<conio.h> #include<stdio.h> #define pi 3.1416 class geometria { public: float area(float b,float h){return (b*h)/2;} float area(float r) {return(pi*(r*r));} float area(float b1,float b2, float h) {return ((b1+b2)/2)*h;} }; void main() { clrscr(); geometria dibujo; cout<<"\n"<<dibujo.area(3.2,6); cout<< "\n"<<dibujo.area(6.8); cout<< "\n"<<dibujo.area(4.8,6.2,6); getch(); }

Dormir() { en un árbol}

Dormir() { sobrela espalda}

Dormir() { sobre el vientre }

Dormir() { }

Animal dormir()

León dormir()

Oso dormir()

Tigre dormir()

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

33

1.6.- Historia de los paradigmas en el Desarrollo del Software

El desarrollo de los lenguajes de programación, sorprendentemente, sigue de cercas el

desarrollo de los procesos físicos y electrónicos usados en las computadoras de hoy en dia.

Acreditan a Charles Babbage a menudo con diseñar las primeras máquinas parecidas a

computadoras, que tenían varios programas escritos para ellas (en el equivalente del lenguaje

ensamblador) por Ada Lovelace.

Alan Turing utilizó la construcción teórica de una máquina de Turing que se comportaba en

principio de todas las maneras relevantes como las computadoras modernas, según el

programa de nivel bajo con el que se encontraba.

En 1940 las primeras computadoras reconocidas como modernas, eléctricamente accionadas

fueron creadas, requiriendo a los programadores funcionar las máquinas a mano. Algunas

necesidades militares del calculo eran una fuerza impulsora en el desarrollo temprano de las

computadoras, tal como cifrado (encryption), desciframiento (decryption), calculo de la

trayectoria y desarrollo de bombas atómicas. En aquella época, las computadoras eran

extremadamente grandes, lentas y costosas: los avances en tecnología electrónica en los años

de la posguerra condujeron a la construcción de computadoras electrónicas más prácticas. En

aquella época solamente Konrad Zuse imaginaba el uso de un lenguaje de programación

(desarrollado eventualmente como Plankalkül) como los de hoy para solucionar problemas.

Los descubrimientos subsecuentes en la tecnología electrónica (transistores, circuitos

integrados, y chips) condujeron el desarrollo de computadoras cada vez más confiables y más

usables. Esto fue paralelo por el desarrollo de una variedad de lenguajes de programación

estandarizado para funcionar en ellos. La disponibilidad y la facilidad de empleo mejoradas de

computadoras condujeron a un círculo mucho más ancho de la gente que puede tratar de las

computadoras. El desarrollo explosivo subsecuente ha dado lugar al Internet, ordenadores

personales, y al uso creciente de la programación en computadoras personales, con idiomas

más accesibles tales como python, básico vi sual, etc.

PARADIGMAS DE PROGRAMACION

Un paradigma de programación es un paradigma para los programas de computadora o más

generalmente el desarrollo de programación del software o de los sistemas de software. Da la

visión de que el programador tiene la ejecución del programa: por ejemplo, en el caso de la

programación orientada a objetos, el programador considera la ejecución del programa como

colección de objetos.

Un paradigma de programación a menudo está conectado con cierta escuela de la arquitectura

del software o similares y es asociado a menudo a cierta familia de lenguajes de programación.

Muchos lenguajes se diseñan para poner un paradigma en ejecución. Por ejemplo, Smalltalk y

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

34

Java se asocian a la programación orientada a objetos, mientras que Haskell y Scheme se

asocian a la programación funcional. Otras idiomas, tales como Common Lisp, python, y Oz

son para permitir el uso de paradigmas múltiples. La relación entre los paradigmas y los

lenguajes puede ser más compleja, sin embargo; por ejemplo, C++ agrega aspectos de la

programación orientada a objetos a C, un lenguaje de programación estructurado.

A programming paradigm is often closely connected to a certain school of software architecture,

software engineering or similar and is often associated with a certain family of programming

languages. Many languages are designed to implement a particular paradigm. For instance,

Smalltalk and Java are associated with object-oriented programming, while Haskell and

Scheme are associated with functional programming. Other languages, such as Common Lisp,

Python, and Oz are intended to allow the use of multiple paradigms. The relationship between

paradigms and languages can be more complex, however; for instance, C++ adds aspects of

Object-oriented programming to C, a structured programming language.

Copiar y pegar programas no es considerado un paradigma.

Algunos lenguajes orientados a objetos * SIMULA

* O’Haskell

* Ruby

* C++

* Objective -C

* D

* Java

* Action Script

* Python

* Smalltalk

* Perl

* Ocaml

* CLOS

* Eiffel

Fundamentos de Programación Ing. En Sistemas Computacionales

Realizados por: Ing. Jorge Eloy Toledo Coronel

35

1.7.- Beneficios del modelo de objetos y de la poo sobre otros Paradigmas

Día a día los costos del Hardware decrecen. Así surgen nuevas áreas de aplicación

cotidianamente: procesamiento de imágenes y sonido, bases de datos multimediales,

automatización de oficinas, ambientes de ingeniería de software, etc. Aún en las aplicaciones

tradicionales encontramos que definir interfases hombre-máquina “a-la-Windows” suele ser

bastante conveniente.

Lamentablemente, los costos de producción de software siguen aumentando; el mantenimiento

y la modificación de sistemas complejos suele ser una tarea trabajosa; cada aplicación,

(aunque tenga aspectos similares a otra) suele encararse como un proyecto nuevo, etc.

Todos estos problemas aún no han sido solucionados en forma completa. Pero como los

objetos son portables (teóricamente) mientras que la herencia permite la reusabilidad del

código orientado a objetos, es más sencillo modificar código existente porque los objetos no

interaccionan excepto a través de mensajes; en consecuencia un cambio en la codificación de

un objeto no afectará la operación con otro objeto siempre que los métodos respectivos

permanezcan intactos. La introducción de tecnología de objetos como una herramienta

conceptual para analizar, diseñar e implementar aplicaciones permite obtener aplicaciones más

modificables, fácilmente extendibles y a partir de componentes reusables. Esta reusabilidad del

código disminuye el tiempo que se utiliza en el desarrollo y hace que el desarrollo del software

sea mas intuitivo porque la gente piensa naturalmente en términos de objetos más que en

términos de algoritmos de software.

Realizado por: Ing. Jorge Eloy Toledo Coronel

1

Unidad 2

Técnicas Básicas de Modelado de Objetos

2.1.- definición de clases, atributos, métodos y objetos

2.2.- El modelo como resultado de la abstracción

2.3.- El UML como herramienta de modelado de objetos

2.4.- Planteamiento del problema

2.5.- Análisis.

2.6.- Introducción al diseño de la solución

Realizado por: Ing. Jorge Eloy Toledo Coronel

2

2.1.- Definición de Clases, Atributos, Métodos y Objetos.

Clases

El mecanismo de clases de Python añade clases al lenguaje con un mínimo de sintaxis y semántica nueva. Es una mezcla de los mecanismos de clase de C++ y Modula-3. Como en los módulos, las clases de Python no ponen una barrera absoluta entre la definición y el usuario, sino que más bien se fían de la buena educación del usuario para no ``invadir la definición''. Se mantienen las características más importantes con plena potencia. El mecanismo de herencia de clases permite múltiples clases base, una clase derivada puede redefinir cualquier método de sus clases base y un método puede llamar a un método de una clase base con el mismo nombre. Los objetos pueden contener una cantidad arbitraria de datos privados. En terminología C++, todos los miembros de la clase (datos incluidos) son públicos y todas las funciones miembro son virtuales. No hay constructores ni destructores especiales. Como en Modula-3, no existen abreviaturas para hacer referencia a los miembros del objeto desde sus propios métodos. La función método se declara con un primer argumento explícito que representa al objeto y que se proporciona implícitamente al llamar a la función. Como en Smalltalk, las clases son ellas mismas objetos, aunque en un sentido más amplio de la palabra: en Python, todos los tipos de datos son objetos. Esto proporciona la semántica para importar y renombrar. Sin embargo, como en C++ o en Modula3, los tipos internos no pueden ser la clase base para extensiones del usuario. Además, como en C++ y al contrario de Modula-3, la mayoría de operadores internos con sintaxis especial (operadores aritméticos, índices, etc.) se pueden redefinir en las clases.

Unas palabras sobre la terminología

A falta de una terminología universalmente aceptada para hablar de clases, haré uso ocasional de términos de Smalltalk y C++ (haría uso de términos de Modula-3, ya que la semántica orientada al objeto es más cercana a Python que la de C++, pero no espero que muchos lectores la dominen). También he notado que hay un agujero en la terminología de los lectores orientados a objetos: La palabra ``objeto'' en Python no significa necesariamente una instancia de una clase. Como en C++ y en Modula-3, al contrario que en Smalltalk, no todos los tipos son clases: Los tipos internos, como listas y enteros no lo son, ni siquiera algunos tipos más exóticos, como los ficheros. Sin embargo, todos los tipos de Python comparten algo de semántica común, descrita adecuadamente mediante la palabra ``objeto''. Los objetos tienen individualidad. Se pueden asociar múltiples nombres (y en diferentes ámbitos) al mismo objeto, lo que se conoce como ``generar alias'' en otros lenguajes. Esto no se aprecia a primera vista en Python y no hace falta tenerlo en cuenta cuando se trata con tipos inmutables (números, cadenas, tuplas...). Sin embargo los alias tienen un efecto (¡buscado!) en la semántica del código Python que involucra los objetos mutables, como listas, diccionarios y la mayoría de los tipos que representan entidades externas al programa (ficheros, ventanas...). Se suele usar en beneficio del programa, ya que los alias se comportan como punteros en algunos aspectos. Por ejemplo, pasar un objeto es poco costoso, ya que la implementación sólo pasa un puntero. Si la función modifica el objeto que pasa como argumento, el que llama a la función verá los cambios. De este modo se elimina la necesidad de tener los dos mecanismos de traspaso de argumentos de Pascal.

Ámbitos y espacios nominales en Python

Realizado por: Ing. Jorge Eloy Toledo Coronel

3

Antes de presentar las clases, debo contar algo sobre las reglas de alcance de Python. Las definiciones de clases realizan truquitos con los espacios nominales y se necesita saber cómo funcionan los alcances y espacios nominales para comprender plenamente lo que ocurre. Incidentalmente, el conocimiento de este tema es útil para cualquier programador en Python avanzado. Empecemos con unas definiciones. Un espacio nominal es una correspondencia entre nombres y objetos. La mayoría de los espacios de nombres se implementan en la actualidad como diccionarios, pero eso no se nota en modo alguno (salvo por el rendimiento) y puede cambiar en el futuro. Ejemplos de espacios nominales son:

• El conjunto de nombres internos (funciones como abs() y las excepciones internas). • Los nombres globales de un módulo. • Los nombres locales dentro de una llamada a función.

En cierto sentido, el conjunto de atributos de un objeto también forma un espacio nominal. Lo que hay que tener claro de los espacios nominales es que no existe absolutamente ninguna relación entre los nombres de diferentes espacios. Por ejemplo, dos módulos pueden definir una función ``maximizar'' sin posibilidad de confusión; los usuarios de los módulos deben preceder el nombre con el nombre del módulo. Por cierto, utilizo la palabra atributo para referirme a cualquier nombre que venga detrás de un punto; por ejemplo, en la expresión z.real, real es un atributo del objeto z. Hablando estrictamente, las referencias a nombres en un módulo son referencias a atributos. En la expresión nombremod.nombrefunc, nombremod es un objeto módulo y nombrefunc es atributo suyo. En este caso, resulta que existe una correspondencia directa entre los atributos del módulo y los nombres globales definidos en el módulo: ¡comparten el mismo espacio nominal9.1! Los atributos pueden ser de sólo lectura o de lectura/escritura. En este caso, es posible asignar valores a los atributos. Los atributos de los módulos son de lectura/escritura: Se puede escribir "nombremod.respuesta = 42". Los atributos de lectura/escritura se pueden borrar con la sentencia del, por ejemplo: "del nombremod.respuesta". Los espacios nominales se crean en diferentes momentos y tienen tiempos de vida diferentes. El espacio nominal que contiene los nombres internos se crea al arrancar el intérprete de Python y nunca se borra. El espacio nominal global de un módulo se crea al leer la definición del módulo. Normalmente, los espacios nominales de los módulos también duran hasta que se sale del intérprete. Las sentencias ejecutadas por el nivel superior de llamadas, leídas desde un guion o interactivamente, se consideran parte de un módulo denominado __main__, así que tienen su propio espacio nominal (los nombres internos también residen en un módulo, llamado __builtin__). El espacio nominal local de una función se crea cuando se llama a la función y se borra al salir de la función, por una sentencia "return"o si salta una excepción que la función no captura (en realidad, lo más parecido a lo que ocurre es el olvido). Por supuesto, las llamadas recursivas generan cada una su propio espacio nominal. Un ámbito es una región textual de un programa Python en que el espacio nominal es directamente accesible. ``Directamente accesible'' significa en este contexto una referencia sin calificar (sin puntos) que intenta encontrar un nombre dentro de un espacio nominal. Aunque los ámbitos se determinan estáticamente, se utilizan dinámicamente. En cualquier punto de la ejecución, existen exactamente tres ámbitos anidados (es decir, hay tres espacios nominales accesibles directamente): el ámbito interior, el primero en que se busca el nombre, que contiene los nombres locales, el ámbito medio, siguiente en la búsqueda de nombres, que contiene los nombres globales del módulo, y el ámbito externo, el último en la búsqueda, que contiene los nombres internos. Normalmente, el ámbito local hace referencia a los nombres locales de la función en curso (textualmente). Fuera de las funciones, el ámbito local hace referencia al mismo espacio nominal que el ámbito global: el espacio nominal del módulo. Las definiciones de clases colocan otro espacio nominal en el ámbito local. Es importante darse cuenta de que los ámbitos se determinan textualmente: El ámbito global de una función definida en un módulo es el espacio nominal de este módulo, sin importar desde dónde o con qué alias se haya llamado a la función. Por otra parte, la búsqueda real de nombres se lleva a cabo dinámicamente, en tiempo de ejecución. Sin embargo, la definición del

Realizado por: Ing. Jorge Eloy Toledo Coronel

4

lenguaje tiende a la resolución estática de los nombres, así que ¡no te fíes de la resolución dinámica de los nombres! De hecho ya se determinan estáticamente las variables locales. Un asunto especial de Python es que las asignaciones siempre van al ámbito más interno. Las asignaciones no copian datos, simplemente enlazan nombres a objetos. Lo mismo vale para los borrados: la sentencia "del x" elimina el enlace de x del espacio nominal al que hace referencia el ámbito local. De hecho, todas las operaciones que introducen nombres nuevos utilizan el ámbito local. Particularmente, las sentencias import y las definiciones de funciones asocian el nombre del módulo o función al ámbito local. Se puede utilizar la sentencia global para indicar que ciertas variables residen en el ámbito global.

Un primer vistazo a las clases

Las clases introducen una pizca de sintaxis nueva, tres tipos de objeto nuevos y algo de semántica nueva.

Sintaxis de definición de clases

La forma más simple de definición de clase tiene este aspecto: class nombreClase: <sentencia-1> . . . <sentencia-N>

Las definiciones de clases, como las definiciones de funciones (sentencias def) deben ejecutarse para tener efecto (es perfectamente correcto colocar una definición de clase en una rama de una sentencia if o dentro de una función). En la práctica, las sentencias de dentro de una definición de clase serán definiciones de funciones, pero se permite otro tipo de sentencias, lo que resulta útil en algunos casos, ya veremos esto. Las definiciones de funciones interiores a la clase suelen tener una lista de argumentos un poco especial, dictada por las convenciones de llamada a método. Esto también se explica más adelante. Cuando se entra en una definición de clase, se genera un nuevo espacio nominal, que se utiliza como ámbito local; así que todas las asignaciones a variables locales caen dentro de este nuevo espacio nominal. En particular, las definiciones de funciones enlazan aquí el nombre de la nueva función. Cuando se abandona una definición de clase de manera normal (se ejecuta la última línea de su código), se crea un objeto de clase. Es, sencillamente, un envoltorio del contenido del espacio nominal creado por la definición de la clase. Se verá con más detalle en la siguiente sección. El ámbito local original (el que estaba activo cuando se entró en la definición de clase) se reinstancia y el objeto clase se enlaza con el nombre de clase dado en la cabecera de la función (en el ejemplo nombreClase).

Objetos clase

Los objetos de clase soportan dos tipos de operaciones: referencia a atributos e instanciación. Las referencias a atributos utilizan la sintaxis estándar que se utiliza para todas las referencias a atributos en Python: obj.nombre. Los nombres de atributos válidos son todos los nombres

Realizado por: Ing. Jorge Eloy Toledo Coronel

5

que estaban en el espacio nominal de la clase cuando fue creada la clase. Por lo tanto, si la definición de la clase tiene este aspecto:

class MiClase: "Simple clase de ejemplo" i = 12345 def f(x): return 'hola, mundo'

MiClase.i y MiClase.f son referencias a atributos válidas, que devuelven un entero y un objeto método, respectivamente. También se puede asignar valores a los atributos de una clase; puedes cambiar el valor de MiClase.i con una asignación. __doc__ es también un atributo válido, que devuelve la cadena de documentación que corresponde a la clase: "Simple clase de ejemplo". La instanciación de clases utiliza notación de función. Basta con imaginar que el objeto clase es una función sin parámetros que devuelve una instancia nueva de la clase. Por ejemplo, siguiendo con el ejemplo anterior:

x = MiClase() crea una nueva instancia de la clase y la asigna a la variable local x. La operación de instanciación (``la llamada'' a un objeto clase) genera un objeto vacío. Muchas clases prefieren generar los objetos en un estado inicial conocido. Por ello, una clase puede definir un método especial denominado __init__(), así:

def __init__(self): self.vaciar()

Cuando una clase define un método __init__(), la instanciación de clases llama automáticamente a __init__() para la instancia de clase recién creada. Así que, en el ejemplo de la Bolsa, se puede obtener una instancia de clase inicializada nueva mediante:

x = Bolsa() Por supuesto, el método __init__() podría tener argumentos que le añadirían flexibilidad. En tal caso, los argumentos proporcionados al operador de instanciación de clase se pasan a __init__(). Por ejemplo,

>>> class Complejo: ... def __init__(self, parteReal, parteImaginaria): ... self.r = parteReal ... self.i = parteImaginaria ... >>> x = Complejo(3.0,-4.5) >>> x.r, x.i (3.0, -4.5)

Objetos instancia

¿Qué se puede hacer con los objetos instancia? Las únicas operaciones que entienden son las referencias a atributos. Hay dos tipos de nombres de atributo válidos. A los primeros los voy a llamar atributos de datos. Corresponden a las ``variables de instancia'' de Smalltalk o a los ``miembros dato'' de C++. No es necesario declarar los atributos de datos. Como las variables locales, aparecen por arte de magia la primera vez que se les asigna un valor. Por ejemplo, si x es una instancia de la clase MiClase creada anteriormente, el código siguiente mostrará el valor 16 sin dejar rastro:

x.contador = 1 while x.contador < 10: x.contador = x.contador * 2 print x.contador del x.contador

El segundo tipo de referencia a atributo que entienden los objetos instancia son los Métodos. Un método es una función que ``pertenece a'' un objeto. En Python, el término método no se limita a las instancias de una clase, ya que otros tipos de objeto pueden tener métodos también. Por ejemplo, los objetos de tipo lista tienen métodos llamados append,

Realizado por: Ing. Jorge Eloy Toledo Coronel

6

insert, remove, sort, etc. Sin embargo, vamos a utilizar ahora el término exclusivamente para referirnos a los métodos de objetos instancia de una clase, salvo que se indique lo contrario. Los nombres válidos de métodos de un objeto instancia dependen de su clase. Por definición, todos los atributos de una clase que son objetos función (definidos por el usuario) definen los métodos correspondientes de sus instancias. Así que, en nuestro ejemplo, x.f es una referencia a método correcta, ya que MiClase.f es una función, pero x.i no lo es, ya que MiClase.i no es una función. Pero x.f no es lo mismo que MiClase.f - es un objeto método, no un objeto función.

Objetos método

Normalmente, se llama a un método de manera inmediata, por ejemplo: x.f()

En nuestro ejemplo, esto devuelve la cadena 'hola, mundo'. Sin embargo, no es necesario llamar a un método inmediatamente: x.f es un objeto método y se puede almacenar y recuperar más tarde, por ejemplo:

xf = x.f while 1: print xf()

mostrará "hola, mundo" hasta que las ranas críen pelo. ¿Qué ocurre exactamente cuando se llama a un método? Habrás observado que x.f() fue invocado sin argumento, aunque la definición del método f especificaba un argumento. ¿Qué le ha pasado al argumento? Desde luego, Python hace saltar una excepción cuando se llama a una función que necesita un argumento sin especificar ninguno (aunque no se utilice)... En realidad, te puedes imaginar la respuesta: Lo que tienen de especial los métodos es que el objeto que los llama se pasa como primer argumento de la función. En nuestro ejemplo, la llamada x.f() es totalmente equivalente a MiClase.f(x). En general, llamar a un método con una lista de argumentos es equivalente a llamar a la función correspondiente con la lista de argumentos resultante de insertar el objeto del método al principio de la lista de argumentos original. Si todavía no entiendes cómo funcionan los métodos, igual te aclara las cosas un vistazo a la implementación. Cuando se hace referencia a un atributo de una instancia que no es un atributo de datos, se busca en su clase. Si el nombre denota un atributo de clase válido que resulta ser un objeto función, se crea un objeto método empaquetando juntos (punteros hacia) el objeto instancia y el objeto función recién encontrado en un objeto abstracto: el objeto método. Cuando se llama al objeto método con una lista de argumentos, se desempaqueta de nuevo, se construye una nueva lista de argumentos a partir del objeto instancia y la lista de argumentos original y se llama al objeto función con la nueva lista de argumentos.

Variables privadas

Se pueden utilizar, de manera limitada, identificadores privados de la clase. Cualquier identificador de la forma __fiambre (al menos dos guiones bajos iniciales, no más de un guion bajo final) se reemplaza textualmente ahora con _nombreClase__fiambre, donde nombreClase es la clase en curso, eliminando los guiones bajos iniciales. Esta reescritura se realiza sin tener en cuenta la posición sintáctica del identificador, por lo que se puede utilizar para definir, de manera privada, variables de clase e instancia, métodos y variables globales. También sirve para almacenar variables de instancia privadas de esta clase en instancias de otras clases. Puede que se recorten los nombres cuando el nombre reescrito tendría más de 255 caracteres. Fuera de las clases o cuando el nombre de la clase consta sólo de guiones bajos, no se reescriben los nombres. La reescritura de nombres pretende dar a las clases un modo sencillo de definir métodos y variables de instancia ``privados'', sin tener que preocuparse por las variables de instancia definidas por las clases derivadas ni guarrear con las variables de instancia por el código externo a la clase. Observa que las reglas de reescritura se han diseñado sobre todo para evitar accidentes; aún es posible, con el suficiente empeño, leer o modificar una variable considerada privada. Esto puede ser útil, por ejemplo, para el depurador, por lo que no se ha cerrado esta puerta falsa. Hay un pequeño fallo: la derivación de una clase con el mismo nombre que su clase base hace posible el uso de las variables privadas de la clase base.

Realizado por: Ing. Jorge Eloy Toledo Coronel

7

Observa que el código pasado a exec, eval() o evalfile() no considera el nombre de la clase llamante la clase actual. Es similar al efecto de la sentencia global, cuyo efecto está, de igual manera, restringido al código de un fichero. Se aplica la misma restricción a getattr(), setattr(), delattr() y también cuando se hace referencia a __dict__ directamente. He aquí un ejemplo de una clase que implementa sus propios métodos __getattr__ y __setattr__ y almacena todos los atributos en una variable privada de manera que funciona adecuadamente en todas las versiones de Python, incluidas las anteriores a agregar esta característica:

class atributosVirtuales: __vdic = None __vdic_nombre = locals().keys()[0] def __init__(self): self.__dict__[self.__vdic_nombre] = {} def __getattr__(self, nombre): return self.__vdic[nombre] def __setattr__(self, nombre, valor): self.__vdic[nombre] = valor

Las excepciones pueden ser clases

Las excepciones definidas por usuario ya no están limitadas a objetos cadena de texto; también pueden identificarse mediante clases. Utilizando estos mecanismos es posible crear jerarquías ampliables de excepciones. Hay dos formas válidas nuevas de sentencia raise:

raise Clase, instancia raise instancia

En la primera forma, instancia debe ser una instancia de Clase o de una clase derivada de ella. La segunda forma es un atajo de:

raise instancia.__class__, instancia Una cláusula except puede enumerar clases al igual que objetos cadena. Una clase de una cláusula except captura una excepción si es de la misma clase que la excepción que ha saltado o es de una clase base de ella (al revés no; una clase derivada no captura ninguna de sus clases base). Por ejemplo, el código a continuación mostrará B, C, D, en ese orden:

class B: pass class C(B): pass class D(C): pass for c in [B, C, D]: try: raise c() except D: print "D" except C: print "C" except B: print "B"

Observa que si invertimos las cláusulas ("except B" primero), se mostraría B, B, B, ya que la primera cláusula captura todas las excepciones, por ser clase base de todas ellas. Cuando se presenta un mensaje de error para una excepción sin capturar, se muestra el nombre de la clase, dos puntos, un espacio y, por último, la instancia convertida a cadena mediante la función interna str().

Realizado por: Ing. Jorge Eloy Toledo Coronel

8

2.2.- El Modelo como resultado de la abstracción

El modelo procedimental puede representarse como en la figura 8.1.

Figura 8.1.- Modelo procedimental. donde se observa que los datos y el código se manejan como partes separadas. El programa ( código ) es alimentado con los datos para que produzca resultados. Por otra parte, el modelo orientado a objetos puede representarse como en la figura 8.2.

Figura 8.2.- Modelo de la Programación Orientada a Objetos. donde DATOS y CODIGO se han unido para formar un OBJETO, el cual va a producir ciertos RESULTADOS, de acuerdo al MENSAJE que se le envíe. Esto es, un objeto de ciertas características va a comportarse de acuerdo a su clase al recibir un mensaje específico. Como se logra el ENCAPSULAMIENTO en el lenguaje C++ ? Podemos pensar que, así como se requieren tipos para definir las variables en un enfoque procedimental, se requieren "tipos" o "moldes" para crear los objetos. En el lenguaje C++ esos moldes se crean por medio de las palabras reservadas : class, struct y union . La Geometría representa un campo idóneo para ejemplificar el manejo de objetos. Las definiciones para cada una de las figuras se hacen a través de enunciados que incluyen la expresión: " .. es el lugar geométrico de todos los puntos que ...". Como puede verse, el concepto de punto es la base para la definición de cualquier figura geométrica. La representación de las figuras geométricas, en la pantalla de un monitor, se hace por medio de los pixeles, que son los elementos básicos ( puntos iluminados ) utilizados para representar los gráficos en la pantalla. Con base a estos conceptos, en la siguiente sección vamos a crear una clase base llamada punto. Los objetos de tipo punto podrán situarse en cualquier lugar de la pantalla utilizando un par de coordenadas ( x,y ).

dentro de la programación c# que tien como extensión cs que ya es para la programación de sisteas .net se tiene el siguiente modelo: programa en c#l compilador lenguaje msil basura donde el el lenguaje msil es un lenguaje a nivel maquina pero de alto nivel y la basura pos son los objetos no relacionados.

Realizado por: Ing. Jorge Eloy Toledo Coronel

9

Nov ‘97 UML aprobado por el OMG

1998

1999

2000

UML 1.2

UML 1.3

UML 1.4

2005?

Revisiones menores

UML 1.5 2003

2.3.- El UML como una Herramienta de modelado de Objetos A comienzos de 1999 se le dio forma a la primera versión de este curso de modelado OO con UML. A partir del material recolectado y preparado para la asignatura de quinto año de facultad “Laboratorio de Sistemas de Información”. Por otra parte, en mi tesis doctoral (en animación automática de modelos conceptuales) había trabajado en profundidad en aspectos de modelado orientado a objetos. En un comienzo no existía una demanda específica pero ya en Agosto de 1999 el curso pudo estrenarse parcialmente en un seminario que dicté en la Universidad Santa María de Valparaíso-Chile. Posteriormente y hasta la fecha se han realizado 16 ediciones del curso, el cual se ofrece a través de nuestro departamento y el Centro de Formación de Postgrado de la UPV. A mediados de 2000 se dio otro paso: dejar a libre disposición vía internet el material del curso. El objetivo ha sido promover y difundir el uso de técnicas OO en el mundo hispano, facilitando la labor de preparación de material para profesores y/o proporcionar documentación de apoyo para los estudiantes. Hasta fines del 2003 se habían realizado más de 20000 descargas del material del curso, lo cual confirmaba la necesidad de información de UML en español en la red. Cada edición del curso ha dado pie a mejoras, todo ello intentando mantener el volumen de trasparencias. Se han añadido notas al pie de página en algunas trasparencias para apoyar la exposición. Precisamente en esto se centra el esfuerzo actual y futuro de este material. Esperamos que el material proporcionado os sea de utilidad, ¿Qué es UML? § UML = Unified Modeling Language

§ Un lenguaje de propósito general para el modelado orientado a objetos. Impulsado por

el Object Management Group (OMG, www.omg.org) § Documento “OMG Unified Modeling Language Specification”

§ UML combina notaciones provenientes desde:

• Modelado Orientado a Objetos • Modelado de Datos • Modelado de Componentes • Modelado de Flujos de Trabajo (Workflows)

Historia de UML § Comenzó como el “Método Unificado”, con la participación de Grady Booch y Jim

Rumbaugh. Se presentó en el OOPSLA’95 § El mismo año se unió Ivar Jacobson. Los “Tres Amigos” son socios en la compañía

Rational Software. Herramienta CASE Rational Rose

Realizado por: Ing. Jorge Eloy Toledo Coronel

10

Rational Software o (Grady Booch, Jim Rumbaugh y Ivar

Jacobson) Digital Equipment Hewlett-Packard i-Logix (David Harel) IBM ICON Computing

o (Desmond D’Souza) Intellicorp and James Martin & co. (James

Odell)

Participantes en UML 1.0 Inconvenientes en UML § Definición del proceso de desarrollo usando UML. UML no es una metodología

§ No cubre todas las necesidades de especificación de un proyecto software. Por

ejemplo, no define los documentos textuales § Ejemplos aislados

Ø MCI Systemhouse Ø Microsoft Ø ObjecTime Ø Oracle Corp. Ø Platinium Technology Ø Sterling Software Ø Taskon Ø Texas Instruments Ø Unisys

Realizado por: Ing. Jorge Eloy Toledo Coronel

11

Use Case Diagrams

Use Case Diagrams Diagramas

de Casos de

Scenario Diagrams

Scenario Diagrams Diagramas

de Colaboraci

State Diagrams

State Diagrams Diagramas

de Component

Component Diagrams Component

Diagrams Diagramas de

Distribució

State Diagrams

State Diagrams Diagramas

de Objetos

Scenario Diagrams

Scenario Diagrams Diagramas

de Estados

Use Case Diagrams

Use Case Diagrams Diagramas

de Secuencia

State Diagrams

State Diagrams Diagramas

de Clases

Diagramas de

Actividad

Modelos

§ “Monopolio de conceptos, técnicas y métodos en torno a UML y el OMG”

Perspectivas de UML § UML es el lenguaje de modelado orientado a objetos estándar predominante ahora y

en los próximos años § Razones:

• Participación de metodólogos influyentes • Participación de importantes empresas • Estándar del OMG

§ Evidencias: • Herramientas que proveen la notación UML • “Edición” de libros (más de 300 en www.amazon.com) • Congresos, cursos, “camisetas”, etc.

Diagramas de UML Los diagramas expresan gráficamente partes de un modelo

Realizado por: Ing. Jorge Eloy Toledo Coronel

12

Retirar dinero

Consultar ExtractoCliente

Realizar transferencia

Ejemplo: Resumen § UML define una notación que se expresa como diagramas sirven para representar

modelos/subsistemas o partes de ellos § El 80 por ciento de la mayoría de los problemas pueden modelarse usando alrededor

del 20 por ciento de UML-- Grady Booch 2.4.- Planteamiento del Problema Esta fase está dada por el enunciado del problema, el cual requiere una definición clara y precisa. Es importante que se conozca lo que se desea que realice la computadora; mientras esto no se conozca del todo no tiene mucho caso continuar con la siguiente etapa 2.4.1.- Analizar el enunciado del problema

El Análisis de Sistemas trata básicamente de determinar los objetivos y límites del sistema objeto de análisis, caracterizar su estructura y funcionamiento, marcar las directrices que permitan alcanzar los objetivos propuestos y evaluar sus consecuencias. Dependiendo de los objetivos del análisis podemos encontrarnos ante dos problemáticas distintas:

• Análisis de un sistema ya existente para comprender, mejorar, ajustar yo predecir su comportamiento.

• Análisis como paso previo al diseño de un nuevo sistema-producto.

En cualquier caso, podemos agrupar más formalmente las tareas que constituyen el análisis en una serie de etapas que se suceden de forma iterativa hasta validar el proceso completo:

• Conceptualización Consiste en obtener una visión de muy alto nivel del sistema, identificando sus elementos básicos y las relaciones de éstos entre sí y con el entorno.

Realizado por: Ing. Jorge Eloy Toledo Coronel

13

• Análisis funcional Describe las acciones o transformaciones que tienen lugar en el sistema. Dichas acciones o transformaciones se especifican en forma de procesos que reciben una entradas y producen unas salidas.

• Análisis de condiciones (o constricciones) Debe reflejar todas aquellas limitaciones impuestas al sistema que restringen el margen de las soluciones posibles. Estas se derivan a veces de los propios objetivos del sistema:

o Operativas, como son las restricciones físicas, ambientales, de mantenimiento, de personal, de seguridad, etc.

o De calidad, como fiabilidad, mantenibilidad, seguridad, convivencialidad, generalidad, etc.

Sin embargo, en otras ocasiones las constricciones vienen impuestas por limitaciones en los diferentes recursos utilizables:

o Económicos, reflejados en un presupuesto. o Temporales, que suponen unos plazos a cumplir. o Humanos. o Metodológicos, que conllevan la utilización de técnicas determinadas. o Materiales, como espacio, herramientas disponibles, etc.

• Construcción de modelos Una de las formas más habituales y convenientes de analizar un sistema consiste en construir un prototipo (un modelo en definitiva) del mismo.

• Validación del análisis A fin de comprobar que el análisis efectuado es correcto y evitar en su caso la posible propagación de errores a la fase de diseño, es imprescindible proceder a la validación del mismo. Para ello hay que comprobar los extremos siguientes:

o El análisis debe ser consistente y completo. o Si el análisis se plantea como un paso previo para realizar un diseño, habrá

que comprobar además que los objetivos propuestos son correctos y realizables.

Una ventaja fundamental que presenta la construcción de prototipos desde el punto de vista de la validación radica en que estos modelos, una vez construidos, pueden ser evaluados directamente por los usuarios o expertos en el dominio del sistema para validar sobre ellos el análisis.

. 2.4..2.- Identificar funciones del sistema 2.5.- Análisis 2.5.1.- Descubrir objetos en el dominio del problema

Si se observa alrededor en una habitación, existen un conjunto de objetos físicos que pueden ser fácilmente identificados, clasificados y definidos (en términos de atributos y operaciones). Pero cuando se “observa” el espacio de un problema en una aplicación de software, los objetos pueden ser más difíciles de identificar.

Se puede empezar a identificar objetos examinando el planteamiento del problema o realizando un “análisis sintáctico gramatical” en la narrativa del sistema que se va a construir. Los objetos se determinan subrayando cada nombre o cláusula nominal e introduciéndola en una tabla simple.

Los sinónimos deben destacarse. Si se requiere del objeto que implemente una solución, entonces éste formará parte del espacio de solución; en caso de que el objeto se necesite solamente para describir una solución, éste forma parte del espacio del problema. Los objetos se manifiestan de alguna de las formas siguientes:

Realizado por: Ing. Jorge Eloy Toledo Coronel

14

Entidades Externas que producen o consumen información a usar por un sistema computacional. Por ejemplo: otros sistemas, dispositivos, personas.

Cosas que son parte del dominio de información del problema. Por ejemplo: informes, presentaciones, cartas, señales.

Ocurrencias o Sucesos que ocurren dentro del contexto de una operación del sistema. Por ejemplo: una transferencia de propiedad o la terminación de una serie de movimientos en un robot.

Papeles o Roles desempeñados por personas que interactúan con el sistema. Por ejemplo: director, ingeniero, vendedor.

Unidades Organizacionales que son relevantes en una aplicación. Por ejemplo: división, grupo, equipo.

Lugares que establecen el contexto del problema y la función general del sistema. Por ejemplo: planta de producción o muelle de carga.

Estructuras que definen una clase de objetos o, en casos extremos, clases relacionadas de objetos. Por ejemplo: sensores, vehículos de cuatro ruedas o computadoras.

La clasificación mostrada es una de las muchas que se han propuesto en la literatura. También es importante destacar qué no son los objetos. En general, un objeto nunca debe tener un “nombre procedimental imperativo”. Por ejemplo, si los desarrolladores de un software para un sistema gráfico médico definieron un objeto con el nombre inversión de imagen, estarían cometiendo un sutil error. La imagen obtenida por el software pudiera ser, en efecto, un objeto (es un elemento que forma parte del dominio de información), pero la inversión de la imagen es una operación que se aplica a dicho objeto. Inversión debe definirse como una operación del objeto imagen, pero no como un objeto separado que signifique “inversión de imagen”. Como establecen algunos autores, “… el objetivo de la orientación a objetos es encapsular, pero manteniendo separados los datos y las operaciones sobre estos datos”.

Para ilustrar cómo pueden definirse los objetos se presenta la narrativa de procesamiento para el sistema Hogar Seguro:

El software Hogar Seguro le permite al propietario de la casa configurar el sistema de seguridad una vez que este se instala, controla todos los sensores conectados al sistema de seguridad, e interactúa con el propietario a través de un teclado numérico y teclas de función contenidas en el panel de control de Hogar Seguro.

Durante la instalación, el panel de control de Hogar Seguro se usa para “programar” y configurar el sistema. A cada sensor se le asigna un número y tipo, se programa una contraseña maestra para activar y desactivar el sistema, y se introducen números de teléfono a marcar cuando un sensor detecte un suceso.

Cuando se reconoce un suceso de sensor, el software invoca una alarma audible asociada al sistema. Después de un tiempo de espera especificado por el propietario durante las actividades de configuración del sistema, el software marca un número de teléfono de un servicio de control, proporciona información acerca de la localización, e informa de la naturaleza del suceso detectado. El número será remarcado cada 20 segundos hasta obtener una conexión telefónica.

Toda la interacción con Hogar Seguro está gestionada por un subsistema de interacción con el usuario que toma la entrada a partir del teclado numérico y teclas de función, y muestra mensajes y el estado del sistema en la pantalla LCD.

Realizado por: Ing. Jorge Eloy Toledo Coronel

15

La interacción con el teclado toma la siguiente forma…Extrayendo los nombres pueden proponerse varios objetos potenciales:

La lista anterior debe ser continuada hasta que se hayan considerado todos los nombres de la descripción del proceso. Observe que se ha llamado a cada entrada en la lista un objeto potencial. Se debe considerar cada uno de ellos antes de tomar una decisión final.

Coud y Yourdon sugieren seis características de selección a usar cada vez que un analista considera si incluye o no un objeto potencial en el modelo de análisis:

Información retenida el objeto potencial será de utilidad durante el análisis solamente si la información acerca de él debe recordarse para que el sistema funciones.

Servicios necesarios el objeto potencial debe poseer un conjunto de operaciones identificables que pueden cambiar de alguna manera el valor de sus atributos.

Atributos múltiples durante el análisis de requisitos, se debe centrar la atención en la información principal (un objeto con un solo atributo puede, en efecto, ser útil durante el diseño, pero seguramente será mejor presentado como un atributo de otro objeto durante la actividad de análisis).

Atributos comunes puede definirse un conjunto de atributos para el objeto potencial, los cuales son aplicables a todas las ocurrencias del objeto.

Operaciones comunes puede definirse un conjunto de operaciones para el objeto potencial, las cuales son aplicables a todas las ocurrencias del objeto.

Requisitos esenciales entidades externas que aparecen en el espacio del problema y producen o consumen información esencial para la producción de cualquier solución para el sistema, serán casi siempre definidas como objetos en el modelo de requisitos.

Para ser considerado un objeto válido a incluir en el modelo de requisitos, un objeto potencial debe satisfacer todas (o casi todas) las características anteriores. La decisión de incluir objetos potenciales en el modelo de análisis es algo subjetivo, y una evaluación posterior puede llegar a descartar un objeto o reincluirlo. Sin embargo, el primer paso del Análisis Orientado a Objetos debe ser la definición de objetos, y la consiguiente toma de decisiones (incluso subjetivas).

Teniendo esto en cuenta, se aplicarán las características selectivas a la lista de objetos potenciales de Hogar Seguro:

Realizado por: Ing. Jorge Eloy Toledo Coronel

16

Debe tenerse en cuenta que: (1) la lista anterior no incluye todo, hay que añadir objetos adicionales para completar el modelo; (2) algunos de los objetos potenciales rechazados serán atributos de los objetos aceptados (por ejemplo, número y tipo son atributos de sensor, y contraseña maestra y número de teléfono pueden convertirse en atributos de sistema); y (3) diferentes descripciones del problema pueden provocar la toma de diferentes decisiones de “aceptación o rechazo” (por ejemplo, si cada propietario tiene su propia contraseña o fue identificado por impresiones de voz, el objeto Propietario cumpliría las características a y b y habría sido aceptado).

2.5.2.- Identificar atributos de los objetos

Los atributos describen un objeto que ha sido seleccionado para ser incluido en el modelo de análisis. En esencia, son los atributos los que definen al objeto, los que clarifican lo que representa el objeto en el contexto del espacio del problema. Por ejemplo, si se tratara de construir un sistema de estadísticas para jugadores profesionales de béisbol, los atributos del objeto Jugador serían muy diferentes de los atributos del mismo objeto cuando se use dentro del contexto de un sistema de pensiones para jugadores profesionales. En el primero, atributos tales como nombre, posición, promedio de bateo, porcentaje de estancia en el campo de juego, años jugados y partidos jugados pueden ser relevantes. En el segundo caso, algunos de estos atributos serían relevantes pero otros serían reemplazados (o potenciados) por atributos como salario medio, crédito total, opciones elegidas para el plan de pensión, dirección postal, etc.

Para desarrollar un conjunto significativo de atributos para un objeto, el analista puede estudiar de nuevo la narrativa del proceso (o descripción del ámbito del alcance) para el problema y seleccionar aquellos elementos que razonablemente “pertenecen” al objeto. Además, para cada objeto debe responderse el siguiente interrogante: “¿Qué elementos (compuestos y/o simples) definen completamente al objeto en el contexto del problema actual?”

Para ilustrar esto, se considerará el objeto Sistema definido para Hogar Seguro. Anteriormente se indicó que el propietario puede configurar el sistema de seguridad para reflejar la información acerca de los sensores, sobre la respuesta de la alarma, sobre la activación / desactivación, sobre identificación, etc. Usando la notación de la descripción del contenido se podría representar estos elementos de datos compuestos de la siguiente manera:

Información del sensor = tipo de sensor + número de sensor + umbral de alarma. Información de respuesta de la alarma = tiempo de retardo + número de teléfono + tipo de alarma.

Información de activación / desactivación = contraseña maestra + cantidad de intentos permitidos + contraseña temporal.

Realizado por: Ing. Jorge Eloy Toledo Coronel

17

Información de identificación = ID del sistema + verificación de número de teléfono + estado del sistema.

2.5.3.- Identificar métodos en los objetos.

Los métodos especifican la forma en que se controlan los datos de un objeto. Los métodos en un tipo de objeto sólo hacen referencia a la estructura de datos de ese tipo de objeto. No deben tener acceso directo a las estructuras de datos de otros objetos. Para utilizar la estructura de datos de otro objeto, deben enviar un mensaje a éste. El tipo de objeto empaca juntos los tipos de datos y su comportamiento. Un objeto entonces es una cosa cuyas propiedades están representadas por tipos de datos y su comportamiento por métodos. Un método asociado con el tipo de objeto factura podría ser aquel que calcule el total de la factura. Otro podría transmitir la factura a un cliente. Otro podría verificar de manera periódica si la factura ha sido pagada y, en caso contrario, añadir cierta tasa de interés.

2.6.- Introducción al Diseño de la solución 2.6.1.- Representación grafica de una clase § El Diagrama de Clases es el diagrama principal para el análisis y diseño del sistema

§ Un diagrama de clases presenta las clases del sistema con sus relaciones

estructurales y de herencia § La definición de clase incluye definiciones para atributos y operaciones

§ El modelo de casos de uso debería aportar información para establecer las clases,

objetos, atributos y operaciones

Diagrama de Clases

Alumno

DNI : char[10]número_exp : intnombre : char[50]

alta()poner_nota(asignatura : char *, año : int, nota : float)matricular(cursos : asignatura, año : int)listar_expediente()

Realizado por: Ing. Jorge Eloy Toledo Coronel

18

Un Diagrama de Clases de Diseño muestra la especificación para las clases software de una aplicación. Incluye la siguiente información: • Clases, asociaciones y atributos. • Interfaces, con sus operaciones y constantes. • Métodos. • Navegabilidad. • Dependencias. A diferencia del Modelo Conceptual, un Diagrama de Clases de Diseño muestra definiciones de entidades software más que conceptos del mundo real. En la Figura 39 se muestra un ejemplo de Diagrama de Clases de Diseño sencillo.

Realizado por: Ing. Jorge Eloy Toledo Coronel

19

Ejemplo de Diagrama de Clases

2.6.2.- Diagrama de iteración entre la aplicación y una clase. Los Diagramas de Interacción muestran el intercambio de mensajes entre instancias del modelo de clases para cumplir las post-condiciones establecidas en un contrato Hay dos clases de Diagramas de Interacción: 1. Diagramas de Colaboración. 2. Diagramas de Secuencia. La notación en UML para ambos es la definida en la página 11. De entre ambos tipos, los Diagramas de Colaboración tienen una mayor expresividad y mayor economía espacial (una interacción compleja puede ser muy larga en un Diagrama de Secuencia), sin embargo en ellos la secuencia de interacción entre objetos es más difícil de seguir que en un Diagrama de Secuencia. Ambos tipos de diagramas expresan la misma información, por lo que se puede usar cualquiera de los dos para expresar la interacción entre los objetos del sistema. La creación de los Diagramas de Interacción de un sistema es una de las actividades más importantes en el desarrollo orientado a objetos, pues al construirlos se toman unas decisiones clave acerca del funcionamiento del futuro sistema. La creación de estos diagramas, por tanto, debería ocupar un porcentaje significativo en el esfuerzo dedicado al proyecto entero. Creación de Diagramas de Interacción Para crear los Diagramas de Colaboración o de Secuencia se pueden seguir los siguientes consejos: • Crear un diagrama separado para cada operación del sistema en desarrollo en el ciclo de desarrollo actual. - Para cada evento del sistema, hacer un diagrama con él como mensaje inicial. • Usando los apartados de responsabilidades y de post-condiciones del contrato de operación, y la descripción del caso de uso como punto de partida, diseñar un sistema de objetos que interaccionan para llevar a cabo las tareas requeridas. • Si el diagrama se complica, dividirlo en dos diagramas más pequeños. Para ello se termina la secuencia de mensajes en un mensaje determinado, y en el segundo diagrama se comienza con el mensaje que terminó el primero. Debe indicarse en el primer diagrama que el resto de la interacción se detalla en el segundo. El comportamiento dinámico del sistema que se describe en un Diagrama de Interacción debe ser acorde con la estructura estática del sistema que se refleja en el Diagrama de Clases de Diseño. Es aconsejable realizar un Diagrama de Clases de Diseño borrador antes de comenzar con los Diagramas de Interacción. La capacidad de realizar una buena asignación de responsabilidades a los distintos objetos es una habilidad clave, y se va adquiriendo según aumenta la experiencia en el desarrollo orientado a objetos. Responsabilidad es como un contrato u obligación de una clase o tipo. Las responsabilidades están ligadas a las obligaciones de un objeto en cuanto a su comportamiento. Básicamente, estas responsabilidades pueden ser de tipo Conocer o de tipo Hacer: • Conocer: - Conocer datos privados encapsulados. - Conocer los objetos relacionados. - Conocer las cosas que puede calcular o derivar. • Hacer: - Hacer algo él mismo.

Realizado por: Ing. Jorge Eloy Toledo Coronel

20

: Encargado

:WInPréstamos

:Socio

:Video

:Préstamo

1: prestar(video, socio)

2: verificar situación socio

3: verificar situación video

4: registrar préstamo5: entregar recibo

- Iniciar una acción en otros objetos. - Controlar y coordinar actividades en otros objetos. Por ejemplo, puedo decir que “un Recibo es responsable de calcular el total” (tipo hacer), o que “una Transacción es responsable de saber su fecha” (tipo conocer). Las responsabilidades de tipo “conocer” se pueden inferir normalmente del Modelo Conceptual. Una responsabilidad no es lo mismo que un método, pero los métodos se implementan para satisfacer responsabilidades. 1.- Diagramas de Colaboración.

Realizado por: Ing. Jorge Eloy Toledo Coronel

21

Socionúmero : intnombre : char[50]número_prestamos : int = 0

alta()baja()prestar(código_libro : int, fecha : date)devolver(código_libro : int, fecha : date)

con préstamos

sin préstamos

alta baja

prestar devolver[ número_préstamos = 1 ]

prestar

devolver[ número_préstamos > 1 ]

número_préstamos = 0

número_préstamos > 0

: Encargado :WInPréstamos :Socio :Video :Préstamo

prestar(video, socio)

verificar situación socio

verificar situación video

registrar préstamo

entregar recibo

2. Diagramas de Secuencia

2.6.3.- Diagramas de estado de una clase

Realizado por: Ing. Jorge Eloy Toledo Coronel

22

Realizado por: Ing. Jorge Eloy Toledo Coronel

1

Unidad 3 Técnicas de Diseño detallado 3.1.- Diseño algorítmico 3.2.- Diseño algorítmico de las funciones

Realizado por: Ing. Jorge Eloy Toledo Coronel

2

3.1.- Diseño Algorítmico Definición de Algoritmo La palabra algoritmo se deriva de la traducción al latín de la palabra árabe alkhowarizmi, nombre de un matemático y astrónomo árabe que escribió un tratado sobre manipulación de números y ecuaciones en el siglo IX. Un algoritmo es una serie de pasos organizados que describe el proceso que se debe seguir, para dar solución a un problema especifico. Tipos de Algoritmos: Ø Cualitativos: Son aquellos en los que se describen los pasos utilizando palabras. Ø Cuantitativos: Son aquellos en los que se utilizan cálculos numéricos para definir los pasos del proceso. Características de los Algoritmos a.- Un algoritmo debe ser finito. Esta característica nos dice que si aplicamos o seguimos un algoritmo, éste debe terminar en algún momento, es decir, tiene un numero finito de pasos. b.- Un algoritmo debe estar definido. Esta característica nos dice que si seguimos un algoritmo una vez debemos llegar a una solución y si lo seguimos otra vez, debemos llegar a la misma solución. c.- Un algoritmo debe ser preciso. Esto es , se debe indicar el orden de ejecución de cada paso. 3.1.1.- FORMAS DE REPRESENTAR LOS ALGORITMOS. Existen Diferentes formas de representar los algoritmos, ya sea en forma grafica o utilizando una forma narrativa; entre estas tenemos: Ø Gráficos: Es la representación gráfica de las operaciones que realiza un algoritmo (diagrama de flujo). Ø No Gráficos: Representa en forma descriptiva las operaciones que debe realizar un algoritmo. (Pseudo código).

Diagramas de Flujo.

Pseudo Códigos

Diagramas de Nassi – Shneiderman.

Diagramas de Warnier – Or

Diagramas de Flujo: Los diagramas de flujo que se realizan para resolver un problema especifico deben ser claros y concisos. Por lo general estos diagramas deben ser independientes del lenguaje de programación que se vaya a utilizar para codificar el algoritmo. También se recomienda que no sea muy complejos y que sean entendibles por otras personas relacionadas con el area de la programación. Se han diseñado un conjunto de símbolos y signos estándar por el Instituto de Normalización Americano (ANSI) que prácticamente ha sido adoptado internacionalmente. Podemos considerar dos diagramasde flujo:

Realizado por: Ing. Jorge Eloy Toledo Coronel

3

Diagrama de Flujo de Sistema: En este tipo de diagrama se describe el flujo de información entre los diferentes periféricos y el CPU que conforman un sistema de computo, no referido como una Pc; sino como un sistema completo que incluya, por ejemplo Lectoras de Cintas Magnéticas, Lectora de Documentos Ópticos, Lectora de discos magnéticos, Impresoras, Graficadores, etc. Los símbolos utilizados en este tipo de diagramas son diferentes a los usados en el diagrama de flujo de detalle, no los describiremos aquí ya que no es el alcance de este curso; para mayor información se recomienda ver cualquier bibliografía al respecto. Diagrama de flujo de Detalle: En este curso centraremos nuestra atención en este tipo de diagramas, ya que con este representaremos en forma grafica el algoritmo que desarrollaremos para resolver un problema especifico. Por lo tanto podemos decir que “ un diagrama de flujo es la representación grafica de un algoritmo en el que se utilizan símbolos especiales que indican las operaciones especificas que deberá realizar la computadora para llegar a la solución de cierto problema ” Los principales símbolos de un diagrama de flujo que utilizaremos, se muestran a continuación: Ovalo: Se utiliza para indicar el inicio o el final del Diagrama de Flujo.

Paralelogramo o tarjeta perforada: Indica la entrada de datos o Información a la Computadora

Rectángulo: Indica el proceso o Procesamiento de Información.

Circulo Pequeño: Sirve como conector entre partes de un diagrama de flujo, pero en la Misma pagina.

Flechas: Indican la dirección del flujo o sentido de ejecución de las Operaciones. Hoja para Impresora: Indica únicamente la salida de la Información. Hexágono: Indica un Proceso Iterativo. Rombo: se utiliza para la toma de decisiones y cada una de los vértices puede contener un si o un no

Realizado por: Ing. Jorge Eloy Toledo Coronel

4

Pseudo Códigos: Es otra de las maneras para representar algoritmos usando la forma narrada o descriptiva para cada uno de los pasos del algoritmo. La palabra Pseudocodigo significa falso código porque realmente no es un código, o sea no son instrucciones escritas en un lenguaje de programación, sino que es una forma sencilla de describir la solución de un problema utilizando el lenguaje natural; el español o el ingles de tal forma que su trascripción a un lenguaje de programación de alto nivel sea lo mas sencillo para quien esta aprendiendo a programar. El Pseudocodigo utiliza palabras reservadas tales como leer(Read), escribir(Write), imprimir(print), si – entonces – si no(if then else) , repite mientras(while - do), repite – hasta(repeat - until), etc. Un ejemplo de Pseudocodigo para calcular el area de un triangulo. INICIO Leer el valor de la base Leer el valor de la altura Calcular el area que es igual a la base por la altura dividida entre dos Imprimir el area FIN

Diagramas de Nassi – Shneiderman.: Otra forma grafica de representar un algoritmo es el Diagrama de Nassi – Shneiderman o Diagrama de N/S, es como un Diagrama de flujo pero con las flechas omitidas y las cojas y bloques continuos. Las acciones sucesivas se escriben en cajas sucesivas, como en el diagrama de flujo, acciones diferentes pueden escribirse en una sola caja. El sistema de representación permite tener una visión mucho mas estructurada de los algoritmos y por consiguiente mayor facilidad al introducirlos al lenguaje de computadora. El diagrama se lee de arriba hacia abajo. Cada bloque ejecuta una acción especifica que se puede documentar o describir con la precisión que sedesee.

Ejemplo: Diagrama de flujo del ejemplo anteriormente visto.

INICIO LEER EL VALOR DE LA BASE

LEER EL VALOR DE LA ALTURA

CALCULAR EL AREA = (BASE * ALTURA)/2

IMPRIMIR EL AREA FIN

Diagramas de Warnier – Or: Es la forma de representar un algoritmo, utilizando llaves abiertas en la cual sus extremos tendrá cualquiera de las dos opciones si o no.

Realizado por: Ing. Jorge Eloy Toledo Coronel

5

Ejemplo: Elaborar el algoritmo que al proporcionar 2 números diferentes, nos imprima el mayor de ellos Inicio si Imprimir el mayor es n1 Leer n1, n2 Si n1>n2 entonces

no imprimir el mayor es n2 fin 3.1.2.- Implementación de algoritmos secuenciales. Ejemplo 1.- Se desea calcular e imprimir la suma de dos números positivos, diseñar el algoritmo y programa en c++ Pseudocodigo Diagrama de Flujo Inicio Leer el valor de A y de B Calcular el valor de C = A + B Imprimir el valor de la suma C Fin Programa en C++ ·#include <iostream.h> #include <stdio.h> #include <conio.h> #include <math.h> float a,b,c; void main() { //* Inicio del programa*// clrscr(); cout<<”Valor de a=”; cin>>a;//* variables de entrada*// cout<<”Valor de a=”; cin>>b; c= a +b; cout<<”El valor de la suma = “<<c<<” \n”; getch(); }

Realizado por: Ing. Jorge Eloy Toledo Coronel

6

Ejemplo 2.- Se desea realizar un sistema para elcanje de dolares americanos a pesos mexicanos diseñar el algoritmo y el programa en C++ al proporcionar como dato de entrada la cantidad de dolares, sabiendo que un dólar americano = $ 10.11 Pseudocodigo Diagrama de Flujo Inicio Hacer dl=10.00 Leer cd Hacer pm= cd * dl Imprimir cd Fin Programa en C++ ·#include <iostream.h> #include <stdio.h> #include <conio.h> #include <math.h> #define dl 10.11 void main() { float cd,pm; clrscr(); cout<<”Cantidad de dolares = “; cin>>cd; pm= cd * dl; cout<<”En pesos Mexicanos = “<<pm<<”\n”; getch(); } 3.2.- Diseño algorítmico de funciones Nosotros podemos realizar cualquier algoritmo y representarlo en cualquiera de las formas anteriormente dichas pero a si vez dividiéndolos en módulos, funciones, procedimientos, subalgoritmos etc. Por ejemplo Se tienen dos valores enteros, positivos mayores que cero de los cuales debemos saber quien de los dos es el mayor en caso contrario que nos imprima que son numero iguales Normalmente así quedaría el Pseudodigo Inicio Leer a1,a2 Si a1>0 y a2>0 entonces Si a1 > a2 entonces Imprimir el mayor es a1 Si no Si a1<a2 entonces Imprimir el mayor es a2 Si no Imprimir los numeros son iguales Fin si Fin si Fin si Fin

Realizado por: Ing. Jorge Eloy Toledo Coronel

7

Programa en C++ ·#include <iostream.h> #include <stdio.h> #include <conio.h> #include <math.h> Int a1,a2; void main() {clrscr(); cout<<”A1 = “; cin>>a1;

cout<<”A2 = “; cin>>a2; If ((a1 > 0) && (a2>0)) { If (a1>a2) {

cout<<”El numero mayor es a1 \n”; getch(); } else If (a2>a1) {

cout<<”El numero mayor es a2 \n”; getch(); } else {

cout<<”Los numeros son iguales \n”; getch(); } }

} Ahora lo resolveremos por módulos

pseudodigos Función leer Función Imprimir Inicio Inicio Leer a1,a2 si a1>0 y a2>0 entonces Fin si a1>o entonces Imprimir el mayor es a1 Si no Si a1<a2 entonces Imprimir el mayor es a2 Si no Imprimir los numeros son iguales Fin si Fin si Fin si

Fin

Realizado por: Ing. Jorge Eloy Toledo Coronel

8

Diagramas de flujo Función leer Función Imprimir Programa en C++ ·#include <iostream.h> #include <stdio.h> #include <conio.h> #include <math.h> Int a1,a2; Void leer() Void imprimir() void main() { Leer(); Imprimir(); } Void leer() {clrscr(); cout<<”A1 = “; cin>>a1; cout<<”A2 = “; cin>>a2; } Void imprimir() { Clrscr();

If ((a1 > 0) && (a2>0)) { If (a1>a2) { cout<<”El numero mayor es a1 \n”; getch(); } else If (a2>a1) { cout<<”El numero mayor es a2 \n”; getch(); } else { cout<<”Los numeros son iguales \n”; getch(); } }

}

Realizado por: Ing. Jorge Eloy Toledo Coronel

1

Unidad 4

Introducción a la Programación

4.1.- Clasificación del software

4.2.- Conceptos de la programación

4.3.- Datos

4.4.-Operadores, operandos y expresiones

4.5.- Prioridad de operadores, evaluación de expresiones

4.6.- estructura básica de un programa

4.7.- proceso de creación de un ejecutable

Realizado por: Ing. Jorge Eloy Toledo Coronel

2

4.1.- Clasificación del software

Software, programas de computadoras. Son las instrucciones responsables de que el hardware (la máquina) realice su tarea. Como concepto general, el software puede dividirse en varias categorías basadas en el tipo de trabajo realizado. Las dos categorías primarias de software son los sistemas operativos (software del sistema), que controlan los trabajos del ordenador o computadora, y el software de aplicación, que dirige las distintas tareas para las que se utilizan las computadoras. Por lo tanto, el software del sistema procesa tareas tan esenciales, aunque a menudo invisibles, como el mantenimiento de los archivos del disco y la administración de la pantalla, mientras que el software de aplicación lleva a cabo tareas de tratamiento de textos, gestión de bases de datos y similares. Constituyen dos categorías separadas el software de red, que permite comunicarse a grupos de usuarios, y el software de lenguaje utilizado para escribir programas

- Sistema operativo

Sistema operativo, software básico que controla una computadora. El sistema operativo tiene tres grandes funciones: coordina y manipula el hardware del ordenador o computadora, como la memoria, las impresoras, las unidades de disco, el teclado o el Mouse; organiza los archivos en diversos dispositivos de almacenamiento, como discos flexibles, discos duros, discos compactos o cintas magnéticas, y gestiona los errores de hardware y la pérdida de datos. Los sistemas operativos controlan diferentes procesos de la computadora. Un proceso importante es la interpretación de los comandos que permiten al usuario comunicarse con el ordenador. Algunos intérpretes de instrucciones están basados en texto y exigen que las instrucciones sean tecleadas. Otros están basados en gráficos, y permiten al usuario comunicarse señalando y haciendo clic en un icono. Por lo general, los intérpretes basados en gráficos son más sencillos de utilizar.

Los sistemas operativos pueden ser de tarea única o multitarea. Los sistemas operativos de tarea única, más primitivos, sólo pueden manejar un proceso en cada momento. Por ejemplo, cuando la computadora está imprimiendo un documento, no puede iniciar otro proceso ni responder a nuevas instrucciones hasta que se termine la impresión.

Todos los sistemas operativos modernos son multitarea y pueden ejecutar varios procesos simultáneamente. En la mayoría de los ordenadores sólo hay una UCP; un sistema operativo multitarea crea la ilusión de que varios procesos se ejecutan simultáneamente en la UCP. El mecanismo que se emplea más a menudo para lograr esta ilusión es la multitarea por segmentación de tiempos, en la que cada proceso se ejecuta individualmente durante un periodo de tiempo determinado. Si el proceso no finaliza en el tiempo asignado, se suspende y se ejecuta otro proceso. Este intercambio de procesos se denomina conmutación de contexto. El sistema operativo se encarga de controlar el estado de los procesos suspendidos. También cuenta con un mecanismo llamado planificador que determina el siguiente proceso que debe ejecutarse. El planificador ejecuta los procesos basándose en su prioridad para minimizar el retraso percibido por el usuario. Los procesos parecen efectuarse simultáneamente por la alta velocidad del cambio de contexto.

- Software de Aplicación, programa informático diseñado para facilitar al usuario la realización de un determinado tipo de trabajo. Posee ciertas características que le diferencia de un sistema operativo (que hace funcionar al ordenador), de una utilidad (que realiza tareas de mantenimiento o de uso general) y de un lenguaje (con el cual se crean los programas informáticos). Suele resultar una solución informática para la automatización de ciertas tareas complicadas como puede ser la contabilidad o la gestión de un almacén. Ciertas aplicaciones desarrolladas 'a medida' suelen ofrecer una gran potencia ya que están exclusivamente diseñadas para resolver un problema específico. Otros, llamados paquetes integrados de software, ofrecen menos potencia pero a cambio incluyen varias aplicaciones, como un programa procesador de textos, de hoja de cálculo y de base de datos.

-

Realizado por: Ing. Jorge Eloy Toledo Coronel

3

- Lenguaje de programación del software

Lenguaje de programación, en informática, cualquier lenguaje artificial que puede utilizarse para definir una secuencia de instrucciones para su procesamiento por un ordenador o computadora. Es complicado definir qué es y qué no es un lenguaje de programación. Se asume generalmente que la traducción de las instrucciones a un código que comprende la computadora debe ser completamente sistemática. Normalmente es la computadora la que realiza la traducción.

Vistos a muy bajo nivel, los microprocesadores procesan exclusivamente señales electrónicas binarias. Dar una instrucción a un microprocesador supone en realidad enviar series de unos y ceros espaciadas en el tiempo de una forma determinada. Esta secuencia de señales se denomina código máquina. El código representa normalmente datos y números e instrucciones para manipularlos. Un modo más fácil de comprender el código máquina es dando a cada instrucción un mnemónico, como por ejemplo STORE, ADD o JUMP. Esta abstracción da como resultado el ensamblador, un lenguaje de muy bajo nivel que es específico de cada microprocesador.

Los lenguajes de bajo nivel permiten crear programas muy rápidos, pero que son a menudo difíciles de aprender. Más importante es el hecho de que los programas escritos en un bajo nivel son prácticamente específicos para cada procesador. Si se quiere ejecutar el programa en otra máquina con otra tecnología, será necesario reescribir el programa desde el principio.

Clasificación del Software

Además de estas categorías basadas en tareas, varios tipos de software se describen basándose en su método de distribución. Entre estos se encuentran los así llamados programas enlatados, el software desarrollado por compañías y vendido principalmente por distribuidores, el freeware y software de dominio público, que se ofrece sin costo alguno, el shareware, que es similar al freeware, pero suele conllevar una pequeña tasa a pagar por los usuarios que lo utilicen profesionalmente y, por último, el infame vapourware, que es software que no llega a presentarse o que aparece mucho después de lo prometido.

4.2.- Conceptos de la Programación

Programa: un conjunto de órdenes para un ordenador. Un programa puede estar formado por apenas unas pocas órdenes (por ejemplo, uno que sume dos números) o por varios miles de órdenes (como un programa de gestión completo para una empresa). Cuando se trata de un programa ya terminado que se compra, se suele hablar de una Aplicación Informática. Los programas se deben escribir en un cierto

Programación: Se llama programación al acto de crear un programa de computadora, un conjunto concreto de instrucciones que una computadora puede ejecutar. El programa se escribe en un lenguaje de programación, aunque también se pueda escribir directamente en lenguaje de máquina, con cierta dificultad. Un programa se puede dividir en diversas partes, que pueden estar escritas en lenguajes distintos

Programación: Programar es automatizar y definir una serie de procesos para resolver un problema y obtener un resultado final. Un programa es el conjunto de instrucciones que se le dan al ordenador para resolver un problema o tarea determinada. Consiste en proporcionar a un equipo un conjunto de instrucciones (o sentencias) que deben ser ejecutadas en orden, y que proporcionan una salida. Preparación de los datos previos indispensables para obtener la solución de un problema mediante las instrucciones codificadas de un ordenador. Lenguaje de Programación Se utilizan para indicar al ordenador las acciones que ha de realizar para resolver un determinado problema. Básicamente los lenguajes de programación se componen de ordenes (en adelante llamadas instrucciones) que es lo que en si mismo le dice al ordenador lo que tiene que hacer. Un conjunto de esas instrucciones forman el programa.

Realizado por: Ing. Jorge Eloy Toledo Coronel

4

Lenguajes de alto nivel

Por lo general se piensa que los ordenadores son máquinas que realizan tareas de cálculos o procesamiento de textos. La descripción anterior es sólo una forma muy esquemática de ver una computadora. Hay un alto nivel de abstracción entre lo que se pide a la computadora y lo que realmente comprende. Existe también una relación compleja entre los lenguajes de alto nivel y el código máquina.

Los lenguajes de alto nivel son normalmente fáciles de aprender porque están formados por elementos de lenguajes naturales, como el inglés. En BASIC, el lenguaje de alto nivel más conocido, los comandos como "IF CONTADOR = 10 THEN STOP" pueden utilizarse para pedir a la computadora que pare si CONTADOR es igual a 10. Por desgracia para muchas personas esta forma de trabajar es un poco frustrante, dado que a pesar de que las computadoras parecen comprender un lenguaje natural, lo hacen en realidad de una forma rígida y sistemática.

Lenguaje de programación. Los lenguajes de programación que se acercan más al lenguaje humano que al del ordenador reciben el nombre de "lenguajes de alto nivel" (como Pascal); los que se acercan más al ordenador son los de "bajo nivel" (como el ensamblador). Lo más habitual es crear los programas en un lenguaje de alto nivel (llamado "fuente") y después convertirlos al lenguaje propio del ordenador ("compilarlos" para obtener un "ejecutable"). Se llama programación al acto de crear un programa de computadora, un conjunto concreto de instrucciones que una computadora puede ejecutar. El programa se escribe en un lenguaje de programación, aunque también se pueda escribir directamente en lenguaje de máquina, con cierta dificultad. Un programa se puede dividir en diversas partes, que pueden estar escritas en lenguajes distintos.

Intérpretes y compiladores

La traducción de una serie de instrucciones en lenguaje ensamblador (el código fuente) a un código máquina (o código objeto) no es un proceso muy complicado y se realiza normalmente por un programa especial llamado compilador. La traducción de un código fuente de alto nivel a un código máquina también se realiza con un compilador, en este caso más complejo, o mediante un intérprete. Un compilador crea una lista de instrucciones de código máquina, el código objeto, basándose en un código fuente. El código objeto resultante es un programa rápido y listo para funcionar, pero que puede hacer que falle el ordenador si no está bien diseñado. Los intérpretes, por otro lado, son más lentos que los compiladores ya que no producen un código objeto, sino que recorren el código fuente una línea cada vez. Cada línea se traduce a código máquina y se ejecuta. Cuando la línea se lee por segunda vez, como en el caso de los programas en que se reutilizan partes del código, debe compilarse de nuevo. Aunque este proceso es más lento, es menos susceptible de provocar fallos en la computadora.

En conclusión un compilador es aquel que traduce todas las instrucciones, las almacena en un lenguaje llamado maquina para posteriormente verificar si esta bien o esta mal, al programa realizado en lenguaje de alto nivel se le llama programa fuente y al resultado de traducción se le llama programa objeto.

Ejemplo:

Solución. Cpp ---à programa fuente

Solución .bak ---à programa de respaldo de la maquina

Solucion.exe---à programa objeto

Realizado por: Ing. Jorge Eloy Toledo Coronel

5

4.3.- Datos.

Definición de Dato:

Un dato es la unidad o cantidad mínima de información no elaborada, sin sentido en sí misma, pero que convenientemente tratada se puede utilizar en la realización de cálculos o toma de decisiones. Es de empleo muy común en el ámbito informático.

4.3.2.- Tipos De Datos Todos los datos tienen un tipo asociado con ellos. Un dato puede ser un simple carácter, tal como ‘b’, un valor entero tal como 35. El tipo de dato determina la naturaleza del conjunto de valores que puede tomar una variable. Numéricos Simples Lógicos Alfanuméricos (string) Tipos de datos Arreglos (Vectores, Matrices) Estructurados Registros (Def. por el Archivos usuario) Apuntadores

Tipos de Datos Simples Ø Datos Numéricos: Permiten representar valores escalares de forma numérica, esto incluye a los números enteros y los reales. Este tipo de datos permiten realizar operaciones aritméticas comunes. Ø Datos Lógicos: Son aquellos que solo pueden tener dos valores (cierto o falso) ya que representan el resultado de una comparación entre otros datos (numéricos o alfanuméricos). Ø Datos Alfanuméricos (String): Es una secuencia de caracteres alfanuméricos que permiten representar valores identificables de forma descriptiva, esto incluye nombres de personas, direcciones, etc. Es posible representar números como alfanuméricos, pero estos pierden su propiedad matemática, es decir no es posible hacer operaciones con ellos. Este tipo de datos se representan encerrados entre comillas. Ejemplo: “Instituto Tecnológico del Istmo” “1997” 4.3.3.- Identificadores

Los identificadores representan los datos de un programa (constantes, variables, tipos de datos). Un identificador es una secuencia de caracteres que sirve para identificar una posición en la memoria de la computadora, que nos permite accesar a su contenido.

Realizado por: Ing. Jorge Eloy Toledo Coronel

6

Ejemplo: Nombre Num_hrs Calif2 Reglas para formar un Identificador Debe comenzar con una letra (A a Z, mayúsculas o minúsculas) y no deben contener espacios en blanco. Letras, dígitos y caracteres como la subraya ( _ ) están permitidos después del primer carácter. La longitud de identificadores puede ser de hasta 8 caracteres. Constantes y Variables Ø Constante: Una constante es un dato numérico o alfanumérico que no cambia durante la

ejecución del programa. Ejemplo: pi = 3.1416 Ø Variable: Es un espacio en la memoria de la computadora que permite almacenar

temporalmente un dato durante la ejecución de un proceso, su contenido puede cambia durante la ejecución del programa. Para poder reconocer una variable en la memoria de la computadora, es necesario darle un nombre con el cual podamos identificarla dentro de un algoritmo.

Ejemplo: área = pi * radio ^ 2 Las variables son : el radio, el área y la constate es pi

Clasificación de las Variables

Numéricas Por su Contenido Lógicas Alfanuméricas (String) Variables De Trabajo Por su Uso Contadores Acumuladores Por su Contenido Ø Variable Numéricas: Son aquellas en las cuales se almacenan valores numéricos, positivos o negativos, es decir almacenan números del 0 al 9, signos (+ y -) y el punto decimal. Ejemplo: iva=0.15 pi=3.1416 costo=2500 Ø Variables Lógicas: Son aquellas que solo pueden tener dos valores (cierto o falso) estos representan el resultado de una comparación entre otros datos. Ø Variables Alfanuméricas: Esta formada por caracteres alfanuméricos (letras, números y caracteres especiales). Ejemplo: letra=’a’apellido=’lopez’ direccion=’Av. Libertad #190’ Por su Uso

Realizado por: Ing. Jorge Eloy Toledo Coronel

7

Ø Variables de Trabajo: Variables que reciben el resultado de una operación matemática completa y que se usan normalmente dentro de un programa. Ejemplo: suma=a+b/c Ø Contadores: Se utilizan para llevar el control del numero de ocasiones en que se realiza una operación o se cumple una condición. Con los incrementos generalmente de uno en uno. Acumuladores: Forma que toma una variable y que sirve para llevar la suma acumulativa de una serie de valores que se van leyendo o calculando progresivamente 4.3.4.- Almacenamiento, direccionamiento y representación en memoria 4.3.5.- Sistema de numeración binaria y hexadecimal 4.4.- Operadores u operandos. Ø Operadores: Son elementos que relacionan de forma diferente, los valores de una o mas variables y/o constantes. Es decir, los operadores nos permiten manipular valores. Aritméticos Tipos de Operadores Relaciónales Lógicos Ø Operadores Aritméticos: Los operadores aritméticos permiten la realización de operaciones matemáticas con los valores (variables y constantes). Los operadores aritméticos pueden ser utilizados con tipos de datos enteros o reales. Si ambos son enteros, el resultado es entero; si alguno de ellos es real, el resultado es real. Operando (Operador) Operando Valor (constante o variable) Operadores Aritméticos + Suma - Resta * Multiplicación / División Mod Modulo (residuo de la división entera) Ejemplos: Expresión Resultado 7 / 2 3.5 12 mod 7 5 4 + 2 * 5 14 4.5.- Prioridad de los Operadores, Evaluacion de Expresiones. Todas las expresiones entre paréntesis se evalúan primero. Las expresiones con paréntesis anidados se evalúan de dentro a fuera, el paréntesis mas interno se evalúa primero. Dentro de una misma expresión los operadores se evalúan en el siguiente orden.

Realizado por: Ing. Jorge Eloy Toledo Coronel

8

1.- ^ Exponenciación 2.- *, /, mod Multiplicación, división, modulo. 3.- +, - Suma y resta. Los operadores en una misma expresión con igual nivel de prioridad se evalúan de izquierda a derecha. Ejemplos: 4 + 2 * 5 = 14 23 * 2 / 5 = 9.2 46 / 5 = 9.2 3 + 5 * (10 - (2 + 4)) = 23 3 + 5 * (10 - 6) = 3 + 5 * 4 = 3 + 20 = 23 3.5 + 5.09 - 14.0 / 40 = 5.09 3.5 + 5.09 - 3.5 = 8.59 - 3.5 = 5.09 2.1 * (1.5 + 3.0 * 4.1) = 28.98 2.1 * (1.5 + 12.3) = 2.1 * 13.8 = 28.98 Ø Operadores Relaciónales: Se utilizan para establecer una relación entre dos valores. Compara estos valores entre si y esta comparación produce un resultado de certeza o falsedad (verdadero o falso). Los operadores relaciónales comparan valores del mismo tipo (numéricos o cadenas) Tienen el mismo nivel de prioridad en su evaluación. Los operadores relaciónales tiene menor prioridad que los aritméticos. Operadores Relaciónales > Mayor que < Menor que > = Mayor o igual que < = Menor o igual que < > Diferente = Igual Ejemplos: Si a = 10 b = 20 c = 30 a + b > c Falso a - b < c Verdadero a - b = c Falso a * b < > c Verdadero Ejemplos no lógicos: a < b < c 10 < 20 < 30 T < 30 (no es lógico porque tiene diferentes operandos) Ø Operadores Lógicos: Estos operadores se utilizan para establecer relaciones entre valores lógicos. Estos valores pueden ser resultado de una expresión relacional. Operadores Lógicos And Y Or O Not Negación ó no

Realizado por: Ing. Jorge Eloy Toledo Coronel

9

Operador And (Y):En esta tabla se observa que su resultado será verdadero si ambos operandos o expresiones son verdaderos; en cualquier otros caso será falso.

P Q P AND Q

0 0 0

0 1 0

1 0 0

1 1 1

Operador Or: En esta operación el resultado siempre será falso si ambos operandos son falsos en los demas casos será verdadero.

P Q P OR Q 0 0 0 0 1 1 1 0 1 1 1 1

Estas tablas de verdad son únicamente para dos operandos o condiciones. Pero se pueden obtener tablas para mas de dos condiciones aplicando las reglas básicas de las tablas anteriores. Por ejemplo: Operador Not: Este operador niega el valor de las condiciones de manera que si el valor de P es verdadero NOT P es falso y si P es falso NOT P es verdadero.

P Q NOT P

0 0 1

0 1 1

1 0 0

1 1 0

Ejemplos: (a < b) and (b < c) (10<20) and (20<30) T and T T Prioridad de los Operadores Lógicos Not And Or Prioridad de los Operadores en General 1.- ( ) 2.- ̂

Realizado por: Ing. Jorge Eloy Toledo Coronel

10

3.- *, /, Mod, Not 4.- +, -, And 5.- >, <, > =, < =, < >, =, Or Ejemplos: a = 10 b = 12 c = 13 d =10 1) ((a > b)or(a < c)) and ((a = c) or (a > = b)) F T F F T and F F 2) ((a > = b) or (a < d)) and (( a > = d) and (c > d)) F F T T F T F 3) not (a = c) and (c > b) F T T T 4.6.- Estructura Básica de un Programa

En C++ un programa esta constituido por funciones, cada ella realiza una labor determinada, gestionando una serie de datos mediante variables, ya hemos visto que estas variables pueden ser globales al programa, al archivo, o locales a las funciones. También hemos visto que al ejecutarse el programa la primera función que se ejecuta es main, por lo que todos los programas deben tener como mínimo esta función, y desde ella se llamarán a todas las demás. Este modelo de programación se denomina estructurada, porque el programa sigue una serie de pasos secuenciales, en los que se van llamando a diversas funciones para realizar las tareas que nos interesan, posteriormente, veremos otro tipo de programación, denominada "programación orientada a objetos", que se desvía un poco de la estructurada, pero eso será más adelante.

Como vimos, un programa podía estar formado por varios archivos fuente (archivos cpp), y que el compilador los enlazaba unos con otros, siendo nuestra labor indicarle que variables y funciones eran globales, locales, etc. Según esto, una práctica inteligente sería que en un archivo tuviéramos la función main, y que todas las demás funciones que se utilizaran en el programa las colocáramos en archivos diferentes agrupadas por realizar tareas semejantes. Con esto conseguimos que esas mismas funciones se puedan utilizar en otros programas sin más que incluir esos mismos archivos cpp. (este tipo de programación, aunque sigue siendo estructurada, sigue, sin embargo, la filosofía de la programación orientada a objetos).

Pero desde luego que la mejor manera de entender esto es realizando un pequeño programa que calcula la integral definida de x^2

/*** func.cpp ***/ /*archivo en el que declaramos y definimos las funciones que utilizará el programa*/

//declaración de funciones float f(float);

Realizado por: Ing. Jorge Eloy Toledo Coronel

11

float min(float,float); float max(float,float); //definición de funciones float f(float x) { return x*x; } float min (float a, float b) { float aux=10000000; float x; for (x=a;x<=b;x+=(b-a)/50) if (f(x)<aux) aux=f(x); return aux; } float max (float a, float b) { float aux=0; for (float x=a;x<=b;x+=(b-a)/50) if (f(x)>aux) aux=f(x); return aux; }

#include <iostream.h> /** Archivo en el que se encontrará la función main.**/ //incluyo la declaración de las funciones min y max como externas y globales al programa extern float min(float,float); extern float max(float,float); //función ppal del programa void main (void) { cout<<"Vamos a integrar la función x^2 \n"; cout<<"Introduce el intervalo que quieras integrar \n"; float i,f,sumainf=0,sumasup=0; cin>>i>>f; for(float x=i;x<f;x+=(f-i)/10000) { sumainf=min(x,x+(f-i)/10000)*(f-i)/10000+sumainf; sumasup=max(x,x+(f-i)/10000)*(f-i)/10000+sumasup; } cout<<"La integral vale "<<(sumasup+sumainf)/2; }

UTILIZACIÓN DE ARCHIVOS CABECERA

Otra manera de aprovechar la compilación separada sería la utilización de archivos cabecera (extensión .h) que sería un paso adelante y facilitando y haciendo más cómoda la programación.

Lo que haríamos sería lo siguiente, introducir las declaraciones de las funciones en un archivo cabecera que luego incluiríamos (#include "miarchivo.h") en los archivos dónde se

Realizado por: Ing. Jorge Eloy Toledo Coronel

12

definieran dichas funciones y en los archivos en los que están se utilizaran, evitando de esta manera tener que repetir la declaración de las funciones cada vez que quisiéramos utilizarlas en un archivo, de esta manera nuestro programa anterior quedaría como sigue...

//declaración de funciones float f(float); float min(float,float); float max(float,float);

//Incluimos el archivo de declaración de las funciones #include "func.h"

//definición de funciones float f(float x) { return x*x; } float min (float a, float b) { float aux=10000000; float x; for (x=a;x<=b;x+=(b-a)/50) if (f(x)<aux) aux=f(x); return aux; } float max (float a, float b) { float aux=0; for (float x=a;x<=b;x+=(b-a)/50) if (f(x)>aux) aux=f(x); return aux; }

#include <iostream.h> /** Archivo en el que se encontrará la función main.**/ //incluyo la declaración de las funciones min y max como externas y globales al programa #include "func.h" //función ppal del programa void main (void) { cout<<"Vamos a integrar la función x^2 \n"; cout<<"Introduce el intervalo que quieras integrar \n"; float i,f,sumainf=0,sumasup=0; cin>>i>>f; for(float x=i;x<f;x+=(f-i)/10000) { sumainf=min(x,x+(f-i)/10000)*(f-i)/10000+sumainf; sumasup=max(x,x+(f-i)/10000)*(f-i)/10000+sumasup; } cout<<"La integral vale "<<(sumasup+sumainf)/2;

Realizado por: Ing. Jorge Eloy Toledo Coronel

13

} 4.7.- Proceso de creación de un ejecutable.

El modelo de compilación de C ++

En la siguiente figura se muestran las distintas etapas que cubre el compilador para obtener el código ejecutable.

Modelo de compilación de C.

El preprocesador

El preprocesador acepta el código fuente como entrada y es responsable de:

• quitar los comentarios • interpretar las directivas del preprocesador las cuales inician con #.

Por ejemplo:

• #include -- incluye el contenido del archivo nombrado. Estos son usualmente llamados archivos de cabecera (header). Por ejemplo:

o #include <math.h> -- Archivo de la biblioteca estándar de matemáticas. o #include <stdio.h> -- Archivo de la biblioteca estándar de Entrada/Salida.

• #define -- define un nombre simbólico o constante. Sustitución de macros. o #define TAM_MAX_ARREGLO 100

Realizado por: Ing. Jorge Eloy Toledo Coronel

14

Compilador de C

El compilador de C traduce el código fuente en código de ensamblador. El código fuente es recibido del preprocesador.

Ensamblador

El ensamblador crea el código fuentei o los archivos objeto. En los sistemas con UNIX se podrán ver los archivos con el sufijo .o.

Ligador

Si algún archivo fuente hace referencia a funciones de una biblioteca o de funciones que están definidas en otros archivos fuentes, el ligador combina estas funciones (con main()) para crear un archivo ejecutable. Las referencias a variables externas en esta etapa son resueltas.

Realizado por: Ing. Jorge Eloy Toledo Coronel

1

Unidad 5

Implementación de la Clase

5.1.- Modificadores de acceso (public, private)

5.2.- Encapsulamiento de la clase

5.3.- El método como elemento de la comunicación

Realizado por: Ing. Jorge Eloy Toledo Coronel

2

5.1.- Modificadores de acceso

Ya hemos visto el significado de los modificadores de acceso public y private, así como el control de acceso por defecto a nivel de paquete, cuando no se especifica nada. En la herencia, surge un nuevo control de acceso denominado protected.

Hemos puesto protected delante de los miebros dato x e y de la clase base Ventana

public class Ventana { protected int x; protected int y; //... }

En la clase derivada la función miembro desplazar accede a dichos miembros dato

public class VentanaTitulo extends Ventana{ //... public void desplazar(int dx, int dy){ x+=dx; y+=dy; } }

Si cambiamos el modificador de acceso de los miembros x e y de la clase base Ventana de protected a private , veremos que el compilador se queja diciendo que los miembro x e y no son accesibles.

Los miembros ancho y alto se pueden poner con acceso private sin embargo, es mejor dejarlos como protected ya que podrían ser utilizados por alguna función miembro de otra clase derivada de VentanaTitulo. Dentro de una jerarquía pondremos un miembro con acceso private, si estamos seguros de que dicho miembro solamente va a ser usado por dicha clase.

Como vemos hay cuatro modificadores de acceso a los miembros dato y a los métodos: private, protected, public y default (por defecto, o en ausencia de cualquier modificador). La herencia complica aún más el problema de acceso, ya que las clases dentro del mismo paquete tienen diferentes accesos que las clases de distinto paquete

Los siguientes cuadros tratan de aclarar este problema

Clases dentro del mismo paquete Modificador de acceso

Heredado Accesible

Por defecto (sin modificador)

Si Si

private No No

protected Si Si

public Si Si

Realizado por: Ing. Jorge Eloy Toledo Coronel

3

Clases en distintos paquetes

Modificador de acceso

Heredado Accesible

Por defecto (sin modificador)

No No

private No No

protected Si No

public Si Si

Desde el punto de vista práctico, cabe reseñar que no se heredan los miembros privados, ni aquellos miembros (dato o función) cuyo nombre sea el mismo en la clase base y en la clase derivada.

La clase base Object

La clase Object es la clase raíz de la cual derivan todas las clases. Esta derivación es implícita.

La clase Object define una serie de funciones miembro que heredan todas las clases. Las más importantes son las siguientes

public class Object { public boolean equals(Object obj) { return (this == obj); } protected native Object clone() throws CloneNotSupportedException; public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } protected void finalize() throws Throwable { } //otras funciones miembro... }

Igualdad de dos objetos:

Hemos visto que el método equals de la clase String cuando compara un string y cualquier otro objeto. El método equals de la clase Object compara dos objetos uno que llama a la función y otro es el argumento de dicha función.

Representación en forma de texto de un objeto

El método toString imprime por defecto el nombre de la clase a la que pertenece el objeto y su código (hash). Esta función miembro se redefine en la clase derivada para mostrar la información que nos interese acerca del objeto. La clase Fraccion redefine toString para mostrar el numerador y el denominador separados por la barra de dividir. En la misma página, hemos mejorado la clase Lista para mostrar los datos que se guardan en los objetos de dicha clase, redefiniendo toString.

La función toString se llama automáticamente siempre que pongamos un objeto como argumento de la función System.out.println o concatenado con otro string.

Realizado por: Ing. Jorge Eloy Toledo Coronel

4

Duplicación de objetos

El método clone crea un objeto duplicado (clónico) de otro objeto. Más adelante estudiremos en detalle la redefinición de esta función miembro y pondremos ejemplos que nos muestren su utilidad.

Finalización

El método finalize se llama cuando va a ser liberada la memoria que ocupa el objeto por el recolector de basura (garbage collector). Normalmente, no es necesario redefinir este método en las clases, solamente en contados casos especiales. La forma en la que se redefine este método es el siguiente.

class CualquierClase{ //.. protected void finalize() trows Throwable{ super.finalize(); //código que libera recursos externos } }

La primera sentencia que contenga la redefinición de finalize ha de ser una llamada a la función del mismo nombre de la clase base, y a continuación le añadimos cierta funcionalidad, habitualmente, la liberación de recursos, cerrar un archivo, etc.

Este ejemplo :

Ilustra una faceta importante de los lenguajes de Programación Orientada a Objetos denominada encapsulación. El acceso a los miembros de una clase está controlado. Para usar una clase, solamente necesitamos saber que funciones miembro se pueden llamar y a qué datos podemos acceder, no necesitamos saber como está hecha la clase, como son sus detalles internos. Una vez que la clase está depurada y probada, la clase es como una caja negra. Los objetos de dicha clase guardan unos datos, y están caracterizados por una determinada conducta. Este ocultamiento de la información niega a la entidades exteriores el acceso a los miembros privados de un objeto. De este modo, las entidades exteriores acceden a los datos de una manera controlada a través de algunas funciones miembro. Para acceder a un miembro público (dato o función) basta escribir.

objeto_de_la_clase_Fraccion.miembro_público_no_estático clase_Fraccion.miembro_público_estático

Delante de los miembros dato, como podemos ver en el listado hemos puesto las plabras reservadas public y private.

• Miembros públicos

Los miembros públicos son aquellos que tienen delante la palabra public, y se puede acceder a ellos sin ninguna restricción.

• Miembros privados

Los miembros privados son aquellos que tienen delante la palabra private, y se puede acceder a ellos solamente dentro del ámbito de la clase.

Los miembros dato num y den son privados, y también la función que calcula el máximo común divisor mcd, que es una función auxiliar de la función miembro publica simplificar. El usuario solamente precisa saber que dispone de una función pública que le permite simplificar una

Realizado por: Ing. Jorge Eloy Toledo Coronel

5

fracción, pero no necesita saber cuál es el procedimiento empleado para simplificar fracciones. Así declaramos la función mcd como privada y simplificar como pública.

• Por defecto (a nivel de paquete)

5.2.- Encapsulamiento de una clase

Antes de nada, debe quedar claro que el encapsulamiento, igual que cualquier buen hábito de programación (como no poner goto, comentar, etc) es útil para código que más adelante se puede querer reutilizar o modificar, por otras personas o por uno mismo. Si yo hago un programa de marcianos y nunca jamas pienso volver a tocarlo, da igual que lo haga con gotos y sin comentar mientras me entere yo mismo mientras lo estoy haciendo y funcione. Pagaré este "pecado" si dentro de dos meses se me ocurre mejorarlo o quiero reaprovechar algo de su código para otro programa.

Comento esto porque el encapsulamiento, llevado a su extremo, como es el caso del punto final de interfaces, hace la programación un poco más complicada (hay que hacer más clases). Este esfuerzo sólo se ve recompensado si el código es muy grande (evitando recompilados innecesarios) o se va a reutilizar en un futuro (podremos extraer clases con menos dependencias de otras clases). Dicho esto, vamos al tema.

Cualquier curso de orientación a objetos nos dice que es mejor poner los atributos de una clase protegidos o privados (nunca públicos) y acceder a ellos a través de métodos públicos que pongamos en la clase. Veamos el motivo. Supongamos, por ejemplo, que nos piden un programa que permita llevar una lista de gente con sus fechas de nacimiento. Entre otras cosas, decidimos hacernos nuestra clase Fecha con varios métodos maravillosos de la siguiente manera.

class Fecha { public: int anho; // El anho con cuatro cifras, ej. 2004 int mes; // El mes, de 1 a 12 int dia; // El dia, de 1 a 31 void metodoMaravilloso1(); void metodoMaravilloso2(); };

Ya hemos hecho la clase. Ahora hacemos el resto del código y en unos varios miles de líneas de código usamos directamente cosas como esta.

Fecha unaFecha; unaFecha.anho = 2004; unaFecha.mes = 1; unaFecha.dia = 25;

Finalmente acabamos nuestro programa y todo funciona de maravilla. Unos días después nos dicen que el programa va a guardar tropecientas mil personas y que ocupan mucho los ficheros, que a ver si podemos hacer algo para remediarlo. ¡Vaya!, almacenamos una fecha con tres enteros. Si usamos el formato de la mayoría de los ordenadores, en el que la fecha es el número de segundos transcurridos desde el 1 de Enero de 1970 (lo que nos devuelve la función time()), basta con un entero.

Realizado por: Ing. Jorge Eloy Toledo Coronel

6

Total, que manos a la obra, cambiamos nuestra clase para que tenga lo siguiente:

class Fecha { public: /* Comentado por ineficiente int anho; int mes; int dia; */

long numeroSegundos;

void metodoMaravilloso1(); void metodoMaravilloso2(); };

Ya está hecho lo fácil. Ahora sólo hay que ir por las tropecientas mil líneas de código cambiando nuestras asignaciones y lecturas a los tres enteros anteriores por el nuevo long.

Hubiera sido mucho mejor si hubieramos hecho estos tres enteros protegidos y unos métodos para acceder a ellos. Algo como esto

class Fecha { public: void tomaFecha (int anho, int mes, int dia); int dameAnho (); int dameMes (); int dameDia (); void metodoMaravilloso1(); void metodoMaravilloso2(); protected: int anho; // El anho con cuatro cifras, ej. 2004 int mes; // El mes, de 1 a 12 int dia; // El dia, de 1 a 31 };

Si ahora tenemos que hacer el mismo cambio, basta con cambiar los atributos protegidos. Los métodos tomaXXX() y dameXXX() se mantienen en cuanto a parámetros y valor devuelto, pero se modifica su código interno para que conviertan el año, mes y día en un long de segundos y al revés. El resto del código no hay que tocarlo en absoluto.

Es incluso mejor hacer los atributos privados que protegidos. Haciéndolos protegidos, las clases hijas (las que heredan de Fecha) pueden acceder directamente a estos atributos. Cuando hagamos el cambio por un long, debemos cambiar también el código de las clases hijas. Si los atributos son privados y obligamos a las clases hijas a acceder a ellos a través de métodos, tampoco tendremos que cambiar el código de estas clases hijas.

El acceso a través de métodos es menos eficiente que hacerlo directamente, así que aunque siguiendo el principio de ocultación es mejor hacer atributos privados, por eficiencia en algunos casos quizás sea mejor hacerlos protegidos (o incluso públicos) a riesgo de tener que cambiar más líneas de código en caso de cambio.

Realizado por: Ing. Jorge Eloy Toledo Coronel

7

CONSEJO: Siempre que sea posible hacer los atributos de

una clase privados.

Importancia de la encapsulación en C++

Con lo contado hasta ahora evitamos tener que cambiar código en caso de cambiar parámetros.

En el caso concreto de C++ hay un pequeño problema adicional. Es bastante normal hacer que las clases se definan por medio de dos ficheros. En el caso de la clase Fecha tendríamos un Fecha.h con la definición de la clase y un Fecha.cc (o .cpp) con el código de los métodos de la clase. Cuando queremos usar la clase Fecha, solemos hacer nuestro #include <Fecha.h> .

Cualquier proceso de compilado eficiente (como la utilidad make de linux y supongo que el Visual C++) es lo suficientemente listo como para recompilar sólo aquellos ficheros que es necesario recompilar. Es decir, si ya tenemos nuestro proyecto compilado y tocamos un fichero, el compilador sólo compilará ese fichero y todos los que dependen de él. Esta características es muy importante en proyectos grandes (con muchos ficheros y muchas líneas de código), para ahorrar tiempo de compilado cada vez que hacemos una modificación (He trabajado en proyectos que tardaban en compilar desde cero alrededor de 4 horas).

¿Cual es el problema?. El problema es que si decidimos, por ejemplo, cambiar nuevamente el atributo privado de la clase Fecha por otra cosa, necesitamos tocar el fichero Fecha.h. Esto hará que se recompilen todos los ficheros que hagan #include <Fecha.h> y todos los ficheros que hagan #include de algun fichero que a su vez haga #include de Fecha.h y así sucesivamente.

La solución es evidente, colocar lo menos posible en el fichero Fecha.h, en concreto los #define y variables globales que no sea necesario ver desde otras clases.

Por ejemplo, nuestra clase Fecha podía tener unos #define para indicar cual es el número mínimo y máximo de mes. Es mejor colocar estos #define en Fecha.cc en vez de en Fecha.h, salvo que alguien tenga que verlos. // Esto mejor en el .cc que en el .h #define MES_MINIMO 1 #define MES_MAXIMO 12

CONSEJO: Siempre que sea posible, poner los #define,

definición de tipos, constantes globales, etc, dentro del fichero .cc

Realizado por: Ing. Jorge Eloy Toledo Coronel

8

Encapsulamiento a través de interfaces

Nos queda una cosa. ¿Por qué tenemos que recompilar muchas cosas si cambiamos un atributo privado de la clase?. Lo ideal sería poder cambiar las cosas internas de la clase sin que haya que recompilar nada más, a fin de cuentas, el atributo es privado y nadie lo utiliza directamente.

Es bastante habitual en programación orientada a objetos el uso de interfaces para hacer que las clases no dependan entre sí. En el caso de C++ el uso de interfaces es útil además para evitar recompilados innecesarios.

Una interface no es más que una clase en la que se definen los métodos públicos necesarios, pero no se implementan. Luego la clase concreta que queramos hacer hereda de esa interface e implementa sus métodos.

En nuestro caso, podemos hacer una clase InterfaceFecha, con los métodos públicos virtuales puros (sin código). Luego la clase Fecha hereda de InterfaceFecha e implementa esos métodos.

En el fichero InterfaceFecha.h tendríamos

class InterfaceFecha { public: virtual void tomaFecha (int anho, int mes, int dia) = 0; virtual int dameAnho () = 0; virtual int dameMes () = 0; virtual int dameDia () = 0; virtual void metodoMaravilloso1() = 0; virtual void metodoMaravilloso2() = 0; };

De momento, ni siquiera existiría un InterfaceFecha.cc

La clase Fecha sigue igual, pero hereda de InterfaceFecha.

#include <InterfaceFecha.h>

class Fecha : public InterfaceFecha { public: void tomaFecha (int anho, int mes, int dia); int dameAnho (); int dameMes (); int dameDia (); void metodoMaravilloso1(); void metodoMaravilloso2(); protected: int anho; // El anho con cuatro cifras, ej. 2004 int mes; // El mes, de 1 a 12 int dia; // El dia, de 1 a 31 };

Realizado por: Ing. Jorge Eloy Toledo Coronel

9

Ahora, todo el que necesite una Fecha, tiene que tener un puntero a InterfaceFecha en vez de a Fecha. Alguien instanciará Fecha y lo guardará en ese puntero. Es decir, podríamos hacer algo como esto #include <Fecha.h> #include <InterfaceFecha.> ... InterfaceFecha *unaFecha = NULL; ... unaFecha = new Fecha(); unaFecha->tomaFecha (2004, 1, 27); ... delete unaFecha; unaFecha = NULL;

Si nos fijamos un poco, todavía no hemos arreglado nada, salvo complicar el asunto. El que haga este código necesita hacer ahora #include tanto de InterfaceFecha.h como de Fecha.h. Si tocamos algo en Fecha.h, este código se recompilará.

Este código necesita #include <Fecha.h> para poder hacer el new de Fecha. Hay que buscar la forma de evitar ese new. Suele ser también bastante habitual hacer una clase (o utilizar la misma Interface si el lenguaje lo permite, como es el caso de C++) para poner un método estático que haga el new y nos lo devuelva.

En el caso de Java, al poner este método, ya no tendríamos una interface, sino una clase. Hacer que Fecha herede de InterfaceFecha nos limita a no heredar de otra cosa (Java no admite herencia múltiple). Si esto es admisible, podemos hacerlo así. Si necesitamos que Fecha herede de otra clase, en vez de poner el método estático en la interface, debemos hacer una tercera clase aparte GeneradorFecha con este método estático.

En nuestro ejemplo de C++, la clase InterfaceFecha quedaría. class InterfaceFecha { public:

static InterfaceFecha *dameNuevaFecha();

virtual void tomaFecha (int anho, int mes, int dia) = 0; virtual int dameAnho () = 0; virtual int dameMes () = 0; virtual int dameDia () = 0; virtual void metodoMaravilloso1() = 0; virtual void metodoMaravilloso2() = 0; };

Ahora sí necesitamos un InterfaceFecha.cc. Dentro de él tendriamos

#include <InterfaceFecha.h> #include <Fecha.h>

InterfaceFecha *InterfaceFecha::dameNuevaFecha() { return new Fecha(); }

Realizado por: Ing. Jorge Eloy Toledo Coronel

10

El código que antes utilizaba el puntero a InterfaceFecha quedaría ahora

#include <InterfaceFecha.> ... InterfaceFecha *unaFecha = NULL; ... unaFecha = InterfaceFecha::dameNuevaFecha(); unaFecha->tomaFecha (2004, 1, 27); ... delete unaFecha; unaFecha = NULL;

Como vemos, sólo es necesario el #include de InterfaceFecha.h y este no incluye a Fecha.h (lo hace InterfaceFecha.cc, no el .h). Hemos hecho que este código no vea en absoluto a Fecha.h. Ahora podemos tocar sin ningún miramiento el fichero Fecha.h, que este código no necesita ser recompilado.

Una ventaja adicional es que se puede cambiar la clase Fecha por otra clase Fecha2 en tiempo de ejecución. Bastaría con poner un atributo estático en InterfaceFecha para indicar qué clase Fecha queremos y hacer que el método dameNuevaFecha() instancie y devuelve una u otra en función de ese atributo.

CONSEJO: Utilizar interfaces para aquellas clases que

preveamos que pueden cambiar durante el desarrollo del

proyecto o que creamos que podemos cambiar más

adelante por otra.

Este mecanismo de obtener una instancia de una clase a través de un método estático y de una interface, para no depender de la clase concreta, creo que dentro del mundo de los patrones de diseño es el patrón Factoria.

PARAMETROS

Un parámetro en C++ es una variable que puede pasar su valor a un procedimiento desde el principal o desde otro procedimiento.

Existen ocasiones en que es necesario mandar al procedimiento ciertos valores para que los use en algún proceso.

Estos valores que se pasan del cuerpo principal del programa o de un procedimiento a otros procedimientos se llaman parametros.

Entonces la declaración completa de un procedimiento es :

Void Nom_Proc(lista de parametros)

{ cuerpo de instrucciones;};

Realizado por: Ing. Jorge Eloy Toledo Coronel

11

Donde lista de parametros es una o mas variables separadas por coma, como lo muestra el pograma ejemplo.

prog12.cpp

#include <stdio.h>

#include <conio.h>

#include <string.h>

// recordar declarar primero proc y funciones

// y observar como se pasa como parametro una string

void proc1(char nom[], int suma);

void main()

{

clrscr();

//llamando o activando procedimiento

// y pasando dos parametros uno de ellos string

proc1("juan perez", 3 + 4);

} //fin main

// ya se fijaron como se pasa la string

void proc1(char nom[], int suma)

{

//declarando variables

int edad;

// capturando

printf("dame edad: "); scanf("%d",&edad);

// operaciones sumando parametro

edad = edad + suma;

//construyendo y desplegando la pagina de salida

printf("%s \n",nom);

Realizado por: Ing. Jorge Eloy Toledo Coronel

12

printf("EDAD= %d", edad);

getchar();getchar();

}

// fin proc

Y no olvidar declarar el procedimiento antes del main() incluyendo sus parametros como lo muestra el ejemplo.

Recordar tambien que se pueden mandar como parametros, datos, variables y expresiones algebraicas(no formulas o ecuaciones algebraicas)

Corrida:

Observar que en el procedimiento los parámetros son dos variables locales es decir variables que solo se pueden usar dentro del procedimiento estas variables son quienes reciben los datos o valores.

REGLAS PARA EL USO DE PARAMETROS

1.- Cuando se usan variables como parametros, la variable que se manda debe ser declarada dentro del principal o del procedimiento de donde se esta enviando.

2.- La variable que se manda tiene un nombre, la que se recibe puede tener otro nombre o el mismo nombre por claridad de programa, pero recordar que internamente en la memoria del computador existiran dos variables diferentes.

3.- La cantidad de variables que se envian deben ser igual en cantidad, orden y tipo a las variables que reciben.

4.- La variable que se recibe tiene un ambito local dentro del procedimiento, es decir solo la puede usar ese procedimiento.

5.- Se puede mandar a un procedimiento un dato, una variable(como lo muestran los ejemplos) o una expresión algebraica (no ecuación o formula, pero siempre se deberan recibir en una variable.

Realizado por: Ing. Jorge Eloy Toledo Coronel

13

Parámetros por valor y por referencia.

Dediquemos algo más de tiempo a las funciones.

Hasta ahora siempre hemos declarado los parámetros de nuestras funciones del mismo modo. Sin embargo, éste no es el único modo que existe para pasar parámetros.

La forma en que hemos declarado y pasado los parámetros de las funciones hasta ahora es la que normalmente se conoce como "por valor". Esto quiere decir que cuando el control pasa a la función, los valores de los parámetros en la llamada se copian a "variables" locales de la función, estas "variables" son de hecho los propios parámetros.

Lo veremos mucho mejor con un ejemplo:

#include <iostream> using namespace std; int funcion(int n, int m); int main() { int a, b; a = 10; b = 20; cout << "a,b ->" << a << ", " << b << endl; cout << "funcion(a,b) ->" << funcion(a, b) << endl; cout << "a,b ->" << a << ", " << b << endl; cout << "funcion(10,20) ->" << funcion(10, 20) << endl; cin.get(); return 0; } int funcion(int n, int m) { n = n + 5; m = m - 5; return n+m; }

Bien, ¿qué es lo que pasa en este ejemplo?. Empezamos haciendo a = 10 y b = 20, después llamamos a la función "funcion" con las variables a y b como parámetros. Dentro de "funcion" los parámetros se llaman n y m, y cambiamos sus valores, sin embargo al retornar a "main", a y b conservan sus valores originales. ¿Por qué?.

La respuesta es que lo que pasamos no son las variables a y b, sino que copiamos sus valores a las variables n y m.

Piensa, por ejemplo, en lo que pasa cuando llamamos a la función con parámetros constantes, es lo que pasa en la segunda llamada a "funcion". Los valores de los parámetros no pueden cambiar al retornar de "funcion", ya que son valores constantes. Si no fuese así, no sería posible llamar a la función con estos valores.

Realizado por: Ing. Jorge Eloy Toledo Coronel

14

Referencias a variables:

Las referencias sirven para definir "alias" o nombres alternativos para una misma variable. Para ello se usa el operador de referencia (&).

Sintaxis:

<tipo> &<alias> = <variable de referencia> <tipo> &<alias>

La primera forma es la que se usa para declarar variables de referencia, la asignación es obligatoria ya que no pueden definirse referencias indeterminadas.

La segunda forma es la que se usa para definir parámetros por referencia en funciones, en las que las asignaciones son implícitas.

Ejemplo:

#include <iostream> using namespace std; int main() { int a; int &r = a; a = 10; cout << r << endl; cin.get(); return 0; }

En este ejemplo las variables a y r se refieren al mismo objeto, cualquier cambio en una de ellas se produce en ambas. Para todos los efectos, son la misma variable.

Pasando parámetros por referencia:

Si queremos que los cambios realizados en los parámetros dentro de la función se conserven al retornar de la llamada, deberemos pasarlos por referencia. Esto se hace declarando los parámetros de la función como referencias a variables. Ejemplo:

#include <iostream> using namespace std; int funcion(int &n, int &m); int main() { int a, b; a = 10; b = 20;

Realizado por: Ing. Jorge Eloy Toledo Coronel

15

cout << "a,b ->" << a << ", " << b << endl; cout << "funcion(a,b) ->" << funcion(a, b) << endl; cout << "a,b ->" << a << ", " << b << endl; /* cout << "funcion(10,20) ->" << funcion(10, 20) << endl; (1) es ilegal pasar constantes como parámetros cuando estos son referencias */ cin.get(); return 0; } int funcion(int &n, int &m) { n = n + 5; m = m - 5; return n+m; }

En este caso, las variables "a" y "b" tendrán valores distintos después de llamar a la función. Cualquier cambio que realicemos en los parámetros dentro de la función, se hará también en las variables referenciadas. Esto quiere decir que no podremos llamar a la función con parámetros constantes, como se indica en (1), ya que no se puede definir una referencia a una constante.

Constructores: Los constructores son funciones miembro especiales que sirven para inicializar un objeto de una determinada clase al mismo tiempo que se declara.

Los constructores tienen el mismo nombre que la clase, no retornan ningún valor y no pueden ser heredados. Además deben ser públicos, no tendría ningún sentido declarar un constructor como privado, ya que siempre se usan desde el exterior de la clase, ni tampoco como protegido, ya que no puede ser heredado.

Añadamos un constructor a nuestra clase

Si una clase posee constructor, será llamado siempre que se declare un objeto de esa clase, y si requiere argumentos, es obligatorio suministrarlos.

Por ejemplo, las siguientes declaraciones son ilegales:

pareja par1; pareja par1();

La primera porque el constructor de "pareja" requiere dos parámetros, y no se suministran.

La segunda es ilegal por otro motivo más complejo. Aunque existiese un constructor sin parámetros, no se debe usar esta forma para declarar el objeto, ya que el compilador lo considera como la declaración de un prototipo de una función que devuelve un objeto de tipo "pareja" y no admite parámetros. Cuando se use un constructor sin parámetros para declarar un objeto no se deben escribir los paréntesis.

Y las siguientes declaraciones son válidas:

Realizado por: Ing. Jorge Eloy Toledo Coronel

16

pareja par1(12,43); pareja par2(45,34);

Cuando no especifiquemos un constructor para una clase, el compilador crea uno por defecto sin argumentos. Por eso el ejemplo del capítulo anterior funcionaba correctamente. Cuando se crean objetos locales, los datos miembros no se inicializarían, contendrían la "basura" que hubiese en la memoria asignada al objeto. Si se trata de objetos globales, los datos miembros se inicializan a cero.

Para declarar objetos usando el constructor por defecto o un constructor que hayamos declarado sin parámetros no se debe usar el paréntesis:

pareja par2();

Se trata de un error frecuente cuando se empiezan a usar clases, lo correcto es declarar el objeto sin usar los paréntesis:

pareja par2;

Destructores

Los destructores son funciones miembro especiales que sirven para eliminar un objeto de una determinada clase, liberando la memoria utilizada por dicho objeto.

Los destructores tienen el mismo nombre que la clase, pero con el símbolo ~ delante, no retornan ningún valor y no pueden ser heredados.

Cuando se define un destructor para una clase, éste es llamado automáticamente cuando se abandona el ámbito en el que fue definido. Esto es así salvo cuando el objeto fue creado dinámicamente con el operador new, ya que en ese caso, si es necesario eliminarlo, hay que usar el operador delete.

En general, será necesario definir un destructor cuando nuestra clase tenga datos miembro de tipo puntero, aunque esto no es una regla estricta. El destructor no puede sobrecargarse, por la sencilla razón de que no admite argumentos.

Ejemplo:

#include <iostream> #include <cstring> using namespace std; class cadena { public: cadena(); // Constructor por defecto cadena(char *c); // Constructor desde cadena c cadena(int n); // Constructor de cadena de n caracteres cadena(const cadena &); // Constructor copia ~cadena(); // Destructor

Realizado por: Ing. Jorge Eloy Toledo Coronel

17

void Asignar(char *dest); char *Leer(char *c); private: char *cad; // Puntero a char: cadena de caracteres }; cadena::cadena() : cad(NULL) {} cadena::cadena(char *c) { cad = new char[strlen(c)+1];// Reserva memoria para cadena strcpy(cad, c); // Almacena la cadena } cadena::cadena(int n) { cad = new char[n+1]; // Reserva memoria para n caracteres cad[0] = 0; // Cadena vacía } cadena::cadena(const cadena &Cad) { // Reservamos memoria para la nueva y la almacenamos cad = new char[strlen(Cad.cad)+1]; // Reserva memoria para cadena strcpy(cad, Cad.cad); // Almacena la cadena } cadena::~cadena() { delete[] cad; // Libera la memoria reservada a cad } void cadena::Asignar(char *dest) { // Eliminamos la cadena actual: delete[] cad; // Reservamos memoria para la nueva y la almacenamos cad = new char[strlen(dest)+1]; // Reserva memoria para la cadena strcpy(cad, dest); // Almacena la cadena } char *cadena::Leer(char *c) { strcpy(c, cad); return c; } int main() { cadena Cadena1("Cadena de prueba"); cadena Cadena2(Cadena1); // Cadena2 es copia de Cadena1 cadena *Cadena3; // Cadena3 es un puntero char c[256]; // Modificamos Cadena1: Cadena1.Asignar("Otra cadena diferente"); // Creamos Cadena3: Cadena3 = new cadena("Cadena de prueba nº 3"); // Ver resultados cout << "Cadena 1: " << Cadena1.Leer(c) << endl; cout << "Cadena 2: " << Cadena2.Leer(c) << endl; cout << "Cadena 3: " << Cadena3->Leer(c) << endl;

Realizado por: Ing. Jorge Eloy Toledo Coronel

18

delete Cadena3; // Destruir Cadena3. // Cadena1 y Cadena2 se destruyen automáticamente cin.get(); return 0; }

Voy a hacer varias observaciones sobre este programa:

1.-Hemos implementado un constructor copia. Esto es necesario porque una simple asignación entre los datos miembro "cad" no copiaría la cadena de un objeto a otro, sino únicamente los punteros.

Por ejemplo, si definimos el constructor copia como:

cadena::cadena(const cadena &Cad) { cad = Cad.cad; }

En lugar de cómo lo hacemos, lo que estaríamos copiando sería el valor del puntero cad, con lo cual, ambos punteros estarían apuntando a la misma posición de memoria. Esto es desastroso, y no simplemente porque los cambios en una cadena afectan a las dos, sino porque al abandonar el programa se intenta liberar automáticamente la misma memoria dos veces. Lo que realmente pretendemos al asignar cadenas es crear una nueva cadena que sea copia de la cadena antigua. Esto es lo que hacemos con el constructor copia, y es lo que haremos más adelante, y con más elegancia, sobrecargando el operador de asignación.

La definición del constructor copia que hemos creado en este último ejemplo es la equivalente a la del constructor copia por defecto.

2.-La función Leer, que usamos para obtener el valor de la cadena almacenada, no devuelve un puntero a la cadena, sino una copia de la cadena. Esto está de acuerdo con las recomendaciones sobre la programación orientada a objetos, que aconsejan que los datos almacenados en una clase no sean accesibles directamente desde fuera de ella, sino únicamente a través de las funciones creadas al efecto. Además, el miembro cad es privado, y por lo tanto debe ser inaccesible desde fuera de la clase. Más adelante veremos cómo se puede conseguir mantener la seguridad sin crear más datos miembro.

3.- La Cadena3 debe ser destruida implícitamente usando el operador delete, que a su vez invoca al destructor de la clase. Esto es así porque se trata de un puntero, y la memoria que se usa en el objeto al que apunta no se libera automáticamente al destruirse el puntero Cadena3.

Ejemplo de un programa orientado a objetos utilizando constructores y destructores //* Ejemplo Numero 1*// #include<iostream.h> #include<conio.h> #include<stdio.h> class numeros { private: int n1,n2,num1,num2; public: numeros(){}

Realizado por: Ing. Jorge Eloy Toledo Coronel

19

numeros(int,int); void leer(); void imprimir(); }; numeros::numeros(int n1,int n2) { n1=num1; n2=num2; } void numeros::leer() {clrscr(); cout<<"Primer Numero = "; cin>>n1; cout<<"Segundo Numero = ";cin>>n2; } void numeros::imprimir() {clrscr(); if((n1>0)&&(n2>0)) { if (n1>n2) { textcolor(5); textbackground(6); cout<<"El mayor en = "<<n1<<"\n"; getch(); } else { cout<<"El mayor en = "<<n2<<"\n"; getch(); } } else { cout<<"los numeros no son mayores de cero\n"; getch(); } } void main() {clrscr(); numeros n; n.leer(); n.imprimir(); } //* Ejemplo 2*// #include<iostream.h> #include<conio.h> #include<stdio.h> #include<math.h> #define pi 3.1416 class circulo { private: float a,radio; public: circulo(){}//* constructor vacio*// circulo(float,float);//*cosntructor con para metros*//

Realizado por: Ing. Jorge Eloy Toledo Coronel

20

void leer(); void imprimir(); }; circulo::circulo(float area,float r) { a=area; radio=r; } void circulo::leer() {clrscr(); cout<<"Proporcionar el valor del radio ="; cin>>radio; } void circulo::imprimir() {clrscr(); a= pi * (radio*radio); cout<<"El Area = "<<a<<"\n"; getch(); } void main() {clrscr(); circulo c;//* esto es para no ponerle parametros a los objetos*// c.leer(); c.imprimir(); }

Realizado por: Ing. Jorge Eloy Toledo Coronel

21

//*Ejemplo 3*// #include<iostream.h> #include<conio.h> #include<stdio.h> class depresiar { private: int annos,i; float suma,d[20],costo; public: depresiar(){} depresiar(int); depresiar(int,float); void leer(); void imprimir(); }; depresiar::depresiar(int na,float s) { annos=na; suma=s; } void depresiar::leer() {clrscr(); cout<<"Cuantos A¤os = "; cin>>annos; cout<<"Costo del Equipo = "; cin>>costo; } void depresiar::imprimir() {clrscr(); suma=0; for(i=1;i<=annos;i++) { suma = suma + i; } cout<<"La suma de los a¤os = "<<suma<<"\n"; getch(); clrscr(); cout<<"La Depresiacion del Equipo es La Siguiente\n"; cout<<" \n"; for(i=annos;i>=1;i--) { d[i]=((i/suma)* costo); cout<<"La Depresiacion = $ "<<d[i]<<"\n"; } getch(); cout<<"============================\n"; cout<<"\n"; cout<<"Que a todo dar que salio\n"; getch(); } void main() { int op; clrscr(); do{clrscr(); cout<<"Opcion = "; cin>>op; switch(op) { case 1:{ depresiar d; d.leer(); break;

Realizado por: Ing. Jorge Eloy Toledo Coronel

22

} case 2:{ depresiar d; d.imprimir(); } } } while (op<3); }

Realizado por: Ing. Jorge Eloy Toledo Coronel

1

Unidad 6

Estructuras Secuénciales y Selectivas

6.1.- Modificadores de acceso(public,private)

6.2.- Entrada y salida de datos

6.3.- Interacción de la aplicación y la clase

6.4.- Estructuras selectivas

Realizado por: Ing. Jorge Eloy Toledo Coronel

2

6.1.- Modificadores de acceso

Ya hemos visto el significado de los modificadores de acceso public y private, así como el control de acceso por defecto a nivel de paquete, cuando no se especifica nada. En la herencia, surge un nuevo control de acceso denominado protected.

Hemos puesto protected delante de los miebros dato x e y de la clase base Ventana

public class Ventana { protected int x; protected int y; //... }

En la clase derivada la función miembro desplazar accede a dichos miembros dato

public class VentanaTitulo extends Ventana{ //... public void desplazar(int dx, int dy){ x+=dx; y+=dy; } }

Si cambiamos el modificador de acceso de los miembros x e y de la clase base Ventana de protected a private , veremos que el compilador se queja diciendo que los miembro x e y no son accesibles.

Los miembros ancho y alto se pueden poner con acceso private sin embargo, es mejor dejarlos como protected ya que podrían ser utilizados por alguna función miembro de otra clase derivada de VentanaTitulo. Dentro de una jerarquía pondremos un miembro con acceso private, si estamos seguros de que dicho miembro solamente va a ser usado por dicha clase.

Como vemos hay cuatro modificadores de acceso a los miembros dato y a los métodos: private, protected, public y default (por defecto, o en ausencia de cualquier modificador). La herencia complica aún más el problema de acceso, ya que las clases dentro del mismo paquete tienen diferentes accesos que las clases de distinto paquete

Los siguientes cuadros tratan de aclarar este problema

Clases dentro del mismo paquete Modificador de acceso

Heredado Accesible

Por defecto (sin modificador)

Si Si

private No No

protected Si Si

public Si Si

Realizado por: Ing. Jorge Eloy Toledo Coronel

3

Clases en distintos paquetes

Modificador de acceso

Heredado Accesible

Por defecto (sin modificador)

No No

private No No

protected Si No

public Si Si

Desde el punto de vista práctico, cabe reseñar que no se heredan los miembros privados, ni aquellos miembros (dato o función) cuyo nombre sea el mismo en la clase base y en la clase derivada.

La clase base Object

La clase Object es la clase raíz de la cual derivan todas las clases. Esta derivación es implícita.

La clase Object define una serie de funciones miembro que heredan todas las clases. Las más importantes son las siguientes

public class Object { public boolean equals(Object obj) { return (this == obj); } protected native Object clone() throws CloneNotSupportedException; public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } protected void finalize() throws Throwable { } //otras funciones miembro... }

Igualdad de dos objetos:

Hemos visto que el método equals de la clase String cuando compara un string y cualquier otro objeto. El método equals de la clase Object compara dos objetos uno que llama a la función y otro es el argumento de dicha función.

Representación en forma de texto de un objeto

El método toString imprime por defecto el nombre de la clase a la que pertenece el objeto y su código (hash). Esta función miembro se redefine en la clase derivada para mostrar la información que nos interese acerca del objeto. La clase Fraccion redefine toString para mostrar el numerador y el denominador separados por la barra de dividir. En la misma página, hemos mejorado la clase Lista para mostrar los datos que se guardan en los objetos de dicha clase, redefiniendo toString.

La función toString se llama automáticamente siempre que pongamos un objeto como argumento de la función System.out.println o concatenado con otro string.

Realizado por: Ing. Jorge Eloy Toledo Coronel

4

Duplicación de objetos

El método clone crea un objeto duplicado (clónico) de otro objeto. Más adelante estudiremos en detalle la redefinición de esta función miembro y pondremos ejemplos que nos muestren su utilidad.

Finalización

El método finalize se llama cuando va a ser liberada la memoria que ocupa el objeto por el recolector de basura (garbage collector). Normalmente, no es necesario redefinir este método en las clases, solamente en contados casos especiales. La forma en la que se redefine este método es el siguiente.

class CualquierClase{ //.. protected void finalize() trows Throwable{ super.finalize(); //código que libera recursos externos } }

La primera sentencia que contenga la redefinición de finalize ha de ser una llamada a la función del mismo nombre de la clase base, y a continuación le añadimos cierta funcionalidad, habitualmente, la liberación de recursos, cerrar un archivo, etc.

Este ejemplo :

Ilustra una faceta importante de los lenguajes de Programación Orientada a Objetos denominada encapsulación. El acceso a los miembros de una clase está controlado. Para usar una clase, solamente necesitamos saber que funciones miembro se pueden llamar y a qué datos podemos acceder, no necesitamos saber como está hecha la clase, como son sus detalles internos. Una vez que la clase está depurada y probada, la clase es como una caja negra. Los objetos de dicha clase guardan unos datos, y están caracterizados por una determinada conducta. Este ocultamiento de la información niega a la entidades exteriores el acceso a los miembros privados de un objeto. De este modo, las entidades exteriores acceden a los datos de una manera controlada a través de algunas funciones miembro. Para acceder a un miembro público (dato o función) basta escribir.

objeto_de_la_clase_Fraccion.miembro_público_no_estático clase_Fraccion.miembro_público_estático

Delante de los miembros dato, como podemos ver en el listado hemos puesto las plabras reservadas public y private.

• Miembros públicos

Los miembros públicos son aquellos que tienen delante la palabra public, y se puede acceder a ellos sin ninguna restricción.

• Miembros privados

Los miembros privados son aquellos que tienen delante la palabra private, y se puede acceder a ellos solamente dentro del ámbito de la clase.

Los miembros dato num y den son privados, y también la función que calcula el máximo común divisor mcd, que es una función auxiliar de la función miembro publica simplificar. El usuario solamente precisa saber que dispone de una función pública que le permite simplificar una

Realizado por: Ing. Jorge Eloy Toledo Coronel

5

fracción, pero no necesita saber cuál es el procedimiento empleado para simplificar fracciones. Así declaramos la función mcd como privada y simplificar como pública.

• Por defecto (a nivel de paquete)

6.2.- Entrada y Salida de Datos

Las operaciones de entrada y salida se realizan en C++, al igual que en C, mediante flujos (streams) o secuencia de datos. Los flujos estándares son cout (flujo de salida) y en cin (flujo de entrada). El flujo de salida fluye normalmente a la pantalla ----- aunque puede ser diseccionado a otros dispositivos de salida ----- y el flujo de entrada representa datos que proceden del teclado (a menos que haya sido redireccionado). SALIDA El flujo de salida se representa por el identificador cout, que es realidad un objeto. El operador << se denomina operador de inserción o de << poner en >>. Dirige el contenido de la variante situada a su derecha al objeto situado a su izquierda. El equivalente en C de cout es la función printf. Por ejemplo: Void main() { printf(“este es tan solo un programa de prueba\n”); } y tiene su equivalente en C++ #include<iostream.h> void main() { cout<<”este es tan solo un programa de prueba\n”); } El archivo de inclusión (cabecera9 <ioestream.h> contiene las facilidades estándares de entrada y salida de datos en C++. El nombre de este archivo puede variar según sea el compilador utilizado. El operador “<<” escribe el argumento que le procede. Supongamos que se desea visualizar una variable entera en la pantalla. En C se utilizaría la función printf junto con una cadena de formato que describe los parámetros a utilizar en printf. Ejemplo Printf (“%d”,precio); En C++, los dispositivos de salida no requieren la cadena de formato. El siguiente programa visualiza la cantidad de 12300. #include<iostream.h> Viod main() { Int precio = 12300; Cout<<precio } Pero si queremos la salida con formato en C++ seria de la siguiente forma: #include<iostream.h> Viod main() { Int precio = 12300; Cout<<” el precio = “<<precio<<”\n”; }

Realizado por: Ing. Jorge Eloy Toledo Coronel

6

ENTRADA.- La función scanf requiere caracteres de formato y operadores de direccionamiento;; y cin no los requiere. Al igual scanf, cin lee el flujo de información de entrada hasta que se encuentre el espacio en blanco en cuyo momento se detiene la entrada. Observe que se puede controlar una nueva línea como un carácter \̀n´ o bien una cadena <<\>>; El operador cin en C++, es una función de entrada de información o de datos que también trabaja con cadenas mas no es recomendable. El siguiente programa muestra la diferencia entre scanf() y el cin: #include<iostream.h> #include<studio.h> Viod main() { int x; Flota y; Scanf(“%”,&y); Printf(“x=%d\t y= %f\n”,.x,y); Cin>>x>>y; Cout << ”x=”<<x<<”\t”<<”y=”<<y<<”\n”; } 6.3.-Interacción de la aplicación clase El mecanismo de clases de Python añade clases al lenguaje con un mínimo de sintaxis y semántica nueva. Es una mezcla de los mecanismos de clase de C++ y Modula-3. Como en los módulos, las clases de Python no ponen una barrera absoluta entre la definición y el usuario, sino que más bien se fían de la buena educación del usuario para no ``invadir la definición''. Se mantienen las características más importantes con plena potencia. El mecanismo de herencia de clases permite múltiples clases base, una clase derivada puede redefinir cualquier método de sus clases base y un método puede llamar a un método de una clase base con el mismo nombre. Los objetos pueden contener una cantidad arbitraria de datos privados. En terminología C++, todos los miembros de la clase (datos incluidos) son públicos y todas las funciones miembro son virtuales. No hay constructores ni destructores especiales. Como en Modula-3, no existen abreviaturas para hacer referencia a los miembros del objeto desde sus propios métodos. La función método se declara con un primer argumento explícito que representa al objeto y que se proporciona implícitamente al llamar a la función. Como en Smalltalk, las clases son ellas mismas objetos, aunque en un sentido más amplio de la palabra: en Python, todos los tipos de datos son objetos. Esto proporciona la semántica para importar y renombrar. Sin embargo, como en C++ o en Modula3, los tipos internos no pueden ser la clase base para extensiones del usuario. Además, como en C++ y al contrario de Modula-3, la mayoría de operadores internos con sintaxis especial (operadores aritméticos, índices, etc.) se pueden redefinir en las clases. Sintaxis de la Clase Class nombre de la clase { Definición de los atributos privados Definición de los atributos publicos } Ejemplo Class nombre { Private:

Char nom[45],direccion[45]; Int edad;

Realizado por: Ing. Jorge Eloy Toledo Coronel

7

Float salario; Public: Void leer(); Void imprimir(); } La iteración de la clase seria: Void nombre:: leer() { Cout<<”Nombre =”; gets(nom); Cout<<”Direccion =”; gets(direccion); Cout<<”Edad=”; cin>>edad; Cout<<”salario =”; cin>>salario; } Void nombre::imprimir() { Cout<<”Nombre =”<<nom<<”\n”; Cout<<”Direccion =”<<direccion<<”\n”; Cout<<”Edad=”<<edad<<”\n”; Cout<<”salario =”<<salario<<”\n”; Getch(); } Void main() { Nombre a; a.leer(); a.imprimir(); } 6.4.- Estructuras de control, asignación y selección Las sentencias de selección también se les conocen como sentencia condicional, entre las que se incluyen if y switch. Muchas sentencias de C y C++ se basan en una prueba condicional que determina una acción que se ha de llevar acabo. Una expresión condicional y tiene como resultado un valor cierto o falso. En C o en C++ cualquier valor distinto de cero es verdadero, incluyendo números negativos. El 0 es el único valor falso. SELECCIÓN SIMPLE: Pseudo código Sintaxis Inicio { Acción Si (condición) entonces if (condición){ Acción acción Acción acción Acción acción “ “ “ “ Acción x acción x Acción Fin si } Fin }

Realizado por: Ing. Jorge Eloy Toledo Coronel

8

Si al evaluar la expresión, esta es verdadera se ejecutan las sentencias del bloque (un bloque empieza con { y termina }), en caso contrario se ejecutan las sentencias a continuación del bloque la cláusula else se puede añadir a la sentencia if cuando la expresión es falsa y se desean ejecutar sentencias distintas. SELECCIÓN MULTIPLE: Pseudo código Sintaxis Inicio { Acción Si (condición) entonces if (condición){ Acción acción Acción acción Acción acción “ “ “ “ Acción x acción x Si no } Acción else “ { “ acción “ acción Fin si } Fin } Otra sentencia de control de selección es la estructura switch (condición) que permite evaluar una expresión y tomar diversas acciones en función del resultado de la expresión. Pseudo código Sintaxis Inicio { Acción acción Según (condición) switch (condición) { En caso ‘1’ acción case ‘1’: acción Break; En caso 2 acción case 2: acción Break; En caso ‘a’ acción case ‘a’: accion Break; Otros default: Acción accion Fin según } Fin } Las siguientes reglas se aplican en el eso de la sentencia switch ().

• Expresión entera. Puede ser una constante, una variable, una llamada a una función o una expresión. La sentencia switch () no funcionara con datos de tipo flotante.

• El valor después de cada etiqueta case debe ser una constante entera o de tipo carácter, como 3 o ‘b’ o bien una expresión que se evalué a una constante como ‘a’ + ‘32’.

Realizado por: Ing. Jorge Eloy Toledo Coronel

9

• Se necesita utilizar una sentencia Irak; después de cada conjunto de sentencias ejecutables. Las sentencias break hace que la ejecución del programa se reanude después del final de la sentencia switch actual. Si no se utiliza las sentencias break; la ejecución del programa se reanudara en las siguientes etiquetas case.

• El conjunto de sentencias Case no necesita ser encerrada entre llaves. • Si ninguno de los valores de constante_1, constante_2, etc. Coincide con el valor de

expresión_entera, se ejecutaran las sentencias que viven a continuación de las sentencias opcional default.

Realizado por: Ing. Jorge Eloy Toledo Coronel

1

Unidad 7

ESTRUCTURAS DE REPETICION 7.1.- Repetir mientras Selectiva simple(si) 7.2.- Repetir hasta 7.3.- Repetir desde

Realizado por: Ing. Jorge Eloy Toledo Coronel

2

7.1.- Estructura Repite Mientras(While) La sentencia while es el ciclo de verificación preeliminar, esto significa que la condición es evaluada antes de entrar a ejecutar las instrucciones dentro del cuerpo del ciclo. Debido a esto se pueden ejecutar de cero a muchas veces. Sintaxis: While (condición) { instrucción_1 instrucción_2 } Ejemplo: La inicialización de un ciclo while por lo regular se realiza antes de ella el incremento dentro del bloque

Entre las sentencias de iteración se incluyen for – while y do while. Cualquier sentencia de iteración tiene tres partes importantes que son: inicialización, condición e incremento, aunque casa sentencia de iteración debe usarse preferentemente según la situación en la mayoría de los casos se puede adaptar cualquiera de las tres a cualquier situación. Ejemplo: Diseñar el algoritmo y programa en c++ que nos permita obtener los 10 primeros numero enteros Diagrama de flujo Pseudocodigo Inicio X=0 Mientras x<0 hacer X=x + 1 Imprimir x Fin mientras Fin

Realizado por: Ing. Jorge Eloy Toledo Coronel

3

7.2.- Estructura repite – hasta(Do – while) Difiere tanto del for como del while en que es un ciclo de verificación posterior, es decir, al ciclo se entra al menos una vez, y la condición del ciclo se prueba al cabo de la primera vez, es mejor utilizarlos en aquellas aplicaciones en las que se requiere entrar al ciclo. Sintaxis: { Do { Instrucción_1 Instrucción_2 } While (condición); } Ejemplo: Diseñar el algoritmo y programa en c++ que nos permita obtener los 10 primeros numero enteros Diagrama de flujo Pseudocodigo Inicio X=0 Repetir X=x+1 Imprimir x Hasta x=10 Fin 7.3.- Estructura repite desde o repite para(For)

Cuando se desea ejecutar una sentencia simple o compuesta, repetitivamente un numero de veces conocido, la construcción adecuada es la sentencia for. Sintaxis:

For (var=vinicial; var<vfinal; var++) //* repetición en forma ascendente*// For (var=vfinal; var>vfinicial; var--) //* repetición en forma descendente*// { Acción Acción }

Realizado por: Ing. Jorge Eloy Toledo Coronel

4

Cuando se encuentra la instrucción for se ejecuta primero la expresión de inicialización, no volviéndose a ejecutarse más. Generalmente esta instrucción realizara la inicialización de la variable de control del ciclo. Tras esto se prueba la condición. Siempre que la condición se evalué como verdadera la instrucción o instrucciones dentro del ciclo son ejecutadas. Después de entrar en el ciclo y ejecutar todas las instrucciones dentro de este se ejecuta la expresión incremento. Sin embargo si la condición toma el valor falso, las instrucciones dentro del ciclo son ignoradas y la ejecución continua con la instrucción final del ciclo. Cuando se necesitan ejecutar varias instrucciones dentro del ciclo se hacen necesarias definir el bloque con llaves {}.

Diagrama de flujo Pseudocodigo Inicio Leer tabla Para i=1 hasta 10 repetir M = tabla * i Imprimir m Fin para Fin