View on GitHub

POO

Curso Medio de POO

Temario

  1. ¿Qué es la P.O.O?
  2. Características de la P.O.O
  3. Algunos Lenguajes Orientados a Objetos
  4. Ventajas y desventajas de este paradigma
  5. Ejemplos
  6. Ejercicios

¿Qué es la Programación Orientada a Objetos?

Que es la P.O.O

¿Qué es un objeto?

Objeto

Ahora hablemos un poco que es la Programación Orientada a Objetos o P.O.O(abrevación), es muy parecida a la programación estructurada, es decir aquí se rescataran muchos conceptos que ya vimos en el capítulo anterior.

Algo de historia

El primer lenguaje P.O.O se llamo simula 67 y fue desarollado por Krinsten Nygaard y Ole-Johan, la invención de este lenguaje era simplificar la gran cantidad de código que se usaba en el paradigma estructurado.

Aun que este paradigma empezo a ganar mucha popularidad cuando en la decada de 1980-1990 los laboratirios de AT&T ampliarón el lenguajes c a C++ el cual ya permitia tener objetos.

Pero es hasta la decada de los 1990 a 2000 que este paradigma se consolido como un paradigma, de hecho en esta decada salierón 3 de los lenguajes orientados a objetos más importantes.

  1. Java (1995)
  2. python (1991)
  3. PHP (1995)

Pero aquí habra nuevos conceptos los cuales hablaremos en más detalle en Características de la P.O.O, por el momento solo los mencionaremos.

ConceptosBasicos

¿Por qué son importantes estos conceptos?

Recordemos que en el paradigma estructurado el código se leía de arriba abajo, lo cual estaba perfecto cuando se hacian códigos muy pequeños, sin emargo a medida que el código se expande, la tarea de darle mantenimiento se vuelve muy complicada, debido a la cantidad de lineas que se tienen que revisar y a la gran catidad de funciones que se tiene que revisar.

La solución que se propuso con la P.O.O es dividir todo en diferentes objetos para que asi consulten los atributos y métodos lo cual resulta mucho más fácil que buscar funciones en especifico en un código de más de mil lineas, pero ¿Qué les parece si definimos de mejor manera? cada uno de los conceptos.

Caracteristicas de la P.O.O ConceptosBasicos ConceptosBasicos

Constructor

Constructor

Ahora veamos como se vería una clase en python, describiendo a una Persona.

##Ejemplo de una clase persona
class Persona:

    def __init__(self,nombre,edad,identificacion):
        """
        Metodo constuctor muy importante
        self es un parametro obligatoro en este lenguaje, y hace referencia al objeto
        nombre es un String
        edad es un numero entero positivo
        identificacion es un String
        """

        self.nombre=nombre  ###Estos son los  atributos de la clase
        self.edad=edad                   
        self.identificacion=identificacion

    def masEdad(self):
        """
        Metodo que nos permite aumentar la edad de una persona
        no regresa nada
        """
        nuevaEdad=self.edad+1
        self.edad=nuevaEdad

    def setNombre(self,name):
        """
        Metodo que nos permite cambiar el nombre de una persona
        """
        self.nombre=name

    def setIdentificacion(self, x):
        """
        Mertodo que nos permite cambiar la identificación      
        """
        self.identificacion=x

    def verificaPersona(self, codigo):
        """
        Metodo que le pasas un codigo y te dice si es el de la persona  o no
        """
        return self.identificacion== codigo

    def __str__(self):
        """
        Metodo que nos permite imprimir nuestros objetos, aqui lo unico que debemos escribir es
        una cadena de como queremos que se vea en pantalla nuestro objeto
        """
        return "El nombre de la persona es " + str(self.nombre) + " su edad es " + str(self.edad) + " su identificacion es " + str(self.identificacion)

Ahora hagamos una lista de sus métodos y de sus atributos

Atributos

  1. Nombre
  2. Edad
  3. Identificación

Métodos

  1. init()
  2. másEdad
  3. setNombres
  4. setIdentificacion
  5. verificarPersona
  6. str()

Revisando los métodos nos podemos dar cuenta por que necesitamos crear objetos, ya que para que nuestros métodos funcionen requerimos de ciertas condiciones, en otras palabras necesitamos poder asegurar que se puedan obtener los datos del nombre, los datos de la identificación y los datos de la edad respectivamente.

Además hay algunos métodos que son particularmente importantes cuando trabajamos con P.O.O

Metodos Importantes

Pero, ahora ¿cómo podemos usar estos métodos que creamos en nuestro código pyhton?, por que para algo los creamos y esto se logra atravez de crear los objetos pero ¿Qué es un objeto?

¿Cómo utilizamos un objeto en python?, muy fácil veamos como podemos crear uno

###Ejemplo de  objeto

if __name__ == "__main__": ##Ponemos el main por buena educacion    

    persona1= Persona("juan",25,"juanito25")##Escribimos el nombre del objeto y entre parentesis
    print(persona1)
    ##Usemos sus metodos
    persona1.setIdentificacion("Juanito27")##Modificamos el valor de la identificacion juanito
    print (persona1)
    for i in range(0,5):
        persona1.masEdad()##Aumentamos su edad
    print(persona1)

Otro ejemplo :)

class Jugete :

    def __init__(self,nombre,marca,precio,fechaLazamiento):
        self.nombre=nombre
        self.marca=marca
        self.precio=precio
        self.fechaLazamiento=fechaLazamiento

    def jugar(self):       
        print("jugando")
        print("El jugete " + str(self.nombre) + " se siente feliz")

    def aumentarPrecio(self,aumento):
        print ("El precio aumento en " + str(aumento)  )
        self.precio+=int(aumento)

    def setNombre(self,nuevo):
        print("El nombre se actualizo por " + str(nuevo))
        self.nombre=nuevo

    def getNombre(self):
        return self.nombre

    def jugeteMasCaro(self, juguete2):
        if self.precio < juguete2.precio:
            print("El jugete " + str(juguete2.nombre) + " Es mas barato " )
        if self.precio == juguete2.precio:
            print ("El Precio es igual")
        else :
            print ("EL juguete " + self.nombre + "es más barato " )

Ahora veamos que la clase juguete y la clase Persona tienen un método que tiene el mismo nombre, esto es muy normal cuando trabajamos con la P.O.O.

Así que tendremos que tener mucho cuidado cuando pase esto debido a que en este caso ambos metodos hacen exactamente lo mismo existiran otros casos donde los código haga cosas totalmente diferentes.

Ejercicio*

  1. Identifique los atributos y métodos de la clase juguete
  2. Documente el codigo de la clase juguete
  3. Haga un método que permita verificar si un juguete es de una determinada marca o no
  4. Haga un main donde almenos utilize 3 métodos de la clase juguete

Hablemos de otros temas muy importantes para la P.O.O que son 2 de los grandes pilares de la P.O.O que son la herencia y el polimorfismo ambos conceptos son muy parecidos sin embargo este conceptos son muy diferentes como veremos a continuación

Primero hablaremos de la Herencia, existen 2 tipos de herencia, la múltiple y la simple en este curso únicamente abarcaremos herencia simple pero ¿Qué es la herencia?

Diagrama de la herencia

Tipos de herencia

Tipos-Herencia

Ahora veamos un ejemplo practico de como usara, supongamos que tenemos 3 Objetos, un disco común un disco, un disco de música y un disco de Videjuegos veamos como podemos usar la herencia.

class Disco :

    def __init__(self,nombre,empresa):
        self.nombre=nombre
        self.empresa=empresa

    def getEmpresa(self):
        return self.empresa

    def setEmpresa(self,nuevo):
        self.empresa=nuevo

    def getNombre(self):
        return self.nombre

    def setNombre(self,nuevo):
        self.nombre=nuevo

    def empezar(self):
        print ("El disco va a empezar a reproducirse")

    def __str__(self):
        return "El nombre es " + str(self.nombre) + " producido por la empresa " +  str(self.empresa)

class Videojuego(Disco) :

    def __init__(self,nombre,empresa,consolas,clasificacion, genero):
        Disco.__init__(self,nombre,empresa)
        self.consolas=consolas
        self.clasificacion=clasificacion
        self.genero=genero

    def jugar(self):
        print("Esta jugando el juego " + str (self.nombre) )
        print("Piu,Piu , Piu ")
        print("Gano yeii")


    def getConsola(self):
        return self.consolas

    def setConsola(self,x):
        self.consolas=x

    def getClacificacion(self):
        return self.clasificacion

    def setClacificacion(self,x):
        self.clasificacion=x

    def getGenero(self):
        return self.genero

    def setGenero(self,x):
        self.genero=x    


    def __str__(self):
        return super().__str__() + " La consolas son " + str(self.consolas) + " Su clacificacion es " + self.clasificacion + " Su genero es " + str(self.genero)

class Musica(Disco):

    def __init__(self, nombre, empresa,numCaciones,album):
        Disco.__init__(self,nombre, empresa)
        self.numCanciones=numCaciones
        self.album=album

    def reproducir(self):
        print("Se esta reproducciendo el album "  + str (self.album))

    def getNumcaciones(self):
        return self.numCanciones

    def setNumcaciones(self,num):
        self.numCanciones=num

    def getAlbum(self):
        return self.album

    def setAlbum(self,album):
        self.album= album

    def __str__(self):
        return super().__str__() + " El album es " + str(self.album) +  " tiene " + str(self.getNumcaciones() )+ " Canciones"  

Ahora, tal vez te estes preguntando ¿qué significa el método super()? que aparece en el método __str()__ es una Palabra reservada que indica que el método que estas buscando, no se encuentra dentro de la clase, que el método en cuestion esta siendo heredado por algunos de sus ancetros, en otras palabras se le esta indicando que el método esta siendo heredado por la clase padre.

Aquí, estamos viendo un clase de herencia simple

Ejemplo De Disco

Donde claramente la clase Padre es Disco y tiene 2 clases hijas cada una independiente sin embargo cada clase hija podría heredar a otra clase y así convertirce en una clase padre como por ejemplo

Ejemplo De Disco 2

Se deja como ejercicio hacer las 3 clases hijas de videojuego como ejercicio.

Polimorfismo

Ahora hablemos un concepto que esta muy relacionado con la herencia que se conoce como polimorfismo. Primero recordaremos el sistema de tipos.

Python es un lenguaje débilmente tipado, esto es que no necesitamos declarar el tipo que van a guardar nuestras variables, por ejemplo, en el siguiente código creamos una variable a y le asignamos un valor de tipo entero, y luego un valor de tipo String. Y python va a impirmir ambos valores sin problemas.

¿Qué pasa en otros lenguajes? Por ejemplo C es un lenguaje fuertemente tipado, esto quiere decir que una vez que creamos una variable, esta guarda un valor de un tipo y este no puede cambiar. Por ejemplo si declaramos una variable que guarde el número 10, haríamos algo como: int a = 10; en C y si luego queremos (Como en el ejemplo de abajo) que esta ahora guarde una cadena, tendríamos un error de tipos y el compilador se quejaría-

a = 10
print(a)
a = "Hola"
print(a)

El sistema de tipos entonces, nos importa porque con el polimorfismo, lo relajamos, esto quiere decir, si antes una variable solo podía guardar cosas de un cierto objeto, ahora, una variable puede guardar cosas de ese mismo objeto y de los objetos generados por clases que heredan a nuestro primer objeto

Polimorfismo

Ahora, la implicación practica de este concepto es poder usar con diferentes objetos el mismo método o poder usar un método con el mismo nombre en diferentes objetos y puedan hacer cosas distintas veamos un ejemplo práctico a continuación

## Ejemplo de polimorfismo
musica1=Musica("MagoOZ","WarnerBros",21,"Ilusia")
juego2=Videojuego("Mario Bros","Nintendo", "Switch","E", "Plataforma")
##Aqui
musica1.empezar()
juego2.empezar()

Hay que notar que si una de las clases Musica o Videojuego tuvieran implementado un método empezar, entonces al momento de mandarlo a llamar, el método que se usaría, sería el que está implementado.

Encapsulamiento

El encapsulamiento de datos consisten en proteger “del exterior” datos que una clase tiene, estos datos pueden ser desde atributos a métodos. En python no existe, pero se puede simular poniendo antes del nombre de los métodos o atributos __, de esta manera indicamos que son especiales.

class A:
    __privado__a = "atributo privado"

    def __metodo__privado(self, s):
        return "privado ", s

Si intentamos llamar a el atributo o al método como lo haríamos normalmente:

a = A()
print(a.__privado_a)
a.__metodo_privado("A")

Nos mandaría un error python diciendo que la clase A no cuenta con ese método ni con ese atributo. ¿Cómo haríamos para llamarlos? Pues necesitamos un método publico dentro de la clase, que nos permita interactuar con los datos (atributos o métodos) privados. por ejemplo hagamos otra clase:

class B:
    __privado_b = "atributo privado de B"

    def __metodo_privado(self, s):
        return "privado de", s

    def metodo_publico(self,s):
        return self.__metodo_privado(s)

    def atributo(self):
        return self.__privado_b

En este caso, tenemos dos métodos, uno que llama al atributo y otro que llama al método privado, probemos para ver cómo es que python ahora nos regresa el valor del atributo y también cómo puede mandar a llamar a un método privado desde el método público.

b = B()
print(b.atributo())
print(b.metodo_publico("B"))

En otros lenguajes por ejemplo Java, podríamos ver el hecho de crear un método público que interactúe con atributos privados como getters y setters y usando palabras reservadas.

Ahora veamos un ejemplo de una calculadora básica, la cuál contendrá un atributo privado que será una constante. Nuetras operaciones con la calculadora tendrán que ver con esa constante, es decir, si queremos sumar dos números, entonces sumamos la constante (Que es el atributo privado) y el argumento que pasamos.

class CalcCons:
    __constante = 0

    constante_pub = 1

    def cambia_constante(self, n):
        self.__constante = n

    def constante(self):
        return self.__constante

    def suma(self,n):
        return self.__constante + n


calculadora = CalcCons()
a = calculadora.constante() # debería regresar 0
print(a)
a = calculadora.suma(9) # debería regresar 9
print(a)
calculadora.cambia_constante(9)
a = calculadora.constante() # debería regresar 9
print(a)
a = calculadora.suma(9) # debería regresar 18
print(a)

Nota que si tenemos un atributo que no comienza con __, entonces podemos acceder a él desde la creación del objeto, y accediendo con el operador ‘.’ (punto) para actualizarlo, por ejemplo, si quisiéramos cambiar la variable ‘constante_pub’, bastaría con hacer lo siguiente:

print(calculadora.constante_pub)
calculadora.constante_pub = 8
print(calculadora.constante_pub)

Ejercicios

  1. Crea una clase ‘A’ que tenga el método =__init__= tenga 2 argumentos.
  2. Crea una clase ‘B’ que herede de la clase ‘A’ y reciba más argumentos, usa la herencia para usar 2 de esos argumentos en el constructor de la clase ‘A’
  3. Crea un método ‘a1’ en la clase ‘A’ que tome dos argumentos y haga algo con ellos (puede ser una suma, una concatenación, etc).
  4. Cuando crees un objeto instancia de la clase ‘B’, manda a llamar al método ‘a1’ con este, ¿Qué pasa?

  5. Crea una clase ‘C’ que herede de la clase ‘B’ ¿Como harías que el constructor herede de la clase B?. ¿Puedes mandar a llamar al método ‘a1’ con una instancia de la clase ‘C’?

  6. Crea un método ‘a2’ en la clase ‘A’ y un método ‘a2’ en la clase ‘B’, mánda a llamar al método ‘a2’ desde la clase ‘C’. ¿Cuál método es el que se ejecuta?