DEV Community

Cover image for C# Inheritance Pt2 - Interfaces
Grant Riordan
Grant Riordan

Posted on

C# Inheritance Pt2 - Interfaces

So, in our last chapter we discussed inheritance using a very basic example of a Bank and different types of banks,to illustrate a very basic concept of being able to inherit properties from one class to another.

It should be pointed out although this was an example, it would not be an ideal real life usage, it was merely just for an example of inheritance.

So how could this setup be improved to allow for scalability, and having different implementation / functionality, e.g. different payment methods.

What is an interface ?

An interface, in layman's terms, is a blue print of ability. It's an outline of what something can do. It states what a class inheriting can do, however it doesn't say how it can do it. You may hear the term "contract" when people refer to an interface, which isn't wrong but I feel a blueprint is more suitable.

The phrase contact is used because of the ideology, that a class that inherits from an interface is agreeing to implement all its methods and such.

When an interface is inherited you must provide an implementation for all methods.

How to declare an interface ?

Declaring an interface is very similar to a class. You have a namespace and you have your declaration like so:

public interface IPaymentMethod {

}

//or

public interface IBank {

}
Enter fullscreen mode Exit fullscreen mode

Let's look at a similar example to our previous bank inheritance, but look how we'd use interfaces in a real life example, with payment methods. As we know there are multiple ways to pay for things in this current world, so say we're building an app that needs to handle multiple payment options, we could create reusable code using interfaces like so:

Firstly create an interface to define a payment method.


public interface IPaymentMethod
{
   void MakePayment();
   bool IsAuthenticated();
}
Enter fullscreen mode Exit fullscreen mode

This can simply have two methods, that all classes will inherit and implement. This is the blueprint of any PaymentMethod, and these must have these two methods.

Let's create our classes

public class DebitCardPayment : IPaymentMethod
{
  public DebitCardPayment()
  {
  }

  public string CardNumber { get; set; }
  public string SecurityNumber { get; set; }

  public void MakePayment()
  {
    Console.WriteLine("A debit card payment was made");
  }

  public bool IsAuthenticated()
  {
   //could check that the 3 digits on card have been 
            entered or something
   return true;
  }
 }

public class GooglePayPayment : IPaymentMethod
{
 public GooglePayPayment()
 {
 }

  public bool IsAuthenticated()
  { //could check googleID  and password entered / fingerprint active
    return true;
  }
  public void MakePayment()
  {
    if (IsAuthenticated())
    {
  Console.WriteLine($"Making authorised GPay payment");
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

So now we've created two classes called GooglePayMethod and DebitCardMethod. These classes inherit and implement the IPaymentMethod interface.

As you can see they both have the same methods according to the interface "contract" yet they implement them differently.

What use is this ? Why is it beneficial ?

Well now we have an interface we can use this interface across an application. We can tell other classes, services etc that require a payment to be made , that we'll provide one, but we're not sure what it'll be nor do we care. It makes our code less "tightly coupled", and accepting of any PaymentMethod, looking at some code may make this easier to grasp.

public class PaymentManager
{

   private IPaymentMethod paymentMethod { get; set; }

   public PaymentManager(IPaymentMethod method)
   {
      this.paymentMethod = method;
   }

   public void HandlePayment()
   {
      paymentMethod.MakePayment();
   }
}
Enter fullscreen mode Exit fullscreen mode

What is this doing? We have create a PaymentManager class that will handle our payments (we could add additional methods in the future), but for now it'll just handle making the payment.

As you can see the constructor accepts a IPaymentMethod object. This means that the PaymentManager can accept any class that inherits from this interface.

This makes the PaymentManager re-usable, as it can be used with any payment method now.

But wait, how do pass payment manager a Payment method implementation (concrete class) ? We can use a factory.

class PaymentMethodFactory
{
  public static IPaymentMethod Create(PaymentMethodType type)
  {
     return type switch
     {
       PaymentMethodType.GooglePay => new GooglePayPayment(),
       PaymentMethodType.DebitCard => new DebitCardPayment(),
       _ => throw new ArgumentNullException("Provided type does not exist"),
     };
   }
}
Enter fullscreen mode Exit fullscreen mode

So now we have a way, using a static class to create our PaymentMethod using our PaymentMethodFactory.

So how does this all fit together and how will it actually be used.

namespace Bank
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var paymentMethod = PaymentMethodFactory.Create(PaymentMethodType.GooglePay);
            var paymentManager = new PaymentManager(paymentMethod);
            paymentManager.HandlePayment();
            Console.ReadLine();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In a larger application we would have more logic to decide what payment method to use (likely an input button, or a checkbox to select the way you'd like to pay). However as a basic concept and understanding, this proves my point. Now we have a console application that can handle multiple payments and isn't reliant on what each does. The manager just wants a payment method, and will handle the payment side, and has one responsibility.

If we were to wish to add a payment method, we don't need to change any of our application, we simply go about creating a new class, inheriting from the IPaymentMethod interface, and we're all set, for example

public class ApplePayPayment : IPaymentMethod
{
    public ApplePayPayment()
    {

    }

    public bool IsAuthenticated()
    {
        //could check apple face recognition
        return true;
    }

    public void MakePayment()
    {
        if (IsAuthenticated())
        {
            Console.WriteLine($"Making authorised Apple Pay payment");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And without any other changes to our code (other than telling the factory to create a ApplyPayMethod) the system will work just as before.

Summary

So there we have it, we've created our first interface, and wrote much more manageable and reusable code base. Next chapter we'll look at Abstract classes, similar to an interface but with some added extra features.

Top comments (0)