🧱 Programando con Objetos: Clases y Objetos
Después de nuestra inmersión inicial en el mundo de las clases y los objetos, hoy vamos a dar un paso más en nuestra nueva serie “Programando con Objetos”. ¿Listos para sumergirnos aún más en la programación orientada a objetos con un toque práctico? Vamos a hacer exactamente eso, pero esta vez, con un poco más de acción mediante TypeScript
, que esto no te asuste, ya que la idea es aprender conceptos y cosas generales de la mayoría de los lenguajes más comunes de nuestro día a día por lo tanto no creo que tengas dificultades si es que manejas otro lenguaje para el aprendizaje que nos encaminaremos.
🎯 Un Vistazo Práctico a Clases y Objetos
Nos adentraremos en el emocionante terreno de TypeScript, donde cada línea de código no solo define una función, sino que cuenta una historia.
Dado una clase, puedes crear cualquier número de objetos. El comportamiento en tiempo de ejecución (cuando el programa esta funcionando) de un objeto es definido por su definición de clase. El siguiente código muestra una simple clase, sin estado ni comportamiento, la cuál puede ser instanciada, es decir, permite la creación de un objeto a partir de su clase.
- 📋 Clase mínima y viable
class Payment
{
// Sin código
}
const computerPayment = new Payment();
const phonePayment = new Payment();
computerPayment == phonePayment // false
Si bien los objetos computerPayment
y phonePayment
pertenecen a la misma clase y no tienen atributos y comportamiento diferentes entre sí, no son lo mismo en la comparación de ambos objetos
ya que se comparan por valor de referencia a la variable que están asociados. Si lo pensamos, en la realidad representan dos tipos de pagos diferentes, uno es el pago de una computadora y otro es el pago de nuestro celular como vemos en el ejemplo, y nuestra intuición nos dice que son dos cosas diferentes de alguna manera.
Una vez que tenemos una instancia
, podemos llamar a cualquiera de sus métodos, en caso de que existan, no sería el caso del ejemplo anterior en el que esta completamente vacia la clase Payment
.
- 📋 Llamando a un método en una instancia.
class Payment
{
public markAsPaid(): void
{
// ...
}
}
const computerPayment = new Payment();
computerPayment.markAsPaid();
Los métodos de instancia, como markAsPaid(), solo pueden ser llamados desde una instancia de clase. Este tipo de métodos son llamados object method. También podemos definir métodos que pueden ser llamados sin una instancia determinada y estos son llamados static methods.
- 📋 Definiendo un método estático
class Payment
{
public anObjectMethod(): void
{
// ...
}
public static aStaticMethod(): void
{
// ...
}
}
const computerPayment = new Payment();
computerPayment.anObjectMethod(); // Necesita ser instanciado previamente como vemos en la línea anterior.
Payment.aStaticMethod(); // No necesita ser instanciado anteriormente, se puede utilizar desde la clase directamente.
Además de los métodos de objeto y los métodos estáticos, una clase también puede contener un método especial llamado: constructor.
Se llamará a este método antes de que se devuelva una referencia al objeto. Si necesita hacer cualquier cosa para preparar el objeto
en un estado determinado antes de que se vaya a usar, podríamos hacerlo mediante el constructor de la clase, donde dependiendo del lenguaje su declaración
es de una manera u otra, para ejemplificar le colocaremos un nombre constructor()
como hace JavaScript / Typescript
en nuestro caso, pero en otros casos este método se declara con el mismo nombre que la clase ejemplo public Payment(args...) { // Prepare object... }
.
- 📋 Definiendo un método constructor
class Payment
{
public constructor()
{
// Preparar el objeto adeacuadamente...
}
}
const computerPayment = new Payment();
En este caso el método contructor de la clase no realiza ninguna acción por lo tanto simplemente hará la creación del objeto Payment
en este caso representado por la variable computerPayment
.
Podríamos hacer algunas validaciones previo a la creación de la instancia u objeto y además podemos evitar que se cree una instancia completa de un objeto lanzando una excepción dentro del constructor, como se muestra en el siguiente código.
- 📋 Lanzando una excepción dentro del constructor
class Payment
{
public construct()
{
throw new RuntimeException(); // No será posible instanciar el objeto Payment ya que su constructor siempre lanza una excepción pase lo que pase.
}
}
try {
const computerPayment = new Payment();
} catch (RuntimeException exception) {
// `computerPayment` será undefined aquí ya que nunca se llego a instanciar Payment.
}
Si queremos saber más sobre excepciones más adelante abordaremos sobre el tema en particular pero en definitiva cortan nuestro flujo de ejecución ya que le decimos al programa que algo inesperado ha pasado y por lo tanto tenemos que manejar este error ocurrido de alguna manera, así sea que el manejo sea no hacer nada, lo más común es dejar un Log (otro tema importante para abordar en otro momento…) en nuestra aplicación para poder visualizar que error/es ocurrierron.
- 📋 Definiendo contructores semánticos (named constructors)
class Payment
{
private construct(...)
{
// Asignación de propiedades...
}
public static make(): Payment
{
// Validaciones, y otras responsabilidades...
return new Payment(...);
}
}
const computerPayment = Payment.make();
const phonePayment = Payment.make();
El método make()
debe definirse como estático porque debe invocarse en la clase directamente, y no en una instancia particular de esa clase,
es un medio para crear la propia clase de una manera directa y más semántica, permitiendo como veremos más adelante realizar validaciones (si… más temas de estudio) respectivas a los argumentos de entrada o estados de la clase para respetar la integridad del objeto, previo a realizar la construcción del mismo, es decir, antes de hacer el new Payment(...)
.
🌌 Conclusión: El Poder de las Clases y Objetos en TypeScript
Y así hemos llegado al final de nuestra primera lección en “Programando con Objetos”. Hemos viajado a través de las nociones básicas de clases y objetos en TypeScript, descubriendo cómo estos conceptos se transforman en código funcional y significativo. Desde instanciar objetos simples hasta comprender la diferencia entre métodos de objetos y estáticos, espero que este viaje haya sido tan iluminador para ustedes como lo fue para mí en su momento.
No olviden que cada línea de código no solo es una instrucción a la computadora, sino también una expresión de nuestro pensamiento y creatividad como desarrolladores. Con cada clase que definimos y cada objeto que instanciamos, así como también con cada nombre que colocamos, estamos modelando y dando forma a nuestras ideas en el mundo digital.