Friday 14 July 2017

Interface Parameters in C#

So I started my new job and noticed in the code I am working on has great use of Interfaces. I became a bit confused about them being passed as method parameters:
public string GetCharacteristics(IApple Apple)
{
...
}

When an object instance is passed as an interface parameter instead of an object, it brings an important benefit of polymorphism. This looser temporal coupling between objects allows you to cleanly separate the class design from its implementation. You then simply pass in any object as an interface parameter to a method and all object parameters can be accessed using the same methods and properties. However, all object class definitions have to implement the expected interface.
public interface IApple
{
        string Type { get; set; }
        string Colour { get; set; }

        int Sweetness();

        bool IsEdible(); 
}

To me this seems like a form of generics, because I can potentially write the same code to handle a variety of object inputs of differing types.
public class Blender : IFruitOperations 
    {
        private int GetDrinkSweetness(IApple Apple)
        {
            return Apple.Sweetness(); 
        }

        public string GetCharacteristics(IApple Apple)
        {
            string Result = 
                $"Apple {Apple.Type} has " +
                $"{GetDrinkSweetness(Apple)} sweetness, ";

            if (Apple is GrannySmith)
                Result += $"and bitterness {(Apple as GrannySmith).Bitterness}. ";
            else if (Apple is PinkLady)
                Result += $"and tastiness {(Apple as PinkLady).Tastiness}. ";

            return Result; 
            
        }

    }


Some example code for future reference, I designed it in such a way that we have specific properties. They are accessed by casting the interface to the specific class type, for example GrannySmith (for Bitterness) or PinkLady (for Tastiness).

We also have decoupled implementations of the interface, as methods Sweetness and IsEdible, however because we are passing interfaces as parameters, we are able to access the unique implementations generically, via GetDrinkSweetness and GetCharacteristics methods.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InterfaceTest
{

    public interface IApple
    {
        string Type { get; set; }
        string Colour { get; set; }

        int Sweetness();

        bool IsEdible(); 
    }


    public interface IFruitOperations
    {
        string GetCharacteristics(IApple Apple); 
    }


    public class GrannySmith : IApple
    {
        public string Type { get; set; }
        public string Colour { get; set; }

        public int Bitterness { get; set; } 

        public int Sweetness()
        {
            return 1; 
        }

        public bool IsEdible()
        {
            return true; 
        }

        public GrannySmith()
        {
            Type = "Granny Smith";
            Colour = "Green";
            Bitterness = 5; 
        }
    }

    public class PinkLady: IApple
    {
        public string Type { get; set; } 
        public string Colour { get; set; } 

        public int Tastiness { get; set; } 

        public int Sweetness()
        {
            return -1; 
        }

        public bool IsEdible()
        {
            return false; 
        }

        public PinkLady()
        {
            Type = "Pink Lady";
            Colour = "Pink";
            Tastiness = -5; 
        }
    }


    public class Blender : IFruitOperations 
    {
        private int GetDrinkSweetness(IApple Apple)
        {
            return Apple.Sweetness(); 
        }

        public string GetCharacteristics(IApple Apple)
        {
            string Result = 
                $"Apple {Apple.Type} has " +
                $"{GetDrinkSweetness(Apple)} sweetness, ";

            if (Apple is GrannySmith)
                Result += $"and bitterness {(Apple as GrannySmith).Bitterness}. ";
            else if (Apple is PinkLady)
                Result += $"and tastiness {(Apple as PinkLady).Tastiness}. ";

            return Result;             
        }

    }


    class Program
    {
        static void Main(string[] args)
        {

            Blender MyBlender = new Blender(); 

            IApple Apple1 = new GrannySmith();
            Console.WriteLine(MyBlender.GetCharacteristics(Apple1));
            Console.WriteLine(
                "Edible? {0}",
                Apple1.IsEdible() ? "Yes" : "No");  


            IApple Apple2 = new PinkLady();
            Console.WriteLine(MyBlender.GetCharacteristics(Apple2));
            Console.WriteLine(
                "Edible? {0}",
                Apple2.IsEdible() ? "Yes" : "No"); 

            Console.ReadLine(); 

        }
    }


}

No comments:

Post a Comment