Lo básico

Palabras vacias

Si estas leyendo esto, probablemente ya habias escuchado algo de la programacion orientada a objetos. Es solo que nunca has entendido lo que quiere decir. ¿Para que sirve la herencia? y ¿que rayos significa polimorfismo? La razón por la que tanta gente batalla tanto al tratar de programar en el paradigma orientado a objetos es por que para ellos, estas aun son palabras vacías.

Luchando con la soledad

Yo era un niño cuando vi un tamagotchi por primera vez. Es una mascota virtual que vive dentro de un aparato del tamaño de un llavero. Ya que siempre quise uno pero nunca lo tuve, vamos a construir nuestra propia mascota virtual para que nos acompañe en esas largas y frías noches de trabajo. Pero primero, tenemos que definir que es una mascota virtual.

Un estuche de monerías virtual

Ok, para este ejercicio digamos que una mascota virtual come, duerme y juega. Todo depende del humor en que este que podria ser enojado, cansado o aburrido. Eso significa que nuestro amiguito no va a jugar si esta hambriento.

Asi que es hora de un poco de diversion. Tu mision, si deseas aceptarla, es crear un enum que represente el humor de esta creatura. Despues codifica sus acciones como de acuerdo a la especificacion. En sus marcas, listos, fuera!

using System.IO;
class VirtualPet
{
  public static VirtualPet CreateTiredPet(TextWriter output)
  {
      return new VirtualPet();
  }
  
  public static VirtualPet CreateHungryPet(TextWriter output)
  {
      return new VirtualPet();
  }
  
  public static VirtualPet CreateBoredPet(TextWriter output)
  {
      return new VirtualPet();
  }
  
  public void Eat(){}
    
  public void Play(){}
    
  public void Sleep(){}
}
class VirtualPetSpecs
{
    static TextWriter writer;
    
    public static void mustPlayOnlyIfBored ()
    {
        Console.WriteLine ("Must Play Only If Bored:");
        writer = new StringWriter();
        VirtualPet bobby = VirtualPet.CreateBoredPet(writer);
        bobby.Play();
        if (writer.ToString () == "playing time")
        Console.WriteLine("pass");
        else
        Console.WriteLine("fail");
    }
    
    public static void mustEatOnlyIfHungry ()
    {
        Console.WriteLine ("Must Eat Only If Hungry");
        writer = new StringWriter();
        VirtualPet bobby = VirtualPet.CreateHungryPet(writer);
        bobby.Eat();
        if (writer.ToString () == "yummy")
        Console.WriteLine("pass");
        else
        Console.WriteLine("fail");
    }
    
    public static void mustSleepOnlyIfTired()
    {
        Console.WriteLine ("Must Sleep Only If Tired");
        writer = new StringWriter();
        VirtualPet bobby = VirtualPet.CreateTiredPet(writer);
        bobby.Sleep();
        if (writer.ToString () == "zzzz...")
        Console.WriteLine("pass");
        else
        Console.WriteLine("fail");
    }
    
}
VirtualPetSpecs.mustPlayOnlyIfBored();
VirtualPetSpecs.mustEatOnlyIfHungry();
VirtualPetSpecs.mustSleepOnlyIfTired();

 

El efecto onda

Ok, ahora que lo hiciste funcionar vamos a modificarlo. Copia el codigo que escribiste y resetea todo usando el boton inferior izquierdo. Pega tu codigo de nuevo y modificalo para que use un diccionario en lugar de un enum. Adelante, yo te espero.
Ahora que has terminado dime, ¿que tan dificil fue eso? ¿de verdad fue muy diferente? ¿crees que podrias usar una lista en lugar del dccionario? ¿crees que podrias hacerlo funcionar con puras cadenas de texto? ¿seria eso muy dificil? ¿Se te ocurre alguna manera de almacenar esos estados en un archivo de configuracion? ¿o que tal en un web service? ¿podrias hacerlo?
¿Si hicieras alguno de estos cambios, como afectarias al objeto VirtualPetSpecs? ¿Por que?

La razon por la que este codigo es tan ‘cambiable’ es por que solo estas cambiando la manera en que hace las cosas pero no que son esas cosas. Hablando en el idioma OOP, estas cambiando la implementacion, no las responsabilidades. Ahora, imagina este codigo:

 

 static void mustPlayOnlyIfBored ()
{
  Console.WriteLine ("Must Play Only If Bored:");
  VirtualPet bobby = new VirtualPet ();
  bobby.mood = Mood.Bored;
  bobby.Play();
  if (bobby.mood == Mood.Tired)
   Console.WriteLine("pass");
  else
   Console.WriteLine("fail");
}

Intenta usar un diccionario, archivo de configuracion o web service. Es mas, trata de cambiar el humor a hambriento (Hungry). O crear un algoritmo que cambie el humor al azar. ¿Puedes hacer eso sin modificar la especificacion?
El problema con este codigo es que VirtualPet esta mostrando demasiado de la manera en que hace las cosas (detalles de implementacion en el idioma OOP). Esto conduce a que el codigo que usa este objeto dependa de los detalles de implementacion del mismo (acoplamiento en el idioma OOP) de ahi que sea imposible modificar este objeto sin modificar el codigo que lo usa. Yo lo llamo el efecto onda, ya que un cambio tiende a propagarse a otras partes del sistema. La unica manera de evitar el efecto onda es escondiendo los detalles de la implementacion por completo. Esto se llama encapsulamiento. Si, asi es: es lo mismo que te dijeron en tu clase de java o c++. Encapsulamiento no es nada mas que la forma de decir «¡esconde los detalles de implementacion!» en el idioma OOP. Y esto abre la puerta para un monton de cosas interesantes.

No te pierdas la parte 2 😉

P.D. Tarea: toma una copia de algun proyecto y empieza a buscar partes donde el codigo depende de los detalles de implementacion de algun objeto. Analiza el efecto onda y como modificar el codigo para prevenirlo. Pon tu respuesta en los comentarios..