Skip to content

Latest commit

 

History

History
204 lines (146 loc) · 6.68 KB

09-classes.adoc

File metadata and controls

204 lines (146 loc) · 6.68 KB

Las clases son una estructura de datos bastante flexible. Permiten definir la información y el comportamiento de cualquier unidad que desees modelar en los programas.

Terminología de Orientación a Objetos

Las clases son parte de un paradígma llamado "Programación Orientada a Objetos" (Object-oriented programming) (P.O.O u O.O.P). La cual se focaliza en construir bloques reusables de código llamados Clases. Cuando se necesita utilizar una clase se debe crear un objeto (o instancia), por eso el término de orientación a objetos. Para entender mejor, se debe conocer la terminología común.

  • Una clase es un bloque de código que define atributos (propiedades) y comportamientos necesarios (métodos) para modelar adecuadamente un elemento del programa. Se puede modelar algo del mundo real como una pelota o una guitarra o algo de un mundo virtual como un personaje de un videojuego y sus leyes físicas.

  • Un atributo (o propiedad) es una pieza de información. Es técnicamente una variable que es parte de una clase.

  • Un comportamiento es una acción definida dentro de una clase. Son comunmente conocidos como métodos, los cuales son las funciones definidoas para la clase.

  • Un objeto es una instancia específica de una clase. Tiene valores definidos para los atributos (variables) de la clase. Se pueden crear tantos objetos de una misma clase, como sea necesario.

El operador is

El operador is tiene dos funciones. La primera es permitir la herencia simple entre clases y la segunda permite comparar si un objeto pertenece a una metaclase específica.

Ejemplo: Juego de Piedra - Papel - Tijera

El siguiente juego de Piedra, Papel o Tijeras es implementado mediante una herencia simple. Se utiliza el patrón de diseño de double dispatch, para simplificar su lógica.

// Piedra, Papel o Tijeras
// Usando el Patron de Double Dispatch
class Elemento {
  pierdeCon(elemento) {}
  leGanaAPiedra(){}
  leGanaAPapel(){}
  leGanaATijera(){}
}

class Piedra is Elemento {
  construct crear() {}

  pierdeCon(elemento) {
    return elemento.leGanaAPiedra()
  }

  leGanaAPiedra() {
    return false
  }

  leGanaAPapel() {
    return false
  }

  leGanaATijera() {
    return true
  }
}

class Papel is Elemento {
  construct crear() {}

  pierdeCon(elemento) {
    return elemento.leGanaAPapel()
  }

  leGanaAPiedra() {
    return true
  }

  leGanaAPapel() {
    return false
  }

  leGanaATijera() {
    return false
  }
}

class Tijera is Elemento {
  construct crear() {}

  pierdeCon(elemento) {
    return elemento.leGanaATijera()
  }

  leGanaAPiedra() {
    return false
  }

  leGanaAPapel() {
    return true
  }

  leGanaATijera() {
    return false
  }
}

var piedra = Piedra.crear()
var papel = Papel.crear()
var tijera = Tijera.crear()

System.print(piedra.pierdeCon(papel))  // true (verdadero)
System.print(tijera.pierdeCon(piedra)) // true (verdadero)
System.print(piedra.pierdeCon(tijera)) // false (falso)
System.print(papel.pierdeCon(tijera))  // true (verdadero)
System.print(papel.pierdeCon(piedra))  // false (falso)

Ejemplo de comparación

Ahora utilizando las clases de Piedra, Papel o Tijeras vamos a comparar los elementos utilizando el operador is.

var piedra = Piedra.crear()

System.print(piedra is Piedra) // true (verdadero)
System.print(piedra == Piedra) // false (falso)

System.print(piedra is Tijera) // false (falso)
System.print(piedra == Tijera) // false (falso)

System.print(piedra is Elemento) // true (verdadero)
System.print(piedra == Elemento) // false (falso)

System.print(Piedra is Elemento) // false (falso)
System.print(Piedra == Elemento) // false (falso)

System.print(Piedra.supertype is Elemento) // false (falso)
System.print(Piedra.supertype == Elemento) // true (verdadero)

Analizando los resultados verdaderos:

  • (piedra is Piedra): Verdadero puesto que el objeto piedra es una instancia de la clase Piedra.

  • (piedra is Elemento): Verdadero puesto que el objeto piedra es una instancia de la clase Piedra y ésta a su vez hereda de Elemento.

  • (Piedra.supertype == Elemento): Verdadero puesto que el super tipo de Piedra es la misma referencia a la clase Elemento.

Analizando los resultados falsos:

  • (piedra == Piedra): Falso puesto que el objeto piedra no tiene la misma referencia que la clase Piedra.

  • (piedra is Tijera): Falso puesto que el objeto piedra no es una instancia de la clase Tijera.

  • (piedra == Tijera): Falso puesto que el objeto piedra no tiene la misma referencia que la clase Tijera.

  • (piedra == Elemento): Falso puesto que el objeto piedra no tiene la misma referencia que la clase Elemento.

  • (Piedra is Elemento): Falso puesto que la clase Piedra no es una instancia de la clase Elemento.

  • (Piedra == Elemento): Falso puesto que la clase Piedra no es una referencia a la clase Elemento.

  • (Piedra.supertype is Elemento): Falso pues que el super tipo de Piedra no hereda de Elemento (ya que el super tipo de Piedra es Elemento).

Ejemplo: Sobrecarga del operador

Podemos sobrecargar el operador is en nuestras clases y "ocultar" su real naturaleza. Normalmente podría ser usado para reemplazar las clases básicas (String, Num, Bool, Fn, Fiber, Map, List, Null, entre otras) y permitir su extensión. Recordemos que en Wren no se puede heredar desde estas clases debido al problema de Reentrancia (Wren no tiene esta capacidad).

Usarlo de esta forma no es común y solo se ha puesto a modo de ejemplo.

class Original {}

class Extendida {
  construct nueva() {}

  is(otra) {otra == Original}

  type {Original}
  static supertype {Original}
}

var instancia = Extendida.nueva()

System.print(instancia is Original) // true (verdadero)
System.print(instancia is Extendida) // false (falso)
System.print(instancia.type) // Original
System.print(Extendida.supertype) // Original

Las clases en Wren pueden ser adornadas con atributos especiales. Estos permiten añadir información para dar contexto o almacenar datos que pueden ser de utilidad para herramientas de programación y otras utilidades.

Solamente pueden estar dentro de una declaración de clase o de método.

#atributo = "valor"
class MiClase {
  #atributo = "valor"
  metodo {true}
}

Los valores pueden ser String, Num, Bool o el tipo especial group. que permite agrupar distintos atributos en un marco en común.

#!cantidad = 10
#grupo(
  nombre = "Camilo"
)
class MiClase {
}