Polymorphism through Interfaces

Consider another example, as shown in Listing 8.2 with Output 8.1: IListable defines the members that a class needs to support if the ConsoleListControl class is to display it. As such, any class that implements IListable can use the ConsoleListControl to display itself. The IListable interface requires a read-only property, CellValues.

Listing 8.2: Implementing and Using Interfaces
public interface IListable
{
    // Return the value of each cell in the row
    string?[] CellValues { get; }
}
 
public abstract class PdaItem
{
    public PdaItem(string name)
    {
        Name = name;
    }
 
    public virtual string Name { getset; }
}
 
public class Contact : PdaItem, IListable
{
    public Contact(string firstName, string lastName,
        string address, string phone)
        : base(GetName(firstName, lastName))
    {
        FirstName = firstName;
        LastName = lastName;
        Address = address;
        Phone = phone;
    }
 
    public string FirstName { get; }
    public string LastName { get; }
    public string Address { get; }
    public string Phone { get; }
    public static string GetName(string firstName, string lastName)
        => $"{ firstName } { lastName }";
 
    public string[] CellValues
    {
        get
        {
            return new string[]
            {
                FirstName,
                LastName,
                Phone,
                Address
            };
        }
    }
 
    public static string[] Headers
    {
        get
        {
            return new string[] {
                "First Name""Last Name    ",
                "Phone       ",
                "Address                       " };
        }
    }
    // ...
}
 
public class Publication : IListable
{
    public Publication(string title, string author, int year)
    {
        Title = title;
        Author = author;
        Year = year;
    }
 
    public string Title { get; }
    public string Author { get; }
    public int Year { get; }
 
    public string?[] CellValues
    {
        get
        {
            return new string?[]
            {
                Title,
                Author,
                Year.ToString()
            };
        }
    }
 
    public static string[] Headers
    {
        get
        {
            return new string[] {
                "Title                                                    "
                "Author             "
                "Year" };
        }
    }
 
    // ...
}
 
public class Program
{
    public static void Main()
    {
        Contact[] contacts = new Contact[]
        {
          new(
              "Dick""Traci",
              "123 Main St., Spokane, WA  99037",
              "123-123-1234"),
          new(
              "Andrew""Littman",
              "1417 Palmary St., Dallas, TX 55555",
              "555-123-4567"),
          new(
              "Mary""Hartfelt",
              "1520 Thunder Way, Elizabethton, PA 44444",
              "444-123-4567"),
          new(
              "John""Lindherst",
              "1 Aerial Way Dr., Monteray, NH 88888",
              "222-987-6543"),
          new(
              "Pat""Wilson",
              "565 Irving Dr., Parksdale, FL 22222",
              "123-456-7890"),
          new(
              "Jane""Doe",
              "123 Main St., Aurora, IL 66666",
              "333-345-6789")
        };
 
        // Classes are cast implicitly convertible to
        // their supported interfaces
        ConsoleListControl.List(Contact.Headers, contacts);
 
        Console.WriteLine();
 
        Publication[] publications = new Publication[3] {
            new(
                "The End of Poverty: Economic Possibilities for Our Time",
                "Jeffrey Sachs", 2006),
            new("Orthodoxy",
                "G.K. Chesterton", 1908),
            new(
                "The Hitchhiker's Guide to the Galaxy",
                "Douglas Adams", 1979)
            };
        ConsoleListControl.List(
            Publication.Headers, publications);
    }
}
 
public class ConsoleListControl
{
    public static void List(string[] headers, IListable[] items)
    {
        int[] columnWidths = DisplayHeaders(headers);
 
        for(int count = 0; count < items.Length; count++)
        {
            string?[] values = items[count].CellValues;
            DisplayItemRow(columnWidths, values);
        }
    }
 
    /// <summary>Displays the column headers</summary>
    /// <returns>Returns an array of column widths</returns>
    private static int[] DisplayHeaders(string[] headers)
    {
        // ...
    }
 
    private static void DisplayItemRow(
        int[] columnWidths, string?[] values)
    {
        // ...
    }
}

Output 8.1
First Name  Last Name      Phone         Address
Dick        Traci          123-123-1234  123 Main St., Spokane, WA  99037
Andrew      Littman        555-123-4567  1417 Palmary St., Dallas, TX 55555
Mary        Hartfelt       444-123-4567  1520 Thunder Way, Elizabethton, PA 44444
John        Lindherst      222-987-6543  1 Aerial Way Dr., Monteray, NH 88888
Pat         Wilson         123-456-7890  565 Irving Dr., Parksdale, FL 22222
Jane        Doe            333-345-6789  123 Main St., Aurora, IL 66666
Title                                                    Author             Year
The End of Poverty: Economic Possibilities for Our Time  Jeffrey Sachs      2006
Orthodoxy                                                G.K. Chesterton    1908
The Hitchhiker's Guide to the Galaxy                     Douglas Adams      1979

In Listing 8.2, the ConsoleListControl can display seemingly unrelated classes (Contact and Publication). Any class can be displayed provided that it implements the required interface. As a result, the ConsoleListControl.List() method relies on polymorphism to appropriately display whichever set of objects it is passed. Each class has its own implementation of CellValues, and converting a class to IListable still allows the particular class’s implementation to be invoked.

{{ snackbarMessage }}
;