Tema 9: Programación Orientada a Objetos
Referencias
• Capítulo 9 PLP
• Guia rápida sobre clases y objetos en la guía de Racket
Indice de hoy
• Ideas fundamentales de la POO • POO en Racket
• Objetos y clases • Herencia
Programación Orientada a Objetos
• La Programación Orientada a Objetos es un paradigma de programación que explota en los 80 pero nace a partir de ideas a finales de los 60 y 70
• Smalltalk como lenguaje paradigmática de POO; desarrollado en Xerox Park a finales de los 70
• Alan Kay es el diseñador del Smalltalk y el creador el término “Object-Oriented”
• Artículo de Alan Kay:“The Early History of Smalltalk”,ACM SIGPLAN, March 1993
• Lenguajes POO: Smalltalk, Java, Ruby, Python, C#, C++ (si se usa con prudencia)
Alan Key
• “I invented the term Object-Oriented and I can tell you I did not have C++ in mind.”
• “Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term objects for this topic
because it gets many people to focus on the lesser idea.The big idea is messaging.”
• “Smalltalk's design--and existence--is due to the insight that everything we can describe can be represented by the recursive composition of a single kind of behavioral building block that hides its combination of state and process inside itself and can be dealt with only through the exchange of messages.”
¿Interesados en SmallTalk?
• Visitar:
• http://www.squeak.org/
• http://swiki.agro.uba.ar/small_land • http://www.squeakland.org
El comienzo de la POO y de las interfaces de
usuario: Ivan Sutherland y Sketchpad
Del paradigma imperativo al OO
• Programación procedural: estado abstracto (tipos de datos y barrera de abstracción) + funciones
• Siguiente paso: agrupar estado y funciones en una única entidad • Los objetos son estas entidades
Algunas características POO
• Objetos (creados/instanciados en tiempo de ejecución) y clases (plantillas estáticas/tiempo de compilación)
• Los objetos agrupan estado y conducta (métodos) Los métodos se invocan mediante mensajes
• Dispatch dinámico: cuando una operación es invocada sobre un objeto, el propio objeto determina qué código se ejecuta. Dos objetos con la misma interfaz pueden tener implementaciones distintas.
• Herencia: las clases se pueden definir utilizando otras clases como plantillas y modificando sus métodos y/o variables de instancia.
Objeto
• Un objeto contiene un estado (atributos o variables de instancia) y un conjunto de funciones (métodos) que implementan las funcionalidades soportadas
• Al ejecutar un método, el objeto modifica su estado
Clase
• Una clase es la plantilla que sirve para definir los objetos
• En una clase se define los elementos que componen el objeto (sus atributos o campos) y sus métodos
• En una clase también se pueden definir variables (variables de clase) compartidas por todos los objetos de esa clase
POO en Scheme
(require (lib "class.ss")) (define persona%
(class object%
(init-field nombre nif) (field (apellidos null)
(fecha-nacimiento null)) (define/public (di-hola)
(printf "Hola, soy ~a~%" nombre)) (super-new)))
(define p1 (new persona% (nif '212121232) (nombre "Pepito"))) (send p1 di-hola)
Sintaxis class
(class <super-clase>
(init-field <var1> ... <varn>) (field (<var1> <valor1>) ... (<varn> <valorn>))
(define/public (<metodo> <args>) <cuerpo>)
(super-new <args>)
Sintaxis new y paso de mensajes
(new <clase> (<arg1> <val1>) ... (<argn> <valn>))
Herencia
• Al definir una clase hay que indicar la superclase que extiende • La superclase por defecto es object%
• La clase hereda los métodos y atributos de la superclase: los objetos de la clase pueden ejecutar los métodos de la clase y los de la superclase
Invocación
• Todos los campos y métodos definidos en una clase pueden usarse directamente en los métodos de esa clase
• Los métodos de la superclase pueden invocarse desde el propio objeto utilizando (send this <metodo>)
• Los métodos y campos de la superclase pueden incluirse en el ámbito de la clase usando las palabras claves inherit y inherit-fields
Ejemplo clase figura
• Definimos una clase figura% con el campo de inicialización nombre y los campos coord-inf-izq y coord-sup-der. Métodos: draw-bounding-box y los setters necesarios.
• Definimos una clase rectangulo% que extiende figura% con los campos de inicialización pos-xy, alto y ancho. Métodos: draw y area.
Ejemplo clase figura
(define figura%
(class object%
(init-field nombre)
(field (coord-sup-izq null) (coord-inf-der null)) (define/public (get-nombre) nombre) (define/public (set-coords c1 c2) (set! coord-sup-izq c1) (set! coord-inf-der c2)) (define/public (draw-bounding-box)
(let ((c1 coord-sup-izq) (c2 coord-inf-der)) (draw-solid-rect c1
(- (posn-x c2) (posn-x c1))
(- (posn-y c2) (posn-y c1))))) (super-new)))
3 formas de definir la subclase rectangulo
• Ejemplo 1
(define rectangulo% (class figura%
(init-field pos-xy alto ancho) (define/public (area)
(* alto ancho)) (super-new)
(send this set-coords pos-xy (make-posn
(+ (posn-x pos-xy) ancho)
3 formas de definir la subclase rectangulo
• Ejemplo 2
(define rectangulo% (class figura%
(init-field pos-xy alto ancho) (inherit-field
coord-sup-izq coord-inf-der) (define/public (area)
(* alto ancho)) (super-new)
(set! coord-sup-izq pos-xy) (set! coord-inf-der
(make-posn
(+ (posn-x pos-xy) ancho)
3 formas de definir la subclase rectangulo
• Ejemplo 3
(define rectangulo% (class figura%
(init-field pos-xy alto ancho) (inherit set-coords) (define/public (area) (* alto ancho)) (super-new) (set-coords pos-xy (make-posn
(+ (posn-x pos-xy) ancho)
Relaciones entre objetos
• Las variables y parámetros guardan referencias a objetos • Más de una variable puede referenciar al mismo objeto
• En la mayoría de lenguajes OO coexisten objetos y datos primitivos
• La semántica de la asignación en un dato primitivo es de copia y en objeto es de referencia
Relaciones entre objetos
(define persona% (class object%
(init-field nombre)
(field (apellidos null) (fecha-nacimiento null) (amigos null)) (define/public (es-amigo? otro)
;memq comprueba si otro está en amigos usando la igualdad eq? (if (memq otro amigos)
#t #f))
(define/public (añade-amigo otro)
(if (not (es-amigo? otro)) ; tambien es posible llamar a los métodos directamente
(begin
(set! amigos (cons otro amigos)) (send otro añade-amigo this))))
Relaciones entre objetos
(define/public (set-apellidos nuevos-apellidos) (set! apellidos nuevos-apellidos))
(define/public (set-fecha-nacimento fecha) (set! fecha-nacimiento fecha))
(define/public (get-nombre-completo) (if (not (null? apellidos))
(string-append nombre " " apellidos) nombre))
(define/public (di-hola)
(define nombre-completo (send this get-nombre-completo)) (printf "hola, soy ~a~%" nombre-completo))
(super-new)))
(define nadal (new persona% (nombre "Rafa"))) (define federer (new persona% (nombre "Roger"))) (define djokovic (new persona% (nombre "Novak"))) (send nadal añade-amigo federer)
Herencia y polimorfismo
(define mago%
(class persona%
(init-field nombre-pila nivel-conjuro) (field (energia 100) (vida #t))
(inherit-field nombre) (define/public (get-nivel-conjuro) nivel-conjuro) (define/public (get-energia) energia) (define/public (rayo)
(set! energia (- energia 10)) (if (< 0 energia)
(set! vida #f)))
(define/public (lanza-conjuro otro-mago)
(define otro-nombre (send otro-mago get-nombre-completo)) (define nivel-otro (send otro-mago get-nivel-conjuro))
Herencia y polimorfismo
(define gandalf (new mago% (nombre-pila "Gandalf") (nivel-conjuro 100))) (define saruman (new mago% (nombre-pila "Saruman") (nivel-conjuro 90))) (send gandalf lanza-conjuro saruman)
(send saruman lanza-conjuro gandalf)
(define enano% (class persona% (inherit-field nombre) ;; Reescritura de métodos (define/override (di-hola)
(printf "Mmmm.. soy ~a y estoy hambriento!~%" nombre)) (super-new)))
(define frodo (new persona% (nombre "Frodo"))) (send frodo añade-amigo gandalf)
(send frodo saludan-amigos) (send gandalf saludan-amigos)
Interfaz
• Una interfaz define un conjunto de métodos
• Cuando declaramos una clase que implementa una interfaz estamos obligados a implementar todos sus métodos
• Una interfaz no define una implementación (no podemos definir campos en una interfaz)
• Una clase puede implementar más de una interfaz, sin las ambiguedades de la herencia múltiple
Ejemplo clases geométricas
• Clase figura%:
(define figura%
(class object%
(init-field nombre)
(field (coord-sup-izq null) (coord-inf-der null)) (define/public (get-nombre) nombre) (define/public (set-coords c1 c2) (set! coord-sup-izq c1) (set! coord-inf-der c2)) (define/public (print)
(printf "[Figura ~a]\n" nombre)) (define/public (draw-bounding-box)
(let ((c1 coord-sup-izq) (c2 coord-inf-der)) (draw-solid-rect c1
(- (posn-x c2) (posn-x c1))
Ejemplo clases geométricas
• Interfaces dibujable% y printable%
(define dibujable% (interface () draw)) (define printable% (interface () print)) (define circulo%
(class* figura% (dibujable% printable%) ;; por que no da error? ;; dónde está la
;;implementación de print? (init-field centro radio)
(inherit set-coords) (define/public (area)
(* 3.14159 radio radio)) (define/public (draw)
(draw-solid-disk centro radio 'red)) (super-new)
Ejemplo completo (herencia e interfaces): stack
(define i-stack% (interface () push! pop! is-empty?)) (define stack%
(class* object% (i-stack%)
(init-field (name 'stack)) (field (stack null))
(define/public (push! v)
(set! stack (cons v stack))) (define/public (pop!)
(let ((v (car stack)))
(set! stack (cdr stack)) v))
(define/public (is-empty?) (null? stack))
Ejemplo completo (herencia e interfaces): stack
(define fancy-stack% (class stack%
(inherit-field name)
(define/override (push! v)
(super push! (cons 'fancy v))) (super-new))) (define double-stack% (class stack% (inherit push!) (define/public (double-push! v) (push! v) (push! v))
(super-new (name 'double-stack))))
(define safe-stack% (class stack% (inherit is-empty?) (define/override (pop!) (if (is-empty?) #f (super pop!))) (super-new)))
Ejemplo completo (herencia e interfaces): stack
(define i-extended-stack% (interface (i-stack%) size))
(define extended-stack%
(class* safe-stack% (i-extended-stack%)
(inherit-field stack) (define/public (size) (length stack)) (super-new)))