Tuesday, June 26, 2012

Upcast to an Interface!

Imagine we have two animals, a dog and a parrot:

  1. namespace MyApp.Core
    {
       public class Dog : Animal
       {
          public string Speak()
          {
             return "Woof!";
          }
       }
    }
     
  2. namespace MyApp.Core
    {
       public class Parrot : Animal
       {
          public string Speak()
          {
             return "Polly wants a cracker.";
          }
          
          public string Squawk()
          {
             return "QuaWk!";
          }
       }
    }

 
 

Their types both inherit from an interface called Animal:

namespace MyApp.Core
{
   public interface Animal
   {
      string Speak();
   }
}

 
 

Alright, we may now hand instantiations of Dog and Parrot into a method signature that consumes an Animal. The methods defined at Animal would be accessible at the instance of animal that lives inside of the method signature. For example, we could make a Parrot, hand the Parrot into the method where it would become of Animal shape and then make the Parrot speak but not squawk as Speak() is a method on Animal while Squawk() is not. When the animal speaks it will speak as a parrot speaks given that Animal itself does not define what happens in speaking. Moreover, if one does reflection against the animal one will get Parrot-tainted goodies. This is another means to have children of many types bottleneck through a parent when entering a common assembly line. This is more inheritance detailed in C# 4.0 in a Nutshell.

using System;
namespace MyApp.Core
{
   public static class AnimalInterpreter
   {
      public static string Interpret(Animal animal)
      {
         string animalAnalysis = "When a " + DigNameOutOfType(animal.GetType());
         animalAnalysis = animalAnalysis + " says: " + animal.Speak();
         animalAnalysis = animalAnalysis + " ...it is hungry!";
         return animalAnalysis;
      }
      
      private static string DigNameOutOfType(Type type)
      {
         string tooMuchInformation = type.FullName;
         string fullName = tooMuchInformation.Split(",".ToCharArray())[0];
         string[] bitsOfFullName = fullName.Split(".".ToCharArray());
         return bitsOfFullName[bitsOfFullName.Length - 1];
      }
   }
}

 
 

This test passes:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MyApp.Core;
namespace MyApp.Tests
{
   [TestClass]
   public class AnimalTester
   {
      [TestMethod]
      public void Test()
      {
         Dog dog = new Dog();
         Parrot parrot = new Parrot();
         Animal animal = dog;
         string dogTalk = AnimalInterpreter.Interpret(dog);
         string parrotTalk = AnimalInterpreter.Interpret(parrot);
         string animalTalk = AnimalInterpreter.Interpret(animal);
         Assert.AreEqual(dogTalk, "When a Dog says: Woof! ...it is hungry!");
         Assert.AreEqual(parrotTalk, "When a Parrot says: Polly wants a cracker. ...it is
               hungry!");
         Assert.AreEqual(animalTalk, "When a Dog says: Woof! ...it is hungry!");
      }
   }
}

No comments:

Post a Comment