0% encontró este documento útil (0 votos)
38 vistas207 páginas

Programacion Orientada AObjetos Con C

El documento describe conceptos clave de la programación orientada a objetos, incluyendo el ciclo de vida del software, factores de calidad del software, tipos de datos abstractos, clases, objetos, mensajes, polimorfismo, encapsulamiento y funciones miembro. También explica estos conceptos en el contexto del lenguaje C++.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PPT, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
38 vistas207 páginas

Programacion Orientada AObjetos Con C

El documento describe conceptos clave de la programación orientada a objetos, incluyendo el ciclo de vida del software, factores de calidad del software, tipos de datos abstractos, clases, objetos, mensajes, polimorfismo, encapsulamiento y funciones miembro. También explica estos conceptos en el contexto del lenguaje C++.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PPT, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 207

Programación Orientada

a Objetos con C++


Ciclo de vida del software

Análisis

Mantenimiento

Depuración

Diseño

Implementación
Factores de calidad del software

 Eficiencia. Capacidad para hacer un buen uso de


los recursos que manipula.
 Portabilidad. Facilidad con la que un software
puede ser transportado sobre diferentes
sistemas físicos o lógicos.
 Integridad. Capacidad de un software para
proteger sus propios componentes contra los
procesos que no tengan derecho de acceso.
Factores de calidad del software

 Verificabilidad. Facilidad de verificación de un


software; es su capacidad para soportar los
procedimientos de validación y de aceptar
juegos de test o ensayo de programas.
 Corrección. Capacidad de los productos software
de realizar exactamente las tareas definidas por
su especificación.
 Robustez. Capacidad de funcionar incluso en
situaciones anormales.

L.I. M.S.I. Sergio Ellerbracke


Factores de calidad del software

 Reutilización. Capacidad de los productos para


ser reutilizados, en su totalidad o en parte, en
nuevas aplicaciones.
 Compatibilidad. Facilidad de los productos para
ser combinados con otros.
 Fácil de utilizar. Un software es fácil de utilizar si
se puede comunicar con él de manera cómoda.
Factores de calidad del software

 Extensibilidad. Facilidad que tienen los


productos de adaptarse a cambios en su
especificación. Existen dos principios
fundamentales para conseguir esto: diseño
simple y descentralización.
Historia de la abstracción del software

 Subrutinas.
 Procedimientos.
 Módulos.
 Tipos abstractos de datos.
 Objetos
 Programación Visual. (Eventos).
 Componentes.
Tipo de datos abstracto (TDA)

 Un tipo de datos es abstracto (TDA) si las


operaciones de alto nivel adecuadas a los tipos
de datos están aisladas de los detalles de la
implementación asociados con el tipo de datos.
 Una clase es un TDA junto con un conjunto de
transformaciones permitidas de dicho TDA.
Conceptos y entidades de
la Orientación a objetos

 Encapsulamiento  Objetos
 Polimorfismo  Mensajes
 Modularidad  Funciones Miembro
 Abstracción  Clases
 Herencia  Instancias
 Persistencia  Jerarquía
 Ligado tardío  Composición
 Genericidad  Asociación
 Concurrencia  Interfaz
Abstracción

 Capacidad para encapsular y aislar la


información del diseño y ejecución.
 Una abstracción denota las características
esenciales de un objeto que lo distinguen de
todos los demás tipos de objeto, y proporciona
así fronteras conceptuales nítidamente definidas
respecto a la perspectiva del observador.
Abstracción

 Principio de mínima sorpresa. Una


abstracción captura el comportamiento complejo
de un objeto, ni más ni menos, y no ofrece
sorpresas o efectos laterales que lleguen más
allá del ámbito de abstracción.
Abstracción

 Modelo contractual. La vista exterior de cada


objeto define un contrato del que pueden
depender otros objetos, y que a su vez debe ser
llevado a cabo por la vista interior del propio
objeto (a menudo en colaboración con otros
objetos).
Modularidad

 Es la propiedad que permite subdividir una


aplicación en partes más pequeñas (llamadas
módulos), cada una de las cuales debe ser tan
independiente como sea posible de la aplicación
en sí y de las restantes partes.
 La modularidad es la propiedad que tiene un
sistema que ha sido descompuesto en un
conjunto de módulos cohesivos y débilmente
acoplados.
Clases

 Una clase es la declaración de un tipo objeto.


 Una clase es una descripción abstracta de un
grupo de objetos, cada uno de los cuales se
diferencia por su estado específico y por la
posibilidad de realizar una serie de operaciones.
 Una clase es una estructura que contiene datos
y procedimientos que son capaces de operar
sobre esos datos.
Clases

 Una clase es un conjunto de objetos que


comparten una estructura común y un
comportamiento común.
 Para una clase dada, habitualmente existen dos
tipos de cliente: objetos que invocan
operaciones sobre instancias de la clase, y
subclases que heredan de esta clase.
Relaciones entre clases

 Los lenguajes OO ofrecen soporte directo para


alguna combinación de estas relaciones:
 Asociación. Implica cardinalidad.
 Generalización/Especialización (herencia).
 Agregación, composición, tiene-un.
 Uso. Acceso al interfaz public.
 Instanciación.
 Metaclase.
Clases en C++

class Nombre
{
cuerpo de la clase
};
Encapsulamiento

 Es la propiedad que permite asegurar que el


contenido de información de un objeto está
oculto al mundo exterior.
 El entorno orientado a objetos oculta
(encapsula) los detalles de implementación de
un objeto. La parte que no está oculta de un
objeto es su interfaz público, que consta de los
mensajes que se pueden enviar al objeto.
Encapsulamiento en C++

 Se consigue mediante el uso de las palabras


reservadas private, protected y public.
 Son miembros de la clase los miembros dato y
los miembros función.
 Los miembros privados son accesibles sólo por
las funciones miembro de la clase.
 Los miembros protegidos son accesibles por las
funciones miembro de la clase y también por las
funciones miembro de las clases derivadas.
Encapsulamiento en C++

 Los miembros públicos son accesibles desde


cualquier parte del programa.
 Los miembros dato normalmente son privados.
 Las relaciones de uso son a veces demasiado
restringidas porque permiten al cliente acceder
sólo al interfaz public del proveedor. A veces,
por razones tácticas, hay que romper el
encapsulamiento de estas abstracciones, y para
eso se provee el concepto friend en C++.
Encapsulamiento en C++

class Nombreclase {
private:
// Miembros privados
protected:
// Miembros protegidos
public:
// Miembros públicos
};
Funciones miembro

 Son los procedimientos o acciones que cambian


el estado de un objeto.
 Los métodos son el único medio de acceder a
los datos privados de un objeto.
 Si un objeto desea obtener datos de otro objeto,
se llama a un método de dicho objeto.
 Los métodos describen el comportamiento
asociado a un objeto.
Funciones miembro en C++

tipo_retorno NombreClase::NombreFuncion(lista de
argumentos)
{

}
Funciones miembro en C++

Constructores
NombreClase::NombreClase(argumentos):lista_inic
{

}
Destructores
NombreClase::~NombreClase(lista de argumentos)
{

}
Funciones miembro en C++

 Constructores y destructores no devuelven


ningún valor.
 Cuando se crea un objeto de una clase se
invoca a un constructor.
Funciones miembro en C++

 Los destructores se pueden invocar de tres


modos diferentes:
 Un objeto sale de ámbito o alcance.
 El operador delete se aplica a un puntero a
un objeto de la clase.
 El destructor se llama directamente por un
programa.
Funciones miembro en C++

 Una función miembro cuyo cuerpo se define en


la declaración de la clase se llama inline. Las
funciones en línea aumentan la velocidad de
ejecución, al reducir los tiempos suplementarios
utilizados en las llamadas y retornos.
 Las funciones miembro reconocen cuál es la
instancia de una clase a la que se llama, debido
a que se invoca a la función miembro con el
apuntador this.
El apuntador this en C++

 Este apuntador se declara implícitamente para


cada clase.
 Este apuntador implícito se conoce como this y
es una parte de cada clase.
 El puntero this es la dirección de la instancia de
cada clase.
Mensajes

 En POO, los mensajes (en vez de los datos) se


mueven por el sistema. En lugar del enfoque
funcional (invocar una función con unos datos),
en un lenguaje orientado a objetos se envía un
mensaje a un objeto.
 Los objetos de un programa se comunican
mediante mensajes.
 Un mensaje es una petición de un objeto a otro
objeto al que se le solicita ejecutar uno de sus
métodos.
Mensajes

 El conjunto de mensajes a los que responde un


objeto se denomina comportamiento del objeto.
No todos los mensajes de un objeto responden,
es preciso que pertenezcan al interfaz accesible.
Objetos

 Un objeto es una instancia de una clase que


encapsula operaciones y representación.
 Un objeto es una entidad cuyo comportamiento
se caracteriza por las acciones que realiza. Con
más precisión, un objeto se define como una
entidad caracterizada por un estado.
 Los objetos tienen un interfaz público y una
representación privada que permiten ocultar la
información que se desee al exterior.
Instancias

 Cada vez que se construye un objeto a partir de


una clase, estamos creando lo que se llama una
instancia de una clase.
 Los objetos no son más que instancias de una
clase.
 Una instancia es una variable de tipo objeto.
Objetos en C++

// Se obtiene una instancia y se invoca al constructor


NombreClase NombreInstancia(lista de parámetros);
NombreClase NombreArray[Tamaño];

// Se obtiene un apuntador a NombreClase, postergándose


// la instanciación de la clase. No se invoca en este
// momento al constructor
NombreClase *NombreApuntador;
NombreClase *NombreArray;
Objetos en C++

// Se instancia la clase y se invoca al constructor


*NombreApuntador = new NombreClase;
*NombreArray = new NombreClase[Tamaño];

// Si se crean con new, es necesario eliminarlos


// (normalmente en el destructor)
delete NombreApuntador;
delete [ ] NombreArray;
Polimorfismo

 Es la posibilidad de que una entidad tome


muchas formas.
 El polimorfismo permite referirse a objetos de
clases diferentes mediante el mismo elemento
de programa y realizar la misma operación de
diferentes formas, según sea el objeto que se
referencia en ese momento.
 El poliformismo requiere ligadura tardía.
Polimorfismo

 El polimorfismo permite que una misma función


se comporte de diferente forma según sea la
clase sobre la que se aplica.
Polimorfismo. Sobrecarga

 Sobrecarga es la propiedad que justifica el


utilizar el mismo nombre de operación para
representar operaciones similares que se
comportan de modo diferente cuando se aplican
a clases diferentes.
 La POO da un poco más énfasis en la
sobrecarga, haciéndola disponible para
operaciones sobre cualquier objeto.
Polimorfismo en C++

 Hay 3 niveles de polimorfismo en C++


 Polimorfismo de funciones miembro. No
requiere de ligadura tardía. Se decide en base
a argumentos.
 Polimorfismo de funciones miembro virtuales
y clases abstractas. Requiere de ligadura
tardía.
 Sobrecarga de operadores. No requiere
ligadura tardía.
Polimorfismo en C++

class Complejo {
double real; double imag;
public:
Complejo( );
Complejo(double);
Complejo(double,double);
void escribir();
Complejo operator + (const Complejo) const;
Complejo operator - (const Complejo) const;
};
Polimorfismo de funciones miembro en C++

// Constructor por defecto


Complejo::Complejo( ) {
real = imag = 0.0;
}

// Constructor - parte real


Complejo::Complejo(double r) {
real = r;
imag = 0.0;
}
Polimorfismo de funciones miembro en C++

// Constructor - parte real e imaginaria


Complejo::Complejo(double r, double i) {
real = r;
imag = i;
}

void Complejo::escribir( ) {
cout << “\nreal: “ << real << “ imaginaria: “ << imag;
}
Polimorfismo por sobrecarga de
operadores en C++

Complejo Complejo::operator +(const Complejo c) const {


return Complejo(real + c.real,imag + c.imag);
}

Complejo Complejo::operator -(const Complejo c) const {


return Complejo(real - c.real,imag - c.imag);
}
Jerarquía

 La jerarquía es una propiedad que permite una


ordenación de las abstracciones. Las dos
jerarquías más importantes 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.
Jerarquía

 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 y chasis. En consecuencia,
camión es una agregación de objetos ruedas,
motor ...
Herencia

 Es una propiedad que permite a los objetos ser


construidos a partir de otros objetos.
 Los objetos pueden heredar propiedades de
otros objetos.
 Una clase hereda sus características (datos y
funciones) de otra clase.
Herencia

 La herencia supone una clase base y una


jerarquía de clases que contienen las clases
derivadas de la clase base. Las clases derivadas
pueden heredar el código y los datos de su clase
base, añadiendo código especial y datos a ellas,
incluso cambiar aquellos elementos de la clase
base que necesita sean diferentes.
Herencia

 A la clase base también se le conoce como


superclase. Las clases que se derivan de una
superclase son las subclases.
 Las clases de objetos mamífero, pájaro e insecto
se definen como subclases de animal; la clase
de objeto persona, como una subclase de
mamífero, y un hombre y una mujer son
subclases de persona.
Tipos de Herencia

 En herencia simple, un objeto (clase) puede


tener sólo un ascendiente, o dicho de otro
modo, una subclase puede heredar datos y
métodos de una única clase, así como añadir o
quitar comportamientos de la clase base.
 La herencia múltiple es la propiedad de una
clase de poder tener más de un ascendiente
inmediato, o lo que es igual, adquirir datos y
métodos de más de una clase.
Herencia simple en C++

class base { … };

class derivada:[public | private | protected] base


{

};
Tipos de derivación de herencia en C++

Derivación pública
public public
protected protected
private no accesible

Derivación protegida
public protected
protected protected
private no accesible
Tipos de derivación de herencia en C++

Derivación privada (default)


public private
protected private
no accesible no accesible

Las derivaciones o herencia privada o protegida, aunque son


casos explícitos de herencia, en la práctica implementan
relaciones de agregación o contención (tiene-un).
Herencia simple en C++

class Habitacion {
int tamano_m_cuadrados;
public:
Habitacion(const int);
~Habitacion( );
void Tamano( );
};
Habitacion::~Habitacion( ) {
cout << “\nDestructor de habitacion”;
}
Herencia simple en C++

Habitacion::Habitacion(const int n)
{
tamano_m_cuadrados = n;
cout << “\nConstructor de Habitacion”;
}

void Habitacion::Tamano( )
{
cout << “\nMts cuadrados: “ << tamano_m_cuadrados;
}
Herencia simple en C++

class Oficina:public Habitacion {


int num_plantilla; // Numero de empleados
public:
Oficina(const int, const int);
~Oficina( );
void plantilla( );
};
Oficina::~Oficina( ) {
cout << “\nDestructor de oficina”;
}
Herencia simple en C++

Oficina::Oficina(const int Tam,const int plan):


Habitacion(Tam) {
num_plantilla = plan;
cout << “\nConstructor de oficina”;
}

void Oficina::plantilla( ) {
cout << “\nNumero de empleados: ” << num_plantilla;
}
Herencia simple en C++

void proc_oficina( )
{
Oficina H999(45,5);
H999.plantilla( );
H999.Tamano( );
}
Herencia simple en C++

La salida del programa será:


Constructor de Habitacion
Constructor de oficina
Numero de empleados: 5
Mts cuadrados: 45
Destructor de oficina
Destructor de Habitacion

L.I. M.S.I. Sergio Ellerbracke


Objetos compuestos

 Un objeto puede contener a otros objetos.


Entonces se dice que se tiene un objeto
compuesto.
 Un objeto compuesto consta de una colección
de dos o más objetos componentes. Los objetos
componentes tienen una relación parte-de con
el objeto compuesto.
Objetos compuestos en C++

class Presentar
{
int limite, valor;
public:
Presentar(int val,int lim) { valor = val; limite = lim; }
void Mostrar( ) { cout << valor; }
};
Objetos compuestos en C++

class Reloj
{
Presentar horas, minutos;
public:
Reloj(int ValHor,int ValMin):horas(ValHor,24),
minutos(ValMin,60) { }
void Ver( );
};
Objetos compuestos en C++

void Reloj::Ver( )
{
horas.Mostrar( );
cout << “\:”;
minutos.Mostrar( );
}
Herencia múltiple

 Caso 1. La propiedad referida sólo está en una


de las subclases padre (no hay problema).
 Caso 2. La propiedad concreta existe en más de
una superclase. En este caso existen diferentes
tipos de conflictos que pueden ocurrir:
Conflictos de nombres, de valores, por defecto,
de dominio, de restricciones.
Herencia múltiple

 Aparecen dos problemas cuando se tiene


herencia múltiple: ¿cómo se tratan las colisiones
de nombres de diferentes superclases? y ¿cómo
se maneja la herencia repetida?
 Las colisiones de nombres pueden aparecer
cuando dos o más superclases diferentes utilizan
el mismo nombre para algún elemento de sus
interfaces, como las variables de instancia o los
métodos.
Herencia múltiple

 Esta es la dificultad fundamental de la herencia


múltiple: las colisiones pueden introducir
ambigüedad en el comportamiento de la
subclase que hereda de forma múltiple.
 El segundo problema es la herencia repetida,
que sucede cuando una clase es un antecesor
de otra por más de una vía. Esta situación se
llama herencia repetida.
Herencia múltiple

 Existen tres enfoques para tratar el problema de


la herencia repetida.
 Primero, se puede tratar la presencia de herencias
repetidas como incorrecta. Este es el enfoque de
Smalltalk y Eiffel.
 Segundo, se puede permitir la duplicación de
superclases, pero requerir el uso de nombres
plenamente calificados para referirse a los miembros
de una copia específica. Este es uno de los enfoques
adoptados por C++.
Herencia múltiple

 Tercero, se pueden tratar las referencias múltiples a


la misma clase como denotando a la misma clase.
Este es el enfoque de C++ cuando la superclase
repetida se introduce como una clase base virtual. En
este enfoque, el grafo de herencias se allana, se
eliminan las clases duplicadas y la jerarquía
resultante se resuelve mediante herencia múltiple.
Herencia múltiple

 La herencia múltiple se sobreutiliza a menudo.


Por ejemplo, un caramelo de algodón es un tipo
de caramelo, pero evidentemente no es un tipo
de algodón. Una vez más, se aplica la piedra de
toque de la herencia: si B no es un tipo de A,
entonces B no debería heredar de A.
Frecuentemente, pueden reducirse tramas de
herencia múltiple mal formadas a una sola
superclase más la agregación de las otras clases
por parte de la subclase.
Un ejemplo de Herencia múltiple

Elemento
Elemento
asegurable con
interés
Bienes

Cuenta Valores
bancaria Bienes
Inmuebles

Cuenta Libreta Acciones Bonos


Anulación/sustitución (overriding)

 Si una propiedad heredada de una superclase se


define nuevamente en la subclase, entonces la
definición realizada es la utilizada en esa
subclase.
Herencia múltiple en C++

class derivada:[public | private | protected] base1,


[public | private | protected] base2
{

};
Herencia múltiple en C++

class A {
protected:
int datos;
public:
void func( ) { }
};
class B:public A {

};
Herencia múltiple en C++

class C:public A
{

};

class D:public B, public C


{

};
Herencia múltiple en C++

int main(void)
{
D d;
// d.func( ) provoca error “Member is ambiguos”
d.B::func( );
}
Herencia repetida en C++ (Por omisión)

class B { class D2:public B {


protected: protected:
int x; …
… };
};
class D1:public B { class Z:public D1,public D2
protected: {
… …
}; };
Herencia repetida en C++ (Por omisión)

B B

D1 D2

Z
Herencia repetida en C++ (Por omisión)

 En este caso, la clase B se presenta dos veces


en la lista de las clases base de Z. El compilador
generará dos copias de la clase base duplicada.
Es decir, Z hereda x dos veces de B: una a
través de D1 y de nuevo a través de D2.
Herencia repetida en C++ (uso de clases
base virtuales)

class B { class D2:virtual public B {


protected: protected:
int x; …
… };
};
class D1:virtual public B { class Z:public D1, public
protected: D2 {
… …
}; };
Herencia repetida en C++ (uso de clases
base virtuales)

D1 D2

Z
Herencia repetida en C++ (uso de clases
base virtuales)

 Se puede forzar al compilador para que genere


sólo una copia de cualquier clase base repetida
utilizando la palabra reservada virtual. En este
caso, la clase B se denomina clase base virtual.
 El tipo de derivación anterior muestra que sólo
existe una copia de los datos correspondientes
(x) a la clase B, en Z; por consiguiente, se
resuelve cualquier ambigüedad.
Clases abstractas

 Es una clase que no puede existir en la realidad


(no se puede instanciar), pero es una
construcción conceptual útil.
 Las subclases de clases abstractas sí se
instancian.
 Una clase abstracta actúa como un depósito de
métodos y atributos compartidos para las
subclases de nivel inmediatamente inferior.
Clases abstractas

 Un tipo especial de clases abstractas son las


clases aditivas. Una clase aditiva se diseña para
mezclarla con otras clases (usando herencia
múltiple) con el fin de producir nuevas
subclases.
 Una clase aditiva es sintácticamente idéntica a
una clase normal, pero su intención es distinta.
El propósito de tal clase es únicamente añadir
funciones a otras clases.
Clases abstractas en C++

 En C++ una clase abstracta tiene al menos una


función miembro que se declara pero no se
define. Estas funciones se conocen como
funciones virtuales. Debido a que una clase
abstracta tiene al menos una función que no se
puede llamar, no puede ser instanciada.
 Si una clase tiene todas sus funciones miembro
como virtuales, se dice que es una clase base
virtual pura.
Funciones virtuales en C++

 Las funciones virtuales permiten que en la


superclase se declare un método virtual, sin
implementarlo. La implementación real del
método se realiza en las subclases.
 Funciones virtuales puras son funciones
virtuales cuya declaración no está seguida por
una definición. Una función virtual pura es una
función inline cuyo cuerpo se define como cero,
es decir “no hace nada”.
Funciones virtuales en C++

 Las funciones virtuales son diferentes de


funciones vacías (funciones cuyo cuerpo no
contiene ninguna sentencia), dado que el
compilador las maneja de modo diferente. La
diferencia entre una función virtual pura y una
función virtual vacía es:
virtual int FuncionVirtualVacia(int numero) {}
virtual int FuncionVirtualPura(int numero) = 0;
Funciones virtuales en C++

 Desde un punto de vista semántico, la diferencia


reside en el hecho de que una función pura no
se puede llamar; si eso sucede, el compilador
emitirá un mensaje de error. Las funciones
virtuales puras declaran, dentro de una clase
abstracta, aquellas funciones cuya definición se
pospone a alguna clase derivada. Una clase que
declara funciones postergadas se convierte en
una clase abstracta.
Funciones virtuales en C++

 Para manejar funciones miembro virtuales, la


mayoría de las implantaciones de C++ usan el
concepto de vtable o tabla de métodos virtuales,
que se define para cada objeto que requiera
selección polimórfica cuando el objeto se crea (y
por tanto se fija la clase del objeto). Esta tabla
suele constar de una lista de apuntadores a
funciones virtuales.
Funciones virtuales en C++

 Estudios de Stroustrup sugieren que una


llamada a función virtual es aproximadamente
igual de eficiente que una llamada a función
normal. En presencia de herencia simple, una
llamada a función virtual requiere sólo tres o
cuatro referencias a memoria más que una
llamada a función normal; la herencia múltiple
añade sólo alrededor de cinco o seis referencias
a memoria.
Reglas para clases abstractas en C++

 Una clase abstracta debe tener al menos una


función virtual.
 Una clase abstracta no se puede utilizar como
un tipo de argumento o como un tipo de retorno
de función.
 Un tipo abstracto no se puede utilizar en una
conversión explícita.
 No se puede declarar una instancia de una clase
abstracta.
Reglas para clases abstractas en C++

 Se puede declarar un puntero o referencia a una


clase abstracta. En otras palabras, una clase
abstracta sólo se puede utilizar a través de
punteros.
 Si una clase derivada de una clase abstracta no
define todas las funciones virtuales de la clase
base, la clase derivada es también una clase
abstracta
Ligadura tardía

 Los lenguajes no orientados a objetos soportan


ligadura temprana o anterior. Esto significa que
el compilador genera una llamada a un nombre
específico de función y el enlazador (linker)
resuelve la llamada a la dirección absoluta del
código que se ha de ejecutar.
 En POO, cuando se envía un mensaje a un
objeto, el código que se llama no se determina
hasta el momento de ejecución.
Ligadura tardía

 El compilador inserta un segmento especial de


código en lugar de la llamada absoluta. Este
código calcula la dirección en tiempo de
ejecución utilizando información almacenada en
el objeto.
Ligadura tardía en C++

 En C++ la ligadura por defecto es estática, y


cuando se utiliza la declaración virtual se utiliza
ligadura dinámica. En C++, siempre que se
omite el especificador virtual, se supone que
las referencias se resuelven en tiempo de
compilación.
 Un uso común de las funciones virtuales es la
declaración de clases abstractas y la
implementación del polimorfismo.
Ligadura tardía en C++

class figura {
public:
virtual double CalcularArea(void) const;
virtual void Dibujar(void) const;
};
Ligadura tardía en C++

class circulo:public figura {


double xc, yc;
double radio;
public:
virtual double CalcularArea(void) const;
virtual void Dibujar(void) const;
};
Ligadura tardía en C++

virtual double circulo::CalcularArea(void) const {


return(PI * radio * radio);
}

virtual void circulo::Dibujar(void) const {



}
Ligadura tardía en C++

figura* s[10]; // apuntadores a 10 objetos figuras


int i, numfiguras = 10;
// crea figuras y almacena punteros en array “s”

// dibujar las figuras
for(i = 0;i < numfiguras;i++)
s[ i ]->Dibujar( );
Ligadura tardía en C++

 En este caso se produce ligadura dinámica; el


compilador C++ no puede determinar cuál es la
implementación específica de la función
Dibujar( ) que se ha de llamar.
 Aquí logramos polimorfismo mediante un array
de elementos que se refieren a objetos de
diferentes clases.
Genericidad

 Es la propiedad que garantiza que un código


puede correr independientemente del tipo de
datos asociado con él.
 En C++, se usan clases parametrizadas
(mediante plantillas o templates).
 Estos elementos genéricos se diseñan con
parámetros formales, que se instanciarán con
parámetros reales.
Genericidad en C++.
Plantillas de funciones

template <declaraciones-parámeros plantilla>


declaración-o definición-funcion

template <class T> T &f(T parámetro) {



}
template <class T> T f(int a,T b) {

}
Genericidad en C++.
Plantillas de funciones

template <class T> T f(T a,T b) {



}

template <class T1,class T2> T1 f(T1 a,T2 b) {



}
Genericidad en C++.
Plantillas de funciones

#ifndef _ _INMIN_H
#define _ _INMIN_H // Evitar múltiples #include
template <class T> T min(T a,T b) {
if(a <= b)
return a;
else
return b;
}
#endif
Genericidad en C++.
Plantillas de funciones

 Es necesario declarar un prototipo por cada uso


de la plantilla.

int min(const int a,const int b);


char min(const char a,const char b);
double min(const double a,const double b);
Genericidad en C++.
Plantillas de funciones

main( ) {
int e1 = 100, e2 = 200;
double d1 = 3.141592, d2 = 2.718283;
char c1 = ‘B’, c2 = ‘W’;
cout << “min(e1,e2) es igual a “ << min(e1,e2);
cout << “min(d1,d2) es igual a “ << min(d1,d2);
cout << “min(c1,c2) es igual a “ << min(c1,c2);
return 0;
}
Genericidad en C++.
Plantillas de clases

 Las plantillas de clases permiten definir clases


genéricas que pueden manipular diferentes tipos
de datos. Una aplicación importante es la
implementación de contenedores, clases que
contienen objetos de un tipo de datos.

template <class nombretipo> clase tipop {



}
Genericidad en C++.
Plantillas de clases

template <class T> class Pila {


T datos[50];
int nElementos;
public:
Pila( ):nElementos(0) { }
void Meter(T elem);
T Sacar( );
int Numero( );
int Vacia( );
}
Genericidad en C++.
Plantillas de clases

Pila <int> pila_ent; // una pila de enteros


Pila <float> pila_real; // una pila de flotantes
template <class elem,int tamano> class cola {
int tamano;

public:
cola(int n);
int vacia( );
...
}
Genericidad en C++.
Plantillas de clases

Cola <int,2048> a;
Cola <char,512> b;
Cola <char,1024> c;
Cola <char,512 * 2> d;
 Dos nombres de clases plantillas se refieren a
las mismas clases, sólo si los nombres de
plantillas son idénticos y sus argumentos tienen
valores idénticos. En consecuencia, sólo las
variables c y d tienen los mismos tipos.
Persistencia

 La persistencia es la propiedad por la que su


existencia trasciende el tiempo (es decir, el
objeto continúa existiendo después de que su
creador deja de existir) y/o el espacio (es decir,
la posición del objeto varía con respecto al
espacio de direcciones en el que fue creado).
Persistencia

 Un objeto tendrá alguna de estas persistencias:


 Resultados transitorios en la evaluación de
expresiones.
 Variables locales en la activación de procedimientos.
 Variables propias, variables globales y elementos del
heap.
 Datos que existen entre ejecuciones de un programa.
 Datos que existen entre varias versiones de un
programa.
 Datos que sobreviven al programa.
Persistencia

 Los lenguajes de programación tradicionales


suelen tratar solamente los tres primeros tipos
de persistencia de objetos; la persistencia de los
tres últimos tipos pertenece típicamente al
dominio de la tecnología de bases de datos.
 La introducción del concepto de persistencia en
el modelo de objetos da lugar a la aparición de
bases de datos orientadas a objetos.
Concurrencia

 La concurrencia permite a diferentes objetos


actuar al mismo tiempo.
 La concurrencia es la propiedad que distingue
un objeto activo (tiene un hilo separado de
control) de uno que no está activo.
Excepciones

 Las excepciones son anomalías (condiciones de


error no esperadas), como división por cero,
desbordamientos, argumentos o resultados
fuera de rango, apuntadores no legales, índices
de arrays fuera de rango, no existencia de
archivos, etc.
 Normalmente, las excepciones suspenden la
ejecución del programa, emitiendo el sistema
mensajes de error.
Excepciones

 Un invariante es una condición booleana cuyo


valor de verdad debe mantenerse. Para
cualquier operación asociada con un objeto, es
necesario definir precondiciones (invariantes
asumidos por la operación) y postcondiciones
(invariantes satisfechos por la operación). La
violación de un invariante rompe el contrato
asociado con una abstracción. Una excepción es
una indicación de que se no se ha satisfecho (o
no puede satisfacerse) algún invariante.
Excepciones

 Las excepciones síncronas suceden en un


tiempo o momento predecible, así, un error
producido por un índice de un array fuera de su
rango válido sólo se produce cuando se ejecuta
una sentencia en la que se utiliza el índice.
 Las excepciones asíncronas se producen por
sucesos fuera del control del programa. Por
consiguiente, el programa no puede anticipar su
ocurrencia.
Excepciones

 Un invariante es una condición booleana cuyo


valor de verdad debe mantenerse. Para
cualquier operación asociada con un objeto, es
necesario definir precondiciones (invariantes
asumidos por la operación) y postcondiciones
(invariantes satisfechos por la operación). La
violación de un invariante rompe el contrato
asociado con una abstracción. Una excepción es
una indicación de que se no se ha satisfecho (o
no puede satisfacerse) algún invariante.
Excepciones en C++

 El mecanismo de manejo de excepciones en C+


+ sólo contempla excepciones síncronas.
 Cuando un programa detecta una excepción, se
notifica al resto del sistema levantando (raising)
o lanzando (throwing) una excepción. En alguna
parte del programa existe un código que maneja
o captura (catch) la excepción.
Excepciones en C++

 El modelo del mecanismo de excepciones de C+


+ se basa en el concepto de salto no local, se
implementa con las palabras reservadas throw,
try y catch, y se basa en los siguientes
conceptos:
Excepciones en C++

 Se detecta una excepción, el programa lanza o


levanta (throws). El lanzamiento de una
excepción hace que el programa realice un salto
no local antes de continuar la ejecución. La
sentencia throw realiza esta tarea.
 La excepción se maneja (captura) mediante
manejadores de excepciones (handlers). Los
manejadores comienzan con la palabra catch y
se declaran al final de un bloque try.
Excepciones en C++

Un ejemplo de excepciones. La fórmula general.

En raices.h
enum error_raices(no_raices_reales,coeficientes_a_cero);
void raices(float a,float b,float c,float &r1, float &r2)
throw(error_raices);
Excepciones en C++

#include “raices.h”

void raices(float a,float b,float c,float &r1,float &r2)


throw(error_raices) {
float discr; // discriminante
if((b * b) < (4 * a * c))
throw no_raices_reales;
if(a == 0)
throw coeficiente_a_cero;
discr = sqrt((b * b) - (4 * a * c);
Excepciones en C++

r1 = (-b - discr) / (2 * a);


r2 = (-b + discr) / (2 * a);
}

main( ) {
float a, b, c, r1, r2;
// Fijar valores para a, b, y c
try {
raices(a, b, c, r1, r2);
}
Excepciones en C++

catch (error e) {
switch(e) {
case no_raices_reales:
cout << “Ninguna raíz real”; break;
case coeficiente_a_cero:
cout << “Primer coeficiente cero”;
break;
}
}
}
Categorías de objetos

 Cosas tangibles.
 Roles o papeles jugados o representados por
personas.
 Organizaciones (empresa, división, equipo…).
 Incidentes (sucesos, eventos u ocurrencias,
tales como vuelo, accidente, llamado a un
servicio…).
 Especificaciones.
Categorías de objetos

 Interacciones (implican generalmente una


transacción o contrato y relacionan dos o más
objetos).
 Lugares.
Clasificación de lenguajes orientados a
objetos

 Basados en Objetos. Soportan objetos. Es decir,


disponen de componentes caracterizados por un
conjunto de operaciones (comportamiento) y un
estado. No existe herencia.
 Basados en clases. Soportan objetos y clases.
Una clase de un objeto se construye con un
interfaz que especifica las operaciones posibles
y un cuerpo que implementa dichas
operaciones.
Clasificación de lenguajes orientados a
objetos

 Orientados a objetos. Además de objetos y


clases ofrecen mecanismos de herencia entre
clases.
Otra clasificación de lenguajes
orientados a objetos

 Lenguajes orientados a objetos puros. Soportan


en su totalidad el paradigma de orientación a
objetos. Smalltalk, Eiffel, Simula.
 Lenguajes orientados a objetos híbridos.
Soportan en su totalidad el paradigma de
orientación a objetos, sobre una base de
lenguaje estructurado. C++, Delphi, Java.
Primer taller de C++

 Implantación de un conjunto. Un conjunto es


una colección no ordenada de objetos. Usando
el constructor de clases, nos gustaría definir
conjunto como un nuevo tipo de datos. Para
mayor sencillez, nos restringiremos a conjuntos
de enteros con un número finito de elementos.
Dada esta restricción, se puede implantar un
conjunto como un arreglo estático de enteros.
También tenemos que registrar el número de
elementos en el conjunto (su cardinalidad).
Segundo taller de C++

 Una tabla de símbolos es una colección de símbolos y


sus atributos. Para simplificar, supondremos que un
símbolo sólo tiene un atributo (un valor entero). Una
forma popular de implantación de las tablas de símbolos
consiste en usar una técnica de dispersión y enlace. La
tabla de símbolos consta de n espacios (de 0 a n - 1).
Se aplica una función de dispersión a cada símbolo para
decidir en cual espacio debe almacenarse. Los símbolos
que tengan la misma dirección de dispersión se
almacenan en el mismo espacio y se arreglan como una
lista ligada.
Tercer taller de C++

 Modifique la clase conjunto del primer taller,


para que:
 Se haga mediante sobrecarga de operadores.
 Sea independiente de tipos (mediante el uso
de plantilla).
 Maneje excepciones.
Metodologías de
Análisis y Diseño Orientados a Objetos

 UML
 Booch
 Coad/Yourdon
 OMT (Rambaugh et al)
 Tom Demarco
 James Martin
 Otras 300 metodologías.
Criterios de calidad del diseño OO

 Acoplamiento. La medida de la fuerza de la


asociación establecida por una conexión entre
un módulo y otro. El acoplamiento fuerte
complica un sistema porque los módulos son
más difíciles de comprender, cambiar o corregir
por sí mismos si están muy interrelacionados
con otros módulos. La complejidad puede
reducirse diseñando sistemas con los
acoplamientos más débiles posibles entre los
módulos.
Criterios de calidad del diseño OO

 Cohesión. Mide el grado de conectividad entre


los elementos de un sólo módulo (y para OO,
una sola clase u objeto). La forma más deseable
es la cohesión funcional, en la cual los
elementos de una clase o módulo trabajan todos
juntos para proporcionar algún comportamiento
bien delimitado. Lo menos deseable es cohesión
por coincidencia, en la que se incluyen en la
misma clase o módulo abstracciones sin ninguna
relación.
Criterios de calidad del diseño OO

 Suficiencia. Por suficiente quiere decirse que la


clase o módulo captura suficientes
características de la abstracción como para
permitir una interacción significativa y eficiente.
Lo contrario produce componentes inútiles.
Criterios de calidad del diseño OO

 Compleción. Por completo, quiere decirse que el


interfaz de la clase o módulo captura todas las
características significativas de la abstracción.
Mientras la suficiencia implica un interfaz
mínimo, un interfaz completo es aquel que
cubre todos los aspectos de la abstracción. Una
clase o módulo completo es aquel cuyo interfaz
es suficientemente general para ser utilizable de
forma común por cualquier cliente.
Criterios de calidad del diseño OO

 Ser primitivo. Las operaciones primitivas son


aquellas que pueden implantarse eficientemente
sólo si tienen acceso a la representación
subyacente de la abstracción. Una operación
que podría implantarse sobre operaciones
primitivas existentes, pero a un coste de
recursos computacionales significativamente
mayor, es también candidata para su inclusión
como operación primitiva.
Clasificación

 La identificación de clases y objetos es la parte


más difícil del diseño orientado a objetos.
 Históricamente, sólo han existido tres
aproximaciones generales a la clasificación:
 Categorización clásica.
 Agrupamiento conceptual.
 Teoría de prototipos.
Clasificación

 Categorización clásica. Todas las entidades que


tienen una determinada propiedad o colección
de propiedades en común forman una categoría.
Tales propiedades son necesarias y suficientes
para definir la categoría. Por ejemplo, las
personas casadas constituyen una categoría: o
se está casado o no se está.
Clasificación

 Agrupamiento conceptual. En este enfoque, las


clases (agrupaciones de entidades) se generan
formulando primero descripciones conceptuales
de estas clases y clasificando entonces las
entidades de acuerdo con las descripciones. Por
ejemplo, se puede establecer un concepto como
una canción de amor. Así, el agrupamiento
conceptual representa más bien un
agrupamiento probabilístico de los objetos.
Clasificación

 Teoría de prototipos. Una categoría como juego no


encaja en el molde clásico, porque no hay propiedades
comunes compartidas por todos los juegos. Aunque no
hay una sola colección de propiedades que compartan
todos los juegos, la categoría de los juegos está unida
por parecidos familiares. Esta es la razón por la que el
enfoque se denomina teoría de prototipos: una clase de
objetos se representa por un objeto prototípico, y se
considera un objeto como un miembro de esta clase si y
sólo si se parece a este prototipo de forma significativa.
Clasificación

 Según nuestra experiencia, identificamos las clases y


objetos en primer lugar de acuerdo con las propiedades
relevantes para nuestro dominio particular. Aquí se hace
hincapié en la identificación de las estructuras y
comportamiento que son parte del vocabulario del
espacio del problema. Si este enfoque fracasas en la
producción de una estructura de clases satisfactoria, hay
que pasar a considerar la agrupación de objetos por
conceptos. Aquí se concentra la atención en el
comportamiento de los objetos que colaboran. Si ambos
intentos fallan al capturar nuestra comprensión del ...
Clasificación

… dominio del problema, entonces se considera la


clasificación por asociación, a través de la cual las
agrupaciones de objetos se definen según el grado en el
que cada uno se parece a algún objeto prototípico.
Abstracciones clave

 Una abstracción clave es una clase u objeto que


forma parte del vocabulario del dominio del
problema. El valor principal que tiene la
identificación de tales abstracciones es que dan
unos límites al problema; enfatizan las cosas
que están en el sistema y, por tanto, son
relevantes para el diseño, y suprimen las cosas
que están fuera del sistema y, por tanto, son
superfluas.
Abstracciones clave

 Una abstracción clave es una clase u objeto que


forma parte del vocabulario del dominio del
problema. El valor principal que tiene la
identificación de tales abstracciones es que dan
unos límites al problema; enfatizan las cosas
que están en el sistema y, por tanto, son
relevantes para el diseño, y suprimen las cosas
que están fuera del sistema y, por tanto, son
superfluas.
Abstracciones clave

 Una vez que se identifica determinada


abstracción clave como candidata, hay que
evaluarla. Frecuentemente, hay que
preguntarse: ¿Cómo se crean los objetos de
esta clase? ¿Pueden los objetos de esta clase
copiarse y/o destruirse? ¿Qué operaciones
pueden hacerse en esos objetos?
Abstracciones clave

 Si no hay buenas respuestas a estas preguntas,


el concepto probablemente no estaba limpio
desde el principio, y podría ser una buena idea
pensar un poquito más sobre el problema y la
solución propuesta en lugar de empezar
inmediatamente a codificar alrededor de los
problemas.
Mecanismos

 Mientras el diseño de una clase incorpora el


conocimiento de cómo se comportan los objetos
individuales, un mecanismo es una decisión de
diseño sobre como cooperan colecciones de
objetos. Los mecanismos representan así
patrones de comportamiento.
Mecanismos

 Los mecanismos representan decisiones de diseño


estratégicas. Estas decisiones deben tomarse
explícitamente; de otro modo se acabará por tener
una muchedumbre de objetos que prácticamente no
cooperan, todos ellos presionando y empujando
para hacer su trabajo con poca consideración hacia
los demás objetos. Los programas más elegantes,
compactos y rápidos incorporan mecanismo
cuidadosamente discurridos.
Mecanismos

 En el extremo superior de los mecanismos están los


marcos de referencia. Son colecciones de clases que
ofrecen un conjunto de servicios para un dominio
particular; un marco de referencia exporta así una
serie de clases y mecanismos individuales que los
clientes pueden utilizar o adaptar. La MFC y la OWL
son marcos de referencia para construir
aplicaciones según los estándares de interfaces de
usuario de windows.
Tareas del análisis

 Durante el análisis, deben plantearse las


siguientes cuestiones principales:
 ¿Cuál es el comportamiento que se desea del
sistema?
 ¿Cuáles son las misiones y responsabilidades
de los objetos que llevan a cabo este
comportamiento?
Tareas del diseño

 Durante el diseño, deben plantearse las


siguientes cuestiones principales relativas a la
arquitectura del sistema:
 ¿Qué clases existen, y cómo se relacionan
estas clases? (Diagramas de clases).
 ¿Qué mecanismos se utilizan para regular la
forma en que los objetos colaboran?
(Diagramas de objetos).
Tareas del diseño

 ¿Dónde debería declararse cada clase y


objeto? (Diagramas de módulos).
 ¿A qué procesador debería asignarse un
proceso, y para un procesador dado, cómo
deberían planificarse sus múltiples procesos?
(Diagramas de procesos).
 Estos cuatro diagramas son fuertemente
estáticos.
Tareas del diseño

 Podemos expresar la semántica dinámica de un


problema o su implantación mediante:
 Diagramas de transición de estados.
 Diagramas de interacción.

L.I. M.S.I. Sergio Ellerbracke


Tareas del diseño

 Esta notación es especialmente aplicable a un


enfoque incremental e iterativo del desarrollo.
Uno no crea un diagrama y luego se aleja de él,
tratándolo como un artefacto sagrado e
inmutable. Antes bien, estos diagramas
evolucionan durante el proceso de diseño a
medida que se toman nuevas decisiones de
diseño y se establece un detalle mayor.
Diagramas de clases

 Se utiliza un diagrama de clases para mostrar la


existencia de clases y sus relaciones.
 Los dos elementos esenciales de un diagrama
de clases son las clases y sus relaciones básicas.
 Las clases se representan con una nube o
mancha amorfa. Se pone el nombre de la clase,
una línea divisoria y algunos atributos y
operaciones.
Diagramas de clases

 Se puede poner un triángulo invertido con la letra A


para indicar que es una clase abstracta, V para
virtual, S para static y F para amigas.
 Relaciones de clase.
 Una línea para asociación.
 Una línea terminada con flecha para herencia.
 Una línea terminada con círculo relleno para agregación. Si
es agregación física se coloca un cuadrado en el otro
extremo.
 Una línea terminada con círculo hueco para uso.
Diagramas de clases

 Se puede anotar la cardinalidad en los extremos


de la línea.
 Se pueden anotar restricciones encerrándolas
entre llaves, adyacente a la clase o relación a la
que se aplica la restricción.
Diagrama de transición de estados

 Un diagrama de transición de estados se utiliza


para mostrar el espacio de estados de una clase
determinada, los eventos que provocan una
transición de un estado a otro, y las acciones
que resultan de ese cambio de estado.
 Los dos elementos esenciales de un diagrama
de transición de estados son los estados y las
transiciones entre estados.
Diagrama de transición de estados

 El estado de un objeto representa los resultados


acumulados de su comportamiento. Para
representarlo se utiliza un rectángulo vertical con
las esquinas redondeadas.
 Un evento es algún suceso que puede causar un
cambio de estado en un sistema. Este cambio se
llama transición de estado.
 Una transición de estado se representa con una
flecha con los nombres evento/acción.
Diagrama de transición de estados

 Una acción es una operación que, a todos los


efectos prácticos, ocupa un tiempo cero. Una
acción denota típicamente la invocación de un
método, el disparo de otro evento, o el inicio o
parada de una actividad. Una actividad, por
contra, es alguna operación que lleva algún
tiempo completar.
Diagrama de transición de estados

 En todo diagrama de transición de estados debe


haber exactamente un estado de partida por
defecto, que se designa escribiendo una
transición sin etiqueta al estado desde un icono
especial, que aparece como un círculo relleno.
 En general, un estado debería documentar los
eventos a los que ignora intencionalmente.
Diagrama de transición de estados

 El orden de evaluación en transiciones de


estado condicionales es importante. Dado el
estado s con la transición T sobre el evento E
con condición c y acción A, se aplica el siguiente
orden:
 Ocurre el evento E.
 Se evalúa la condición c.
 Si c se evalúa como cierta, entonces se
dispara T y se invoca la acción A.
Diagramas de objetos

 Un diagrama de objetos se utiliza para mostrar la


existencia de objetos y sus relaciones en el diseño
lógico de un sistema. Dicho de otro modo, un
diagrama de objetos representa una instantánea en
el tiempo de una corriente (de otro modo
transitoria) de eventos sobre una cierta
configuración de objetos.
 Los dos elementos esenciales de un diagrama de
objetos son los objetos y sus relaciones.
Diagramas de objetos

 Los objetos se representan con la misma nube


que las clases, aunque el contorno es continuo.
 Las relaciones se representan con flechas, que
apunta al objeto servidor.
 Todas las clases tienen implícitamente una
asociación consigo mismas, y por tanto es
posible que un objeto se envíe un mensaje a sí
mismo.
Diagramas de objetos

 La invocación de una operación es el tipo de


mensaje más común. Se pueden incluir
parámetros actuales que encajan con el
prototipo de la operación.
 Para mostrar un orden explícito de los eventos,
opcionalmente se puede poner como prefijo un
número de secuencia (comenzando en el uno)
en una invocación de operación o en un
despacho de evento.
Diagramas de objetos

 Para ciertas aplicaciones críticas respecto al


tiempo, es importante trazar escenarios en
términos de tiempo exacto relativo al comienzo
del escenario.
Diagramas de interacción

 Un diagrama de interacciones se usa para


realizar una traza de la ejecución de un
escenario en el mismo contexto que un
diagrama de objetos. Realmente, en gran parte
un diagrama de interacción es simplemente otra
forma de representar un diagrama de objetos.
Diagramas de interacción

 Los diagramas de interacción son frecuentemente


mejores que los diagramas de objetos para capturar
la semántica de los escenarios en un momento
temprano del ciclo de vida del desarrollo.
 A medida que avanza el desarrollo y se refina la
estructura de clases del sistema, tiende a
desplazarse el énfasis hacia los diagramas de
objetos, cuya semántica es más expresiva.
Diagramas de módulos

 Se utiliza un diagrama de módulos para mostrar la


asignación de clases y objetos a módulos en el
diseño físico de un sistema.
 La única relación que puede darse entre dos
módulos es una dependencia de compilación,
representada por una línea dirigida que apunta al
módulo respecto al cual existe la dependencia. En
C++ se indica una dependencia de compilación con
#include.
Diagramas de módulos

 Los subsistemas representan agrupaciones de


módulos relacionados lógicamente. Un
subsistema es un agregado que contiene otros
módulos y otros subsistemas. Cada módulo del
sistema debe habitar en un sólo subsistema o
en el nivel superior del sistema.
Diagramas de módulos

 En la práctica, un sistema grande tiene un


diagrama de módulos del nivel superior, que
consta de los subsistemas al nivel más alto de
abstracción. Mediante este diagrama un
desarrollador llega a comprender la arquitectura
física general de un sistema.
Diagrama de procesos

 Se usa un diagrama de procesos para mostrar la


asignación de procesos a procesadores en el
diseño físico de un sistema.
 Los tres elementos esenciales de un diagrama
de procesos son los procesadores, los
dispositivos y sus conexiones.
El microproceso de desarrollo

 El microproceso representa las actividades


diarias del desarrollador individual o de un
equipo pequeño de ellos.
 En el microproceso, las fases tradicionales del
análisis y diseño son intencionadamente
borrosas, y el proceso está bajo un control
oportunista.
El microproceso de desarrollo

 Identificar las clases y objetos a un nivel dado


de abstracción.
 Identificar la semántica de estas clases y
objetos.
 Identificar las relaciones entre estas clases y
objetos.
 Especificar el interfaz y después la
implementación de estas clases y objetos.
Identificar las clases y objetos a un nivel
dado de abstracción.

 El propósito de esta etapa es establecer los


límites del problema que se maneja.
 Aquí se descubren aquellas abstracciones que
forman el vocabulario del dominio del problema,
decidiendo que es de interés y que no lo es.
 El producto central de este paso es un
diccionario de datos que se actualiza a medida
que avanza el desarrollo.
Identificar las clases y objetos a un nivel
dado de abstracción.

 Hay tres beneficios esenciales que se derivan de la creación


de un diccionario de datos.
 El mantenimiento de un diccionario ayuda a establecer un
vocabulario común y consistente que puede utilizarse a lo
largo del proyecto.
 Puede servir como un vehículo para hojear a través de los
elementos del proyecto de manera arbitraria.
 Un diccionario de datos permite a los arquitectos adoptar
una visión global del proyecto, que puede llevar al
descubrimiento de aspectos comunes que de otra forma
se soslayarían.
Identificar las clases y objetos a un nivel
dado de abstracción.

 Se completa con éxito esta fase cuando se


dispone de un diccionario de datos
razonablemente estable.
 Es suficiente tener un diccionario que contenga
un conjunto amplio de abstracciones, con
nombres consistentes y con una separación
clara de responsabilidades.
Identificación de la semántica de clases
y objetos.

 El propósito de esta etapa es establecer el


comportamiento y atributos de cada abstracción
que se identifica en la fase previa.
 Aquí se refinan las abstracciones candidatas
mediante una distribución inteligente y medible de
responsabilidades.
 Un producto de esta etapa es un refinamiento del
diccionario de datos, por el cual se asignan
inicialmente responsabilidades a cada abstracción.
Identificación de la semántica de clases
y objetos.

 Otro producto sería el interfaz de cada clase (en C+


+, las partes public y protected).
 Además de estos productos, se pueden producir
también diagramas de objetos y diagramas de
interacción. Estos diagramas sirven para capturar
formalmente la narración de cada escenario, y
reflejar así una distribución explícita de
responsabilidades entre objetos que colaboran.
Identificación de la semántica de clases
y objetos.

 En esta fase es importante centrarse en el


comportamiento, no en la estructura. Los atributos
representan elementos estructurales, y así existe el
peligro, especialmente en fases tempranas del análisis,
de vincular decisiones de implantación demasiado
pronto requiriendo la presencia de ciertos atributos. Los
atributos deberían identificarse en este momento sólo
en la medida en que sean esenciales para construir un
modelo conceptual del escenario.
Identificación de la semántica de clases
y objetos.

 Es importante evitar buscar relaciones de


herencia demasiado pronto: la introducción de
la herencia prematuramente suele llevar a
pérdidas de integridad de tipos.
 Se completa con éxito esta fase cuando para
cada abstracción se tiene un conjunto de
responsabilidades y/o operaciones
razonablemente suficiente, primitivo y completo.
Identificación de las relaciones entre
clases y objetos.

 El propósito de esta etapa es consolidar las


fronteras y reconocer los colaboradores de cada
abstracción que se identificó previamente.
 En este paso se especifican las relaciones entre
clases y objetos (incluyendo relaciones de
herencia y agregación).
 Los productos principales de este paso son los
diagramas de clases, de objetos y de módulos.
Identificación de las relaciones entre
clases y objetos.

 En esta etapa se actualiza también el diccionario de


datos, para reflejar la asignación de clases y objetos
a categorías y de módulos a subsistemas.
 Existen tres actividades asociadas con este paso:
 La especificación de las asociaciones.
 La identificación de varias colaboraciones.
 El refinamiento de las asociaciones.
Identificación de las relaciones entre
clases y objetos.

 Se completa con éxito esta fase cuando se ha


especificado la semántica y las relaciones entre
ciertas abstracciones interesantes de forma
suficiente como para servir a la implantación.
 Las medidas de bondad comprenden la
cohesión, el acoplamiento y la completud.
Implementación de clases y objetos.

 El propósito de esta actividad es crear representaciones


tangibles de las abstracciones.
 El dejar al final esta etapa es intencional: el
microproceso se centra primero en el comportamiento, y
aplaza las decisiones sobre la representación hasta el
momento más tardío posible. Así se evitan decisiones de
implantación prematuras que pueden arruinar
oportunidades para arquitecturas más pequeñas o
simples, y también ofrece la libertad de cambiar las
representaciones según se necesite por razones de
eficiencia.
Implementación de clases y objetos.

 Existe una actividad central a esta etapa: la


selección de estructuras y algoritmos que
suministran la semántica de las abstracciones.
 Mientras las primeras tres fases del
microproceso se centran en la vista externa de
las abstracciones, este paso se centra en la vista
interna.
Implementación de clases y objetos.

 Se completa esta fase cuando se tiene un


modelo ejecutable o casi ejecutable de las
abstracciones.
 La medida de bondad principal de esta fase es
la simplicidad. Las implantaciones complejas,
difíciles o ineficientes son una indicación de que
la propia abstracción tiene carencias, o de que
se ha elegido una representación pobre.
El macroproceso del desarrollo

 Sirve como el marco de referencia para


controlar el microproceso.
 El macroproceso representa las actividades del
equipo de desarrollo completo en una escala de
semanas o meses cada vez.
El macroproceso del desarrollo

 El macroproceso es principalmente del interés


de la dirección técnica del equipo de desarrollo.
Por esta razón, el macroproceso se centra en el
riesgo y la visión arquitectónica, los dos
elementos gestionables que tienen el mayor
impacto en las fechas, calidad y completud.
El macroproceso del desarrollo

 El macroproceso tiene las siguientes etapas:


 Establecer los requisitos centrales para el software
(conceptualización).
 Desarrollar un modelo del comportamiento deseado
del sistema (análisis).
 Crear una arquitectura de la implementación (diseño)
 Transformar la implementación mediante
refinamientos sucesivos (evolución).
 Gestionar la evolución posventa o postentrega
(mantenimiento).
Establecer los requisitos centrales para
el software (conceptualización).

 Los prototipos son los productos primarios de la


conceptualización.
 Sirven para poner a prueba los conceptos,
mediante productos rápidos y sucios.
 Entre más grande sea un sistema es más
importante construir un prototipo, para poder
visualizarlo.
 Todos los prototipos están destinados a ser
desechados.
Establecer los requisitos centrales para
el software (conceptualización).

 Es importante que se establezcan criterios


explícitos para la terminación de un prototipo.
 Hay que ser muy prudente con los riesgos (que
el prototipo, por supuesto, evade).
Modelo del comportamiento deseado del
sistema (análisis).

 El análisis debe dar lugar a una declaración de


lo que hace el sistema, no de cómo lo hace.
 En el análisis, se busca modelar el mundo
identificando las clases y los objetos (y sus
papeles, responsabilidades y colaboraciones)
que forman el vocabulario del dominio del
problema.
Modelo del comportamiento deseado del
sistema (análisis).

 En el análisis se encuentran los puntos


funcionales, que denotan los comportamientos
de un sistema observables exteriormente y
comprobables. Representan una medida de la
complejidad.
 La salida de un análisis es una descripción de la
función del sistema, junto con declaraciones
sobre la eficiencia y los recursos requeridos.
Modelo del comportamiento deseado del
sistema (análisis).

 En desarrollo orientado a objetos se capturan


esas descripciones mediante escenarios, donde
cada escenario denota algún punto funcional
particular.
 Se usan escenarios principales para ilustrar los
comportamientos clave, y los escenarios
secundarios para mostrar comportamiento que
se da bajo condiciones excepcionales.
Modelo del comportamiento deseado del
sistema (análisis).

 Un producto secundario del análisis es una


evaluación de riesgos que identifica las áreas
conocidas de riesgo técnico que pueden
impactar en el proceso de diseño. El enfrentarse
pronto a los riesgos en el proceso de desarrollo
hace mucho más fácil el realizar concesiones
arquitectónicas en fases posteriores.
Modelo del comportamiento deseado del
sistema (análisis).

 Se completa con éxito esta fase cuando se han


desarrollado y rubricado escenarios para todos
los comportamientos fundamentales del
sistema.
 Las medidas de bondad incluyen completud y
simplicidad.
Crear una arquitectura de la
implementación (diseño).

 Hay dos productos principales del diseño: una


descripción de la arquitectura y descripciones de
políticas tácticas comunes.
 A nivel arquitectónico, lo importante es mostrar
el agrupamiento de clases en categorías de
clases (arquitectura lógica), y el agrupamiento
de módulos en subsistemas (arquitectura física).
Crear una arquitectura de la
implementación (diseño).

 Las políticas tácticas comunes incluyen a los


mecanismos localizados que aparecen en todo el
sistema (detección y gestión de errores, gestión
de memoria, gestión de almacenamiento de
datos y enfoques generalizados del control).
Crear una arquitectura de la
implementación (diseño).

 Se completa esta fase con éxito cuando se ha


validado la arquitectura mediante un prototipo y
mediante revisión formal.
 La principal medida de bondad es la simplicidad.
Transformar la implementación mediante
refinamientos sucesivos (evolución).

 La evolución de una arquitectura es, en gran


parte, cuestión de intentar satisfacer una serie
de restricciones que compiten, incluyendo
funcionalidad, tiempo y espacio: siempre se está
limitado por una restricción mayor.
 El desarrollo evolutivo se centra en diseñar
primero por funcionalidad y luego por eficacia
local.
Transformar la implementación mediante
refinamientos sucesivos (evolución).

 La producción es un proceso metodológico


controlado de elevar la calidad del producto
hasta el punto en que puede ser expedido.
 El producto principal de la evolución es una
corriente de versiones ejecutables que
representan sucesivos refinamientos a la versión
inicial de la arquitectura.
Transformar la implementación mediante
refinamientos sucesivos (evolución).

 Hay dos actividades en la evolución: la


aplicación del microproceso y la gestión de
cambios.
 La gestión de cambios existe en reconocimiento
a la naturaleza incremental de los objetos. Su
objetivo es el impedir cambios indisciplinados
que puedan corromper la arquitectura
estratégica del sistema.
Transformar la implementación mediante
refinamientos sucesivos (evolución).

 Se ocupa gestión de cambios para:


 Añadir una nueva clase o una nueva
colaboración entre clases.
 Cambiar la implantación de una clase.
 Cambiar la representación de una clase.
 Reorganizar la estructura de clases.
 Cambiar el interfaz de una clase.
Transformar la implementación mediante
refinamientos sucesivos (evolución).

 Se completa con éxito esta fase cuando la


funcionalidad y calidad de las versiones son
suficientes para expedir el producto.
 La medida principal de bondad es por tanto
hasta que grado se satisfacen los puntos
funcionales asignados a cada versión
intermedia, y en qué medida se ha confluido con
las previsiones temporales establecidas durante
la planificación de versiones.
Gestionar la evolución posventa o
postentrega (mantenimiento).

 Se realizan cambios más localizados en el


sistema que en la evolución, a medida que se
añaden nuevos requisitos y se eliminan errores
persistentes.
 Los hitos del mantenimiento implican versiones
de producción continuadas, así como versiones
intermedias de depuración de errores.
Gestionar la evolución posventa o
postentrega (mantenimiento).

 Se sabe que aún se está efectuando el


mantenimiento de un sistema si la arquitectura
sigue siendo flexible al cambio; se sabe que se
ha entrado en la etapa de conservación cuando
la respuesta a nuevas mejoras comienza a
requerir recursos de desarrollo excesivos.

También podría gustarte