1.48k likes | 1.84k Views
Programación Orientada a Objetos. IMPLEMENTACION LENGUAJES OO. Objetos como Tipo de Datos Abstractos. Los Objetos combinan estados (campos de datos / variables de instancia / miembros de datos / slots) y comportamiento (operaciones / métodos / funciones miembro / funciones) . top. pop.
E N D
Programación Orientada a Objetos IMPLEMENTACION LENGUAJES OO
Objetos como Tipo de Datos Abstractos • Los Objetos combinan estados (campos de datos / variables de instancia / miembros de datos / slots) y comportamiento (operaciones / métodos / funciones miembro / funciones) top pop top pop push push
Objetos como Tipo de Datos Abstractos • Desde fuera, los clientes solo pueden ver el comportamiento del objeto, desde adentro, los métodos proveen el comportamiento a través de modificaciones de estado y de interacción con otros objetos.
Interfase e Implementación • Principio de Parnas para módulos: • Se debe proveer al usuario con toda la información necesaria para utilizar el módulo correctamente y nada más. • Se debe de proveer al implementador con toda la información para completar el módulo y nada más. • Principio de Parnas para objetos: • La definición de una clase debe proveer al usuario de toda la información necesaria para manipular las instancias de la clase correctamente y nada más. • Un método debe tener acceso a toda la información necesaria para llevar a cabo sus responsabilidades y nada más.
Aprendiendo un Lenguaje OO (1) • Definición de Clase • es como una definición de tipo • especifica los datos y el comportamiento (métodos) a ser asociados con los datos • No crea un valor (objeto) • Pueden definirse valores por defecto para los datos. • La visibilidad de los datos y comportamientos puede ser especificado
Aprendiendo un Lenguaje OO (2) • Instanciación de Objetos • Es la creación de una nueva instancia de una clase. Ej.: un valor (objeto) • Se pueden definir valores iniciales para los campos de datos. [Existe confusión en algunos lenguajes con verificación fuerte de tipos donde la instanciación de objetos toma sintácticamente la forma de una declaración] • Mensajes • Tienen un receptor (el objeto al cual se envía el mensaje) • Tiene un selector de mensaje (algún nombre que indica que mensaje se esta enviando • Tiene argumentos.
Aprendiendo un Lenguaje OO (3) • Jerarquía de Clases • Son definidas cuando en la definición de una clase, una o màs clases padres son especificadas (herencia simple o multiple) • Herencia • Es la propiedad por la cual las instancias de una clase hija o subclase pueden acceder tanto a los datos como al comportamiento (métodos) asociados con una clase padre o superclase. • Unión de métodos o búsqueda de método • Es un mecanismo para determinar que método será usado en respuesta a un mensaje enviado
Ejemplo de la Carta 1 • Una carta pertenece a un palo, tiene un valor y un color • Una carta pude estar boca arriba o boca abajo y puede ser volteada de una posición a otra. • Una carta pude ser mostrada o retirada. • Una carta mágica es un tipo especial de carta que puede cambiar su valor
Definición de la Clase “define class” <nombre> <definición datos> <declaración métodos & definiciones> Carta Palo: {brillo, trebol, corazon, espada} Valor: integer BocaArriba: boolean Color: {rojo, negro} Voltear() <algún código> Dibujar(W:window;X,Y:position) <algún código> Borrar() <algún código> “define class” Carta ... ...
Fix Fix Definición de Clase: visibilidad, alcance, protección define class” <nombre> <definición datos> <declaración métodos & definiciones> Carta Palo: {brillo, trebol, corazon, espada} Valor: integer BocaArriba: boolean NrdeCartasenJuego: integer Voltear() Dibujar(W:window;X,Y:position) ... Borrar() Barajar() Priv Priv Priv Class Pub Pub Pub Pub Class Pub
Definición de Clase • Modificadores de Visibilidad para controlar la visibilidad y así la manipulación de los campos de datos y los métodos • Métodos para Setear y Obtener para controlar como los datos son accedidos y modificados • Campos de datos constantes o inmutables para garantizar que no ocurran cambios en ellos. • Campos de datos de clase (variables de clase) que son compartidos entre todas las instancias. • Interfaces e Implementación
Clases y Métodos en C++ (1) • C++ distingue archivos de interfase (extensión .h) y archivos de implementación (extensión .cpp) • El #include puede ser usado para "importar" descripciones de interfaz en los archivos de implementación • Las definiciones de clase se parecen a las definiciones de estructuras pero ambos, datos y métodos son permitidos. • Debido a que los métodos son tratados implemente como tipos especiales de campos, un método y un campo de datos no pueden tener el mismo nombre. • Los métodos con el mismo nombre que la clase son especiales: son los constructores y son usados para crear instancias de la clase.
Clases y Métodos en C++ (2) • La palabra reservada private precede aquellas porciones del código que pueden ser accedidas solo por los métodos de la clase en sí. • La palabra reservada public precede a aquellas porciones de código que pueden ser accedidas por los clientes de la clase. • Debido a que los usuarios de la clase están mayormente interesados en las partes públicas, estas deberían estar primero. • Las descripciones de los miembros privados son dadas para beneficio del compilador solamente. Los clientes no deberían verlas viola el principio de Parnas.
Clases y Métodos en C++ (3) • Un archivo de implementación de una clase de proveer las definiciones de los métodos descritos en el archivo de interfase (a menos que sea un método virtual puro) • Las funciones Inline se proveen para promover el uso de los principios de abstracción y encapsulación al mismo tiempo que se evita la sobrecarga de una llamada a procedimiento. • Las definiciones Inline ocurren también cuando el cuerpo de un método es definido directamente en la definición de clase; esto hace las definiciones de clase más difíciles de leer y algunos compiladores requieren que se listen los miembros privados de datos antes que la interfaz pública.
C++ Carta: Archivo de Interfaz class carta { public: enum palos {brillo, trebol, corazon, espada}; enum colores {rojo, negro}; carta(palos,int); //constructor colores color(); //acceso a atributos bool EstaBocaArriba(); int valor(); palos palo(); void Voltear(); //acciones void Dibujar(window &, int, int); void Borrar(window &, int, int); private: bool BocaArriba; int valordelValor; palos valordelPalo; };
C++ Carta: Archivo de Implementación #include "carta.h" carta ::carta(palos sv ,int rv); { valordelPalo = sv; valordelValor = rv; BocaArriba = true; } inline int carta::valor() { return valordelValor; } colores carta::color() { if (palo()==corazon || palo()==brillo) return rojo; else return negro; } void carta::Voltear() { BocaArriba = ! BocaArriba }
C++ Carta: Archivo Interfaz (bis) class carta { private: bool BocaArriba; const int valordelValor; const palos valordelPalo; public: enum palos {brillo, trebol, corazon, espada}; enum colores {rojo, negro}; carta(palos sv , int rv): valordelPalo(sv), valordelValor (rv) { }; //constructor colores color(); //acceso atributos bool EstaBocaArriba() { return BocaArriba; }; int valor() { return valordelValor; }; palos palo() { return valordelPalo; }; ...
Java • Java no es un dialecto de C++, hay similaridades superficiales, pero las diferencias internas son substanciales. • Java no tiene punteros, referencia, estructuras, uniones, sentencias goto, definición de funciones o sobrecarga de operadores. • Java usa recolección de basura para manejo de memoria, introduce el concepto de interfaces, introduce los paquetes y la visibilidad de paquetes, soporta multihilo y manejo de excepciones. • Java es un lenguaje muy portable debido a que usa una máquina virtual para ejecutarse.
Clases y Métodos en Java • No hay preprocesador, variables globales o tipos de datos enumerados. Los valores simbólicos son creados por declaración e inicialización de un campo de datos con las palabras final y static. • La palabra reservada static usada en los campos de datos indica que solo una copia del campo de datos existe y es compartida por todas las instancias. En un método indica que este existe aún cuando no existan instancias de la clase. Un programa de Java necesita una clase con un método main static. • La implementación de los métodos debe ser proporcionada directamente en la definición de la clase. • Las palabras reservadas public y private son aplicadas individualmente a cada definición de variable o método.
Clase Carta: Java (1) class Carta { final static public int rojo = 0; // valores estáticos final static public int negro = 1; final static public int espada = 0; final static public int corazón = 1; final static public int brillo = 2; final static public int trebol = 3; private boolean bocaArriba; // campos de datos private int valordePalo; private int valordeValor;
Clase Carta: Java (2) Carta (int sv, int rv) // constructor { valordePalo = sv; valordeValor = rv; bocaArriba = true; } public boolean estaBocaArriba() { return bocaArriba; } // acceso atributos public int valor() { return valordeValor; }; public int palo() { return valordePalo; }; public int color() { if (palo() == corazon || palo() == brillo) //acciones return rojo; return negro; } public void voltear() { bocaArriba = ! bocaArriba; } public void dibujar( Graphics g, intx, int y) … }; //clase Carta
CLOS • Common Lisp Object System es un extensión orientada a objetos del lenguaje LISP • CLOS usa un acercamiento funcional al contrario del paso de mensajes para invocar operaciones específicas de las clases • CLOS soporta actualización automática de las instancias cuando cambia la definición de las clase y permite que las instancias se conviertan en instancias de una clase diferente.
CLOS Funciones Genéricas • Asuma que existen las clases racional y complejo y siguen las siguientes definiciones: (defgeneric suma (x y)) (defmethod suma (x y) (+ x y)) (defmethod suma ((x racional) (y racional)) (<cuerpo>)) (defmethod suma ((x complejo) (y complejo)) (<cuerpo>)) • El método ejecutado cuando se llama (suma A B) dependerá de los tipos de A y B, el método es escogido por un proceso que selecciona, ordena y combina los métodos aplicables.
Clases y Métodos en CLOS • El macro defclass define una clase con nombre y retorna un nuevo objeto clase • Una clase CLOS define slots que contienen las instancias de esa clase • Un slot tiene un nombre y puede contener un valor simple; un slot sin un valor es un slot no-unido. • Ambos especificadores de slots y opciones de clase son usados para determinar las características de los slots y crear maneras de manipular el slot • Se puede añadir documentación a los slots y a las clases
Clases y Métodos en CLOS • El especificador :allocation permite distinguir entre slots locales y compartidos. Un slot es local cuando su valor es único para cada instancia individual. Un slot es compartido si es común para todas las instancias de una clase. • El especificador :type permite especificar un tipo para un slot • El especificador :documentation permite añadir documentación al slot
Clases y Métodos en CLOS • Los specificadores :reader, :writer y :accessor crean métodos especiales que permiten leer, escribir o ambos los valores de un slot. • El especificador :initarg introduce una palabra clave que puede ser usada mientras se instancia una clase para inicializar un slot. • Los especificadores :initform permite especificar un valor por defecto para un slot. • La opción de clase :documentation permite añadir documentación a una clase • La opción de clase :default-args permite especificar valores por defecto para los slots de una clase usando los initarg.
Clases y Métodos en CLOS • La macro defmethod define un método y devuelve un objeto método. • La clase en la que un método es definido se menciona explicitamente • Los métodos pueden ser calificados como :before, :after o :around • Cuando no existe una función genérica con el mismo nombre esta se genera automáticamente. • Los argumentos deben ser compatibles sino se produce un error • Cuando no contienen un objeto método con el mismo especializador y calificador un nuevo objeto método es agregado. • Cuando este contiene un objeto método con el mismo especializador y calificador, el método viejo es remplazado.
Clase Carta: CLOS (1) (defclass carta () ((bocaArriba :initarg :bocaArriba :accessor estaBocaArriba :allocation :instance :initform 'true) (palo :initarg :palo :reader palo :allocation :instance) (valor :initarg :valor :reader valor :allocation :instance) (dueno :allocation :class :reader dueno :initform 'vivi)) (:documentation “una clase de ejemplo"))
Clase Carta: CLOS(2) (defclass carta () ((bocaArriba :initarg :bocaArriba :accessor estaBocaArriba :allocation :instance :initform 'true) (palo :initarg :palo :reader palo :allocation :instance) (valor :initarg :valor :reader valor :allocation :instance) (:default-initargs :suit ‘espada :rank 1)) (defmethod voltear ((c carta)) (setf (estaBocaArriba c) (not (estaBocaArriba c)))) (defmethod color ((c carta)) (if (or (eq (palo c) ‘corazon) (eq (palo c) ‘brillo)) ‘rojo ‘negro))
Instanciación e Inicialización “make-instance” <clase> <valores iniciales> (una Carta) palo: brillo valor: 9 bocaArriba: false color: rojo “make instance” Carta brillo, 9, false “make instance” Carta espada, 4, true (otra Carta) palo: espada valor: 4 bocaArriba: true color: negro
Paso de Mensajes “send message” <objeto> <selector mensaje> < argumentos> (una Carta) palo: brillo Valor: 9 bocaArriba: false voltear() true Barajar() Carta
Creación e Inicialización • Alocación en Stack versus Heap • Variables Automáticas versus Dinámicas • Creación Implícita versus Explicita • Recuperación de Memoria Manual versus Recolección de Basura Automática • Punteros Explícitos versus Implícitos • Creación Inmutable versus Asignación simple de instancias a variables o slots. • Inicialización y valores por defecto; Constructores • Recuperación de Memoria; Destructores
Paso de Mensajes • El paso de mensajes es el proceso dinámico de pedir a un objeto que realice una acción. • Los mensajes tienen un receptor (el objeto al cual se envía el mensaje), un selector del mensaje (el nombre del mensaje) y argumentos. • La búsqueda de método es un mecanismo para determinar el método a utilizar en respuesta a un mensaje recibido. • La diferencia entre lenguajes estáticos y dinámicos es importante para el paso de mensajes.
Creación e Inicialización en C++ • Existen variables automáticas y dinámicas • Una variable automática es asignada al espacio cuando se introduce el bloque que contiene la declaración. La declaración no necesita estar al comienzo del bloque. La instancia que se convierte en el valor de la variable es creada implícitamente y el espacio es reservado en la pila. El espacio es liberado una vez que el control sale del bloque. • Una variable dinámica implica el uso de manera explícita de puntero y una creación de instancia explícita a través del operador new. Se separa espacio en el heap y debe ser luego liberado a través del operador delete.
Creación e Inicialización en C++ • La inicialización en C++ se facilita a través del uso de constructores; estos son métodos que son invocados implícitamente cada vez que un objeto de una clase es creado ya sea implícita como explícitamente. • Los mecanismos de sobrecarga de operadores en C++ soporta el uso de múltiples constructores en una clase para permitir múltiples estilos de inicialización. • Hay soporte sintáctico para el uso de constructores en la declaración de variables automáticas y en el operador new. • Los constructores pueden pasar argumentos a constructores de objetos encapsulados.
Creación e Inicialización en C++ • Cuando el cuerpo del constructor es un conjunto simple de asignaciones a variables de instancia, este puede ser remplazado por cláusulas de inicialización en el encabezado de la función. • Los valores pueden ser declarados como inmutables a través de la palabra reservada const. Las variables de instancia que son declaradas como constantes deben ser inicializadas con una cláusula de inicialización porque no pueden ser blanco de una sentencia de asignación. • La limpieza de memoria en C++ esta facilitada a través del uso de destructores; estos métodos son llamados implícitamente cada vez que un objeto de la clase es borrado ya sea implícita como explícitamente.
Paso de Mensajes en C++ • Un método en C++ es llamado una función miembro; pasar un mensaje a un objeto es conocido como la invocación de una función miembro. • La sintaxis es similar a aquella usada para acceder miembros de datos con los argumentos en una lista. Se debe usar paréntesis así no haya argumentos. • La seudo-variable this esta asociada con un puntero a la clase receptora del mensaje; esta puede ser usada para enviar mensajes subsecuentes al receptor o para pasar el receptor como un argumento a otro mensaje.
Ejemplo de Carta: C++ carta lacarta(brillo, 9) carta * micarta micarta = new carta(corazon, 9) lacarta.dibujar(win1,10,10) if(lacarta.estaBocaArriba()) micarta->dibujar(win1,10,10) if(micarta->estaBocaArriba()) colores carta::color() { if (this->palo()==corazon || this->palo()==brillo) return rojo; else return negro; } void carta::haceralgo (int i) { hacerotracosa(this,i); }
Creación e Inicialización en Java • Java utiliza recolección de basura automática. El programador no tiene que tratar con el mantenimiento de memoria. • Todas las variables de algún tipo de objeto son inicialmente asignadas el valor null. • Los objetos son creados con el operador new; se alocaciona espacio en el heap, los punteros son siempre implícitos. • La sintaxis del operador new requiere el uso de paréntesis aún cuando los argumentos no son necesarios. • Los constructores en Java, no soportan cláusulas de inicialización. • Los constructores en Java pueden llamar a otros constructores en la misma clase usando la palabra this; esto permite factorizar el comportamiento común.
Creación e Inicialización en Java • El destructor en Java es representado por la función finalize. Esta función es llmada cada vez que se recupera la memoria a través del recolector de basura. • El operador new en Java puede tomar como argumento una cadena. Esto permite determinar en tiempo de ejecución el tipo del objeto que será alocacionado dado que la cadena puede ser construida con una expresión. • Las variables de instancia que no pueden ser reasignadas pueden ser creadas a través de la palabra reservada final.
Paso de Mensajes en Java • La única diferencia notable con C++ radica en el hecho de que las variables declaradas como un tipo de clase tienen los objetos como valor (el puntero esta implícito); esto es también el caso de la seudo-variable this carta micarta = new carta(corazon, 9) micarta.dibujar(win1,10,10) if(micarta.estaBocaArriba()) colores carta::color() { if (this.palo()==corazon || this.palo()==brillo) return rojo; else return negro; }
Creación e Inicialización en CLOS • CLOS usa un mecanismo de recolección de basura. • La función genérica make-instance es usada para crear e inicializar nuevas instancias de una clase. • El primer argumento para make-instance es el nombre del objeto clase, el resto de argumentos forman la lista de inicialización. • Los argumentos de inicialización que son proporcionados son combinados con las inicializaciones por defecto para los slots que no tienen. • Almacenamiento para las instancias se reserva en el heap, los slots se llenan con los valores y una instancia anónima del objeto se devuelve.
Creación e Inicialización en CLOS • La inicialización en CLOS es muy sofisticada: • El mismo nombrer initarg puede ocurrir en múltiples slots • Un slot puede tener múltiples nombre initarg • Dos nombres initarg que son sinónimos pueden ocurrir en la misma inicialización. • Se pueden escribir métodos para controlar explicitamente la inicialización. Initargs can be used to supply arguments to methods • La inicialización en CLOS no soo ocurre cuando se crea una nueva instancia sino que : • Cuando se reinicializa una instancia. • Cuando se actualiza una instanaic cuando su clase se actualiza • Cuando se actualiza una instancia para cambiar su clase a otra clase.
Paso de Mensajes en CLOS • Los métodos son definidos relativamente a una clase específica. Para cada conjunto de métodos con un nombre dado hay una función genérica. Qué método será llamado cuando se reciba un mensaje dependerá de los argumentos de clase pasados a la función genérica • Sintácticamente un mensaje enviado en una llamada funcional. El receptor del mensaje es el primer argumento de la llamada a función y pude ser usado naturalmente para enviar mensajes subsecuentes al receptor o pasar el receptor como un argumento de un mensaje subsiguiente.
Ejemplo de Carta: CLOS (1) ? (setf test (make-instance 'carta :palo ‘espada :valor 9)) #<CARD #x22F0A0E> ? (valor test) 9 ? (palo test) ESPADA ? (owner test) VIVI ?(estaBocaArriba test) T ?(setf (valor test) 10) > Error: Undefined function SETF::|COMMON-LISP-USER::RANK| called with arguments (10 #<CARD #x550B06E>) .
Ejemplo de Carta: CLOS(2) ?(slot-value test ‘valor) 9 ? (setf (slot-value test ‘valor) 10) 10 ? (valor test) 10 ? (estaBocaArriba test) T ? (voltear test) NIL ? (estaBocaArriba test) NIL ? (color test) NEGRO
Ejemplo de Carta: CLOS(3) ? (setf other (make-instance 'carta :palo ‘espada :valor 2 :bocaArriba 'false)) #<CARD #x22F289E> ? (valor other) 2 ? (bocaArriba other) FALSE ? (owner other) VIVI
Jerarquía de Clases Carta Palo: {brillo, trebol, corazon, espada} Valor: integer Voltear() <algun código> “define class” <nombre> <superclases> <definición datos> <definición métodos &declaraciones> “define class” Carta Mágica Carta ... ... Carta Mágica Cambiar-Valor(R: integer) <algun código>
Herencia • Herencia es la propiedad por las cuales las instancias de una clase hija o una subclases pueden acceder tanto a los datos como al comportamiento (métodos) asociados con una clase padre o superclase. • La Herencia se puede ver como Extensión: el comportamiento y datos asociados con la clase hija es mayor al conjunto de comportamientos y datos asociados con la clase padre.
Herencia • La Herencia se puede ver como Especialización: la clase hija es más especializada o restringida que la clase padre. • La Herencia es transitiva • Las subclases pueden sobreescribir el comportamiento de la superclase