La Programación Orientada a Objetos:
Introducción
Prof. Franco Guidi Polanco
Escuela de Ingeniería Industrial
Pontificia Universidad Católica de Valparaíso, Chile
02-06-14
Franco Guidi Polanco (PUCV-EII) 2
De Problemas a Soluciones
“Half the battle is knowing what problem to solve”
Data Structures and Algorithms (A.A. Aho, J.E. Hopcroft & J.D. Ullman)
De http://pbfcomics.com/
02-06-14
Franco Guidi Polanco (PUCV-EII) 3
De Problemas a Soluciones
v Análisis: entender el problema y sus requerimientos
v Diseño: determinar un modelo que nos permita resolver el problema.
v Implementación: determinar la forma de
representar el modelo que describe el problema (y
la solución):
02-06-14
Franco Guidi Polanco (PUCV-EII) 4
Los Requerimientos v Los requerimientos:
§ son incompletos
§ usualmente están equivocados
§ son engañosos (y los usuarios también)
§ no cuentan la historia completa
v Por lo tanto, los requerimientos
siempre cambian
02-06-14
Franco Guidi Polanco (PUCV-EII) 5
El Desarrollo de Proyectos
Lo que propuso el comité de proyecto
Lo que se especificó como requerimiento
Lo que diseñó el analista
Lo que desarrollaron
los programadores Lo que se instaló al usuario
Lo que necesitaba el usuario
1 2 3
4 5 6
02-06-14
Franco Guidi Polanco (PUCV-EII) 6
Metodologías y Modelos
La Ingeniería de Software provee:
v Metodologías de desarrollo.
§ Desarrollo en cascada
§ Proceso Unificado
§ etc.
v Modelos para soportar el desarrollo
§ Especificación estructurada (DFDs, MER, etc.)
§ UML
§ etc.
v Lenguajes para la implementación
§ C, C++
§ Java
§ etc.
Se estudiarán en detalle en curso de Modelamiento
de Sistemas
Antes de la Programación
Orientada a Objetos
02-06-14
Franco Guidi Polanco (PUCV-EII) 8
Divide et Impera: Descomposición Funcional
v “Divide et Impera”
v Descomposición en funciones:
el analista descompone el
problema en una serie de pasos que permiten resolverlo.
v Los pasos son refinados
sucesivamente, hasta llegar a funciones elementales.
v ¿Costo?
02-06-14
Franco Guidi Polanco (PUCV-EII) 9
Descomposición Funcional
...
ingresarDatos(datos);
calcularMedia(datos, media);
calcularDE(datos, de);
mostrarResultados(media, de);
...
procedimiento ingresarDatos(datos:arreglo) { i=0;
mientras i <= 10 hacer { leer datos[i]
i = i + 1;
} }
procedimiento calcularMedia(datos:arreglo, media:float) { i=0;
suma = 0;
mientras i <= 10 hacer
{ suma = suma + datos[i]
i = i + 1;
} media = suma / 10 } ...
02-06-14
Franco Guidi Polanco (PUCV-EII) 10
La Encapsulación como Agrupación de Funciones
v La encapsulación permite la agrupación de ideas
relacionadas en una unidad, la que posteriormente puede ser referida por un solo nombre.
v El concepto surgió en la década del ’40 con la invención de la subrutina: los programadores se dieron cuenta de que un mismo patrón de instrucciones se podía repetir muchas veces en un programa.
02-06-14
Franco Guidi Polanco (PUCV-EII) 11
Descomposición Funcional: Reutilización de Código
. .
i=1 mientras i<=10 hacer
{ si a[i]=10 entonces a[i]=0 i=i+1
} . . i=1
mientras i<=10 hacer
{ si b[i]=10 entonces b[i]=0 i=i+1
} . . i=1
mientras i<=10 hacer
{ si c[i]=10 entonces c[i]=0 i=i+1
} .
. .
HacerCeros(a) . .
. HacerCeros(b) . .
. HacerCeros(c) . .
.
Procedimiento
HacerCeros(x:arreglo) i=1 mientras i<=10 hacer
{ si x[i]=10 entonces x[i]=0 i=i+1
}
Programa con subrutina Programa original
02-06-14
Franco Guidi Polanco (PUCV-EII) 12
Ventajas de Funciones o Subrutinas
v Ahorro de memoria de computador (código fuente de programas más corto).
v Código fuente más “entendible”: una subrutina agrupa un conjunto de instrucciones en un “concepto” que una
persona puede considerar y manejar como una sola idea (en el ejemplo, HacerCeros).
02-06-14
Franco Guidi Polanco (PUCV-EII) 13
Lenguajes de Programación
v Antes de la POO los lenguajes de programación eran procedimentales.
Aproximación:
Imagine
programar en
Java, usando sólo métodos
estáticos, con instancias de clases que no tengan métodos.
NOTA:
NO LO INTENTE
02-06-14
Franco Guidi Polanco (PUCV-EII) 14
ADT
(Abstract Data Type)
Tipo de dato
(No provisto por el lenguaje de programación)
+ Operaciones
Por separado, pero asociadas.
Reutilización antes de la POO: Tipos Abstractos de
Datos
La Programación
Orientada a Objetos
02-06-14
Franco Guidi Polanco (PUCV-EII) 16
La Programación Orientada a Objetos (POO)
v El paradigma de la Orientación a Objetos es sucesor de la descomposición funcional
v Se centra en el concepto de Objeto:
Objeto = Datos + Métodos
v Los objetos:
§ son responsables de si mismos.
§ “saben” de qué tipo son.
§ conocen su propio estado (datos).
§ contienen el código que les permite actuar.
(Definición tradicional)
02-06-14
Franco Guidi Polanco (PUCV-EII) 17
POO versus Descomposición Funcional
v El modelo de programación funcional mantenía centralizadas las responsabilidades:
§ Una cena en la cual un garzón pide a cada comensal lo que se servirá, y luego les trae los platos solicitados.
v El modelo de programación OO provee delegación de
responsabilidades:
§ Una cena en la cual a los comensales se les indica la distribución del buffet.
Ellos se sirven a su propio gusto.
02-06-14
Franco Guidi Polanco (PUCV-EII) 18
¿Cómo identificar Objetos?
v En problemas pequeños una técnica sencilla se basa en la identificación de sustantivos y verbos :
§ Los sustantivos pueden ser objetos
§ Los verbos pueden ser métodos
02-06-14
Franco Guidi Polanco (PUCV-EII) 19
Objetos
v Una buena forma de concebir un objeto es pensar en él como una entidad con responsabilidades. Las
responsabilidades determinan el comportamiento del objeto.
v Debe existir una forma para comunicar a un objeto qué debe hacer.
v Esta comunicación se logra por medio del conjunto de métodos que un objeto ofrece para que otros puedan invocar.
v El conjunto de estos métodos se denomina interfaz pública del objeto.
02-06-14
Franco Guidi Polanco (PUCV-EII) 20
Visión de Objetos
v Martin Fowler identifica tres perspectivas para describir los objetos:
§ Nivel conceptual: un objeto es un conjunto de responsabilidades.
§ Nivel especificación: un objeto es un conjunto de métodos
(comportamientos), que pueden ser invocados por otros objetos o por si mismos.
§ Nivel implementación: un objeto es código y datos, e interacciones
computaconales entre ellos.
Martin Fowler
02-06-14
Franco Guidi Polanco (PUCV-EII) 21
Perspectivas para Describir Sistemas OO
Nivel Conceptual
Nivel Especificación
Nivel Implementación Análisis
Diseño (Lenguajes de modelamiento e.g. UML)
Codificación (Lenguajes de
programación e.g. Java, C++, C#, etc.)
02-06-14
Franco Guidi Polanco (PUCV-EII) 22
Perspectivas para Describir Sistemas OO: Ejemplo
v Sistema de docencia, que mantiene datos de alumnos y registra sus inscripciones en cursos.
Nivel Conceptual
Nivel Especificación
Nivel Implementación
02-06-14
Franco Guidi Polanco (PUCV-EII) 23
Ejemplo: Nivel Conceptual
Responsabilidades:
v Alumno:
§ Mantener datos de un alumno (rol y nombre). Debe validar el rol del alumno.
v Curso:
§ Mantener datos de un curso (nombre)
§ Mantener la lista de los alumnos que se inscriben en el curso, verificando que estos no se repitan al momento de agregarlos.
§ Retornar alumnos, buscándolos por rol del alumno.
02-06-14
Franco Guidi Polanco (PUCV-EII) 24
Ejemplo: Nivel Especificación
v Clase Alumno:
§ public setRol(numero: int, verificador: int)
§ public setNombre( nombre: String)
§ public getRol(): String
§ public getNombre(): String
v Clase Curso:
§ public setNombre(nombre: String)
§ public addAlumno(alumno:Alumno):boolean
§ public getAlumno(rol: String):Alumno
02-06-14
Franco Guidi Polanco (PUCV-EII) 25
Ejemplo: Nivel Implementación
public class Alumno{
private String rol, nombre;
public void setRol(int numero, int verificador){
if( sumaDigitos(numero) == verificador ) this.rol = rol +”-”+verificador;
}
public void setNombre(Sting nombre){
this.nombre = nombre;
}
public String getRol(){
return rol;
}
public String getNombre(){
return nombre;
}
private int sumaDigitos(int numero){
...
} }
public class Curso{
private String nombre;
private Vector alumnos;
public void setNombre(String nombre){
this.nombre = nombre;
}
public boolean addAlumno(Alumno alumno){
if( getAlumno( alumno.getRol() )== null ){
alumnos.add( alumno );
return true;
}
return false;
}
public Alumno getAlumno(String rol){
...
} }
02-06-14
Franco Guidi Polanco (PUCV-EII) 26
!
¿Es necesario tomar precauciones, si el análisis inicial está bien hecho?
“All systems change during their life cycles. This must be borne in mind when developing systems
expected to last longer than the first version.”
Ivar Jacobson.
“Object Oriented Software Engineering a Use Case Driven Approach”, Addison Wesley, 1992,
02-06-14
Franco Guidi Polanco (PUCV-EII) 27
POO y Encapsulación
v Tradicionalmente se asocia a “ocultamiento de datos” (estado) de un objeto.
v Sin embargo, se refiere además a ocultamiento de:
§ implementación de métodos
§ tipo, clases derivadas
§ detalles de diseño
§ reglas de instanciación
02-06-14
Franco Guidi Polanco (PUCV-EII) 28
Encapsulación como Ocultamiento de Datos v Ejemplo:
public class Punto{
private int coordA, coordB;
public void setXY(int x, int y){
coordA = x;
coordB = y;
}
public int getX(){
return coordA;
}
public int getY(){
return coordB;
} }
El “contexto” de la clase Punto no
tiene visibilidad de cómo ésta
almacena sus datos.
Consecuencia:
Puede modificarse el conjunto de
variables de la clase Punto, sin que esto afecte su contexto.
02-06-14
Franco Guidi Polanco (PUCV-EII) 29
Encapsulación en la Implementación de Métodos v Ejemplo:
public class Angle{
private double angle;
public void setAngle(double a){
angle = a;
}
public double getSin(){
// Cálculo mediante series de // Taylor
...
} }
El “contexto” de la clase Angle no
tiene visibilidad del algoritmo de cálculo del seno del ángulo
Consecuencia:
Puede modificarse la implementación del método sin
afectar al contexto.
02-06-14
Franco Guidi Polanco (PUCV-EII) 30
Encapsulación del Tipo v Ejemplo
Figura +dibujar() +rellenar() +ocultar()
Rombo +dibujar() +rellenar() +ocultar()
Cuadrado +dibujar() +rellenar() +ocultar()
Círculo +dibujar() +rellenar() +ocultar() Contexto
El “contexto” de las figuras no tiene visibilidad de cuál de ellas está
exactamente utilizando.
Consecuencia:
El contexto puede implementar una lógica común para utilizar cualquiera de las figuras (o cualquier nueva subclase).
02-06-14
Franco Guidi Polanco (PUCV-EII) 31
Encapsulación de Detalles de Diseño v Ejemplo
Banco +recibirCliente() +atenderSiguiente()
Cola +agregar() +sacar()
Cajero +atender() Contexto
El “contexto” de la clase Banco no
tiene visibilidad de las clases que
soportan sus operaciones.
Consecuencia:
Puede modificarse la “arquitectura”
del Banco sin
afectar el contexto.
02-06-14
Franco Guidi Polanco (PUCV-EII) 32
Encapsulación de Reglas de Instanciación
public class LeonardoDaVinci{
private static LeonardoDaVinci instance;
private LeonardoDaVinci(){}
public static LeonardoDaVinci getLeonardo(){
if( instance == null )
instance = new LeonardoDaVinci();
}
return instance;
}
public String writeName(){
return “odranoeL”;
} ...
}
El “contexto” de la clase no tiene
visibilidad de la lógica de
instanciación de objetos
LeonardoDaVinci.
¿Consecuencias?
v Ejemplo
02-06-14
Franco Guidi Polanco (PUCV-EII) 33
Encapsulación y Diseño
v Ante especificaciones variables y sistemas que evolucionan...
... ¿podemos lograr un buen diseño?
v Sí, encontrando qué cosas pueden variar en
el diseño y
encapsulándolas ?
02-06-14
Franco Guidi Polanco (PUCV-EII) 34
Encapsulación y Diseño
v Muchos patrones de diseño (soluciones a problemas comunes de diseño) utilizan la encapsulación de tipos para crear capas de separación entre objetos.
v La separación se crea asignando referencias a clases abstractas o interfaces.
v Esto permite modificar alguno de los
“lados” de la capa de separación, sin afectar a la otra.
02-06-14
Franco Guidi Polanco (PUCV-EII) 35
El principio “abierto-cerrado”
v En el libro Object Oriented Software Construction de 1988, Bertrand Meyer propuso el “Open-Closed Principle” (OCP)
v “Las entidades de software (clases, módulos, funciones, etc.) deberían estar abiertos para extensión y
cerrados para modificaciones.”
v En otras palabras, el software debe ser diseñado para soportar la adición de nuevas funcionalidades, sin que esto comporte modificaciones en
aquellas existentes.
v No es siempre posible seguir completamente este principio.
Bertrand Meyer
02-06-14
Franco Guidi Polanco (PUCV-EII) 36
El principio “abierto-cerrado”
v Síntomas de un mal diseño (cuando no se cumple este principio):
§ Al modificar un módulo de software, los cambios se propagan a otros módulos.
v Por lo tanto:
§ Se deben diseñar módulos que nunca cambiarán.
§ Si los requerimientos cambian, se debe extender el comportamiento de tales módulos, agregando nuevo código, no modificando aquél existente.
v La base de este principio está en los conceptos de:
§ Abstracción
§ Polimorfismo
02-06-14
Franco Guidi Polanco (PUCV-EII) 37
El principio “abierto-cerrado”
v Los módulos desarrollados bajo este principio tienen dos características:
§ Están “abiertos para extensión”: el comportamiento del módulo puede ser extendido, a fin de lograr un nuevo comportamiento, impusto por nuevos requerimientos de la misma o de otra aplicación.
§ Están “cerrados para modificaciones”: el código fuente de un módulo existente no debe ser alterado.
02-06-14
Franco Guidi Polanco (PUCV-EII) 38
El principio “abierto-cerrado”
v Aquí no se respeta el principio:
Dibujador
Héroe Enemigo
pinta(Personaje p) pintaHéroe(Héroe p)
pintaEnemigo(Enemigo p)
Personaje
public void pinta(Personaje p){
if( seRequierePintar ){
if( p instance of Héroe)
pintaHeroe((Héroe) p);
else if(p instance of Enemigo) pintaEnemigo((Enemigo) p);
} … }
v ¿Qué pasa si es necesario agregar un nuevo tipo de personaje (ej. un Mago)?
02-06-14
Franco Guidi Polanco (PUCV-EII) 39
El principio “abierto-cerrado”
v Aquí si es respetado el principio:
Dibujador
Héroe Enemigo
pinta(Personaje p)
Personaje
public void pinta(Personaje p){
if( seRequierePintar ) p.pinta();
… }
pinta() pinta()
v Es posible agregar nuevos objetos a pintar (agregando una subclase de Personaje), sin modificar el código ya existente
pinta()
02-06-14
Franco Guidi Polanco (PUCV-EII) 40
Consecuencias del principio “abierto–cerrado”
v “Regla” de diseño: Establecer visibilidad “privada”
a variables de instancia.
v Los conceptos de abstracción y polimorfismo del principio abierto-cerrado están asociados a la
especificación de jerarquías de herencia.
v ¿Hay algo que decir respecto de las jerarquías de
herencia? (Veamos el principio de sustitución de
Liskov)
02-06-14
Franco Guidi Polanco (PUCV-EII) 41
El principio de sustitución de Liskov
v Barbara Liskov, en “Data Abstraction and Hierarchy”, SIGPLAN Notices, 23, 5 (May 1988) estableció lo que hoy se conoce como el “Liskov
Substitution Principle” (LSP):
v “Las funciones que utilizan punteros o referencias a clases de base, deben ser capaces de utilizar subclases de éstas, sin necesidad de conocerlas”
v Esto es:
§ Cualquier propiedad que sea cierta para una súperclase, debe serlo también para sus
subclases.
§ Un cliente de una clase debe funcionar
correctamente con cualquier subclase de ésta
última. Barbara Liskov
02-06-14
Franco Guidi Polanco (PUCV-EII) 42
El principio de sustitución de Liskov v Ejemplo:
Programador
Aéreo Terrestre
Vehículo
Bus Tren
v La clase Programador debe funcionar correctamente con la clase Vehículo, o con cualquier subclase de ella
02-06-14
Franco Guidi Polanco (PUCV-EII) 43
El principio de sustitución de Liskov
v El LSP se violaría ante la presencia de situaciones como la siguiente:
Programador
Aéreo Terrestre
Vehículo
Bus Tren
public void programa(Vehículo v){
if( v instance of Bus ){
throw new InvalidException();
else
programaAutomático(v);
} }
programa(vehiculo v)
02-06-14
Franco Guidi Polanco (PUCV-EII) 44
El principio de “inversión de dependencia”
v El “Dependency Inversion Principle” (DIP) establece cómo implementar los objetivos enunciados por el OCP y el LSP.
v “Los módulos de alto nivel no deberían depender de los módulos de bajo nivel. Ambos deberían depender de abstracciones.
v Las abstracciones no deberían depender de detalles. Los detalles deberían depender de abstracciones.”
Klee Kandinsky
02-06-14
Franco Guidi Polanco (PUCV-EII) 45
El principio de “inversión de dependencia”
v Propone la estategia de depender de abstracciones (interfaces, funciones abstractas y/o clases
abstractas), en vez de depender de funciones y clases concretas.
02-06-14
Franco Guidi Polanco (PUCV-EII) 46
El principio de “inversión de dependencia”
v Aquí no se cumple el DIP:
Copiador
LectorTeclado EscritorDisco
public void copiar(LectorTeclado l, EscritorDisco e){
while( !l.eof){
byte b = l.leer();
e.escribir( b );
} }
v La lógica general del copiador tiene
“cableada” la acción sobre un LectorTeclado y un EscritorDisco
v ¿Posibilidad de reutilizar el código del Copiador?
02-06-14
Franco Guidi Polanco (PUCV-EII) 47
El principio de “inversión de dependencia”
v Aquí sí se cumple:
Lector Escritor Copiador
LectorTeclado EscritorDisco
public void copiar(Lector l, Escritor e){
while( !l.eof){
byte b = l.leer();
e.escribir( b );
} }
02-06-14
Franco Guidi Polanco (PUCV-EII) 48
Después de la OO... ¿qué?
v Los objetos ofrecen una interfaz pública por medio de la cual otros objetos invocan sus comportamientos.
v Los objetos son inherentemente reactivos: su
comportamiento es gatillado por la acción (externa) de otro objeto.
v Nuevo paradigma: agentes de software.
v Los agentes de software son unidades de software con objetivos y responsabilidades.
v Los agentes de software exhiben comportamiento proactivo:
un agente actúa por cuenta propia sobre el ambiente y sobre otros agentes para alcanzar sus objetivos.