oopEmpezando con oop


Observaciones

La programación orientada a objetos (OOP) es un paradigma de programación basado en el concepto de "objetos", que puede contener datos, en forma de campos, a menudo conocidos como atributos; y el código, en forma de procedimientos, a menudo conocidos como métodos.

Introducción

OOP - La programación orientada a objetos es un paradigma de programación muy utilizado en estos días. En OOP, modelamos problemas del mundo real utilizando Objetos y comportamientos de ese tipo, para resolverlos mediante programación.

Hay cuatro conceptos principales de POO

  1. Herencia
  2. Polimorfismo
  3. Abstracción
  4. Encapsulacion

Estos cuatro conceptos juntos se utilizan para desarrollar programas en OOP.

Hay varios lenguajes que apoyan la Programación Orientada a Objetos. Los idiomas más populares son

  • C ++
  • Java
  • DO#
  • Python (Python no está completamente orientado a objetos, pero tiene la mayoría de las características de POO)

OOP Introducción

Intoducción

La Programación Orientada a Objetos (en su mayoría denominada OOP) es un paradigma de programación para resolver problemas.
La belleza de un programa OO (orientado a objetos), es que pensamos en el programa como un conjunto de objetos que se comunican entre sí, en lugar de como un script secuencial que sigue órdenes específicas.

Hay muchos lenguajes de programación compatibles con OOP, algunos de los más populares son:

  • Java
  • C ++
  • do#

También se sabe que Python es compatible con OOP, pero carece de algunas propiedades.


Terminología OOP

El término más básico en OOP es una clase .
Una clase es básicamente un objeto , que tiene un estado y funciona de acuerdo con su estado.

Otro término importante es una instancia .
Piense en una clase como una plantilla utilizada para crear instancias de sí misma. La clase es una plantilla y la (s) instancia (s) son los objetos concretos.

Una instancia creada a partir de la clase A generalmente se conoce como del 'tipo A', exactamente como el tipo de 5 es int y el tipo de "abcd" es una cadena .

Un ejemplo de creación de una instancia denominada insance1 de tipo (clase) ClassA :

Java

ClassA instance1 = new ClassA();
 

C ++

ClassA instance1;
 

o

ClassA *instance1 = new ClassA(); # On the heap
 

Pitón

instance1 = ClassA()
 

Como puede ver en el ejemplo anterior, en todos los casos se mencionó el nombre de la clase y después había paréntesis vacíos (excepto para C ++ donde, si están vacíos, se pueden quitar los paréntesis). En estos paréntesis podemos pasar arguments al constructor de nuestra clase.

Un constructor es un método de una clase que se llama cada vez que se crea una instancia. Puede tomar argumentos o no. Si el programador no especifica ningún constructor para una clase que construyen, se creará un constructor vacío (un constructor que no hace nada).
En la mayoría de los idiomas, el constructor se define como un método sin definir su tipo de retorno y con el mismo nombre de la clase (ejemplo en algunas secciones).

Un ejemplo de creación de una instancia denominada b1 de tipo (clase) ClassB . El constructor de ClassB toma un argumento de tipo int :

Java

ClassA instance1 = new ClassA(5);
 

o

int i = 5;
ClassA instance1 = new ClassA(i);
 

C ++

ClassA instance1(5);
 

Pitón

instance1 = ClassA(5)
 

Como puede ver, el proceso de crear una instancia es muy similar al proceso de llamar a una función.


Funciones vs Métodos

Tanto las funciones como los métodos son muy similares, pero en el Diseño orientado a objetos (OOD), cada uno tiene su propio significado.
Un método es una operación realizada en una instancia de una clase. El método en sí mismo usualmente usa el estado de la instancia para operar.
Mientras tanto, una función pertenece a una clase y no a una instancia específica. Esto significa que no utiliza el estado de la clase ni ningún dato almacenado en una instancia.

De ahora en adelante, mostraremos nuestros ejemplos solo en Java, ya que OOP es muy claro en este lenguaje, pero los mismos principios funcionan en cualquier otro lenguaje OOP.

En Java, una función tiene la palabra estática en su definición, así:

// File's name is ClassA
public static int add(int a, int b) {
    return a + b;
}
 

Esto significa que puede llamarlo desde cualquier parte del script.

// From the same file
System.out.println(add(3, 5));

// From another file in the same package (or after imported)
System.out.println(ClassA.add(3, 5));
 

Cuando llamamos a la función desde otro archivo, usamos el nombre de la clase (en Java, también es el nombre del archivo) al que pertenece, esto da la intuición de que la función pertenece a la clase y no a ninguna de sus instancias.

En contraste, podemos definir un método en ClassA así:

// File's name is ClassA
public int subtract(int a, int b){
    return a - b;
}
 

Después de esta decleración podemos llamar a este método así:

ClassA a = new ClassA();
System.out.println(a.subtract(3, 5));
 

Aquí necesitamos crear una instancia de ClassA para poder llamar a su método restar. Note que NO PODEMOS hacer lo siguiente:

System.out.println(ClassA.subtract(3, 5));
 

Esta línea producirá un error de compilación quejándose de que llamamos a este método no estático sin una instancia.


Usando el estado de una clase

Supongamos que queremos implementar nuestro método de resta de nuevo, pero esta vez siempre queremos restar el mismo número (para cada instancia). Podemos crear la siguiente clase:

class ClassB {

    private int sub_amount;

    public ClassB(int sub_amount) {
        this.sub_amount = sub_amount;
    }

    public int subtract(int a) {
        return a - sub_amount;
    }

    public static void main(String[] args) {
        ClassB b = new ClassB(5);
        System.out.println(b.subtract(3)); // Ouput is -2
    }
}
 

Cuando ejecutamos este código, se crea una nueva instancia llamada b de la clase ClassB y su constructor se alimenta con el valor 5 .
El constructor ahora toma la sub_amount dada y la almacena como su propio campo privado, también llamado sub_amount (esta convención es muy conocida en Java, para nombrar los argumentos igual que los campos).
Después de eso, imprimimos a la consola el resultado de llamar al método restar en b con el valor de 3 .

Note que en la implementación de restar no usamos this. Como en el constructor.
En Java, this solo se debe escribir cuando hay otra variable con el mismo nombre definido en ese ámbito. Lo mismo funciona con la self Python.
Entonces, cuando usamos sub_amount en restar, hacemos referencia al campo privado que es diferente para cada clase.

Otro ejemplo a destacar.
Simplemente cambiemos la función principal en el código anterior a lo siguiente:

ClassB b1 = new ClassB(1);
ClassB b2 = new ClassB(2);

System.out.println(b1.subtract(10)); // Output is 9
System.out.println(b2.subtract(10)); // Output is 8
 

Como podemos ver, b1 y b2 son independientes y cada uno tiene su propio estado .


Interfaces y herencia

Una interfaz es un contrato, define qué métodos tendrá una clase y, por lo tanto, sus capacidades. Una interfaz no tiene una implementación, solo define lo que se necesita hacer.
Un ejemplo en Java sería:

interface Printalbe {
    public void print();
}
 

La interfaz de Printalbe define un método llamado impresión, pero no proporciona su implementación (bastante extraño para Java). Cada clase que se declara a sí misma como implementing esta interfaz debe proporcionar una implementación al método de dibujo. Por ejemplo:

class Person implements Printalbe {

    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void print() {
        System.out.println(name);
    }
}
 

Si Person se declarara a sí mismo como implementable de Drawable pero no proporcionara una implementación para imprimir , habría un error de compilación y el programa no se compilaría.

Herencia es un término que apunta a una clase que se extiende a otra clase. Por ejemplo, digamos que ahora tenemos una persona que tiene una edad. Una forma de implementar una persona así sería copiar la clase Persona y escribir una nueva clase llamada AgedPerson que tenga los mismos campos y métodos pero que tenga otra propiedad.
Esto sería horrible ya que duplicamos todo nuestro código solo para agregar una característica simple a nuestra clase.
Podemos usar la herencia para heredar de Person y así obtener todas sus características, y luego mejorarlas con nuestra nueva característica, así:

class AgedPerson extends Person {

    private int age;

    public AgedPerson(String name, int age) {
        super(name);
        this.age = age;
    }

    public void print() {
        System.out.println("Name: " + name + ", age:" + age);
    }
}
 

Hay algunas cosas nuevas que están sucediendo:

  • Utilizamos la extends palabra guardada para indicar que estamos heredando de Person (y también su implementación en Imprimible , por lo que no necesitamos declarar la implementing Printable nuevamente).
  • Usamos la palabra super para llamar al constructor de Person .
  • Anulamos el método de impresión de Persona con uno nuevo.

Esto se está volviendo bastante técnico en Java, así que no profundizaré más en este tema. Pero mencionaré que hay muchos casos extremos que deben aprenderse sobre la herencia y las interfaces antes de comenzar a usarlos. Por ejemplo, ¿qué métodos y funciones se heredan? ¿Qué sucede con los campos privados / públicos / protegidos cuando se hereda de una clase? y así.

Clase abstracta

Una clase abstracta es un término bastante avanzado en OOP que describe una combinación de ambas interfaces y herencia. Le permite escribir una clase que tiene métodos / funciones implementados y no implementados. En Java, esto se hace usando el abstract palabras clave y no lo explicaré más que un ejemplo rápido:

abstract class AbstractIntStack {

    abstract public void push(int element);

    abstract public void pop();

    abstract public int top();

    final public void replaceTop(int element) {
        pop();
        push(element);
    }
}
 

Nota: la palabra clave final indica que no puede anular este método cuando hereda de esta clase. Si una clase se declara definitiva, entonces ninguna clase puede heredarla.