Interfaces. Do I need these?

My friend has asked this question one week ago. He was not able to understand the usage of interfaces in his small projects. I decided to explain it, but I knew that it would be a long journey, from the beginning to the end. FInally he got the idea.

Today I will try to explain this to you, audience. „Q” is defined as a question. „A” as an answer.

Q: What is interface?

A: We can say that interface is a kind of class which has declarations of all methods, properties or events. It can not contain any fields, types, constants etc. It can not include any implemented methods – only declarations. Methods can not be static.

Q: Ok, but why should I use these? I can write code without them!

A: Yes you can, but there are a lot of situations when you would decide to use interface. There are 2 common examples:

CASE 1: You are a part of development team which is responsible for writing a big application for external customer. Your role is Developer, but there are also: Business Analyst, IT Architect and other Developers. Business Analyst had a meeting with a business side, he passed his analysis to IT Architect who prepared the architecture of the future system. Developers can start their work. There are already clear UML class diagrams & use cases. You open your development environment and start coding. One week later there is another meeting and all developers are supposed to show the results of their coding. Oh, no! You realize that you forgot to write 3 methods in 2 classes, other developers also forgot about something in their code.

To avoid this, you can write a class prototypes before a hard code development period. These prototypes are called INTERFACES. When you write an interface, then class which implements it needs to contain all methods, properties and events declared in interface. You will not forget about any code in your future classes.

Sample:

Interface:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    interface ICustomer
    {
        int Id { get; set; }

        string FirstName { get; set; }

        string LastName { get; set; }

        double Salary { get; set; }

        double RaiseSalary(double employeeBonus);
    }
}

Class which implements this interface:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    internal class Customer : ICustomer
    {
        #region ICustomer Members

        public int Id { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public double Salary { get; set; }

        public double RaiseSalary(double employeeBonus) //implemented method
        {
            Salary = Salary + employeeBonus;
            return Salary;
        }

        #endregion
    }
}

Sample usage:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ICustomer newCustomer = new Customer()
            {
                Id = 1,
                FirstName = "Jack",
                LastName = "Jacky",
                Salary = 23000.1
            };

            Console.WriteLine(newCustomer.Salary);

            newCustomer.Salary = newCustomer.RaiseSalary(1000);

            Console.WriteLine(newCustomer.Salary);
        }
    }
}

Now you can rewrite this code and you will notice that all methods and properties declared in your interface should be also implemented in the implementing class.

CASE 2:

You have prepared the application,  but the business side decided that there should be small changes. In the first version you had Customer class, but now there should be 2 classes: ExternalCustomer and InternalCutomer. RaiseSalary() method should be moved to another class which is called Accountancy. So, how can you avoid writing the same code in RaiseSalary() method without overloading and code repeating? Let’s look at the example:

First, create InternalCustomer class:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    internal class InternalCustomer : ICustomer
    {
        #region ICustomer Members

        public int Id { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public double Salary { get; set; }

        #endregion
    }
}

Then ExternalCustomer class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    internal class ExternalCustomer : ic

    {
        #region ICustomer Members

        public int Id { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public double Salary { get; set; }

        #endregion
    }
}

ICustomer interface:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
 interface ICustomer
 {
 int Id { get; set; }

string FirstName { get; set; }

string LastName { get; set; }

double Salary { get; set; }
 }
}

Now create Accountancy class which will be responsible for all accountancy connected with our customers:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
 internal class Accountancy
 {
 public static double RaiseSalary(ICustomer iCustomer, double employeeBonus)
 {
 iCustomer.Salary = iCustomer.Salary + employeeBonus;
 return iCustomer.Salary;
 }
 }
}

Sample usage:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
 class Program
 {
 static void Main(string[] args)
 {
 ICustomer newInternalCustomer = new InternalCustomer()
 {
 Id = 1,
 FirstName = "Internal",
 LastName = "Customer",
 Salary = 23000.1
 };

ICustomer newExternalCustomer = new ExternalCustomer()
 {
 Id = 1,
 FirstName = "External",
 LastName = "Customer",
 Salary = 33000.1
 };

 

Console.WriteLine(newInternalCustomer.Salary);
 Console.WriteLine(newExternalCustomer.Salary);

newInternalCustomer.Salary = Accountancy.RaiseSalary(newInternalCustomer, 2000);
 newExternalCustomer.Salary = Accountancy.RaiseSalary(newExternalCustomer, 3000);

 Console.WriteLine(newInternalCustomer.Salary);
 Console.WriteLine(newExternalCustomer.Salary);
 }
 }
}

As you can see, you avoid repeating code, which generates higher maintenance cost. Repeating code leads to the Domino effect – one change forces another changes in application code.

Q: Ok, now I understand the meaning of interfaces. Is there another advantage of using interfaces in my code?
A: Yes, of course. You can read about it in another article: https://mjedrzejewski.wordpress.com/2012/12/27/how-to-create-a-well-formed-class-in-oop/

5 uwag do wpisu “Interfaces. Do I need these?

  1. Pozwolę sobie skomentować po Polsku.

    Jest jeszcze jeden ciekawy przykład wykorzystania interfejsu który osobiście polecam. Wynika on z samej definicji interfejsu czyli to że interfejs definiuje porzadaną funkcjonalność.

    Wyobraźmy sobie sytuację: Mamy okno które powinno obsługiwać tryb read-only (dla każdego okna implementacja read-only wyglada troche innaczej)

    Deklarujemy sobie wiec interfejs:

    internal interface IReadOnly
    {
    ShowReadOnly();
    }

    W którymś momencie działania aplikacji, kiedy iterujemy wszystkie okna, musimy sobie odpowiedziec na pytanie: czy okno na którym jestesmy obsluguje tryb read-only? Oczywiście moglibyśmy sobie dodać do klasy okna propercję typu windowInstance.IsReadOnly i na tej podstawie oceniac czy okno obsluguje read-only – lecz wymagałoby to edycji wszytkich okien 😦

    Implementujemy nasz interfejs w oknach ktore nas interesuja:

    internal WindowForm: Window, IReadOnly
    {
    ShowReadOnly()
    {
    //kod zmieniajacy nasze okno na tryb read-only
    }
    }

    A wywołanie w przypadku gdy iterujemy po oknach:

    foreach (Window window in Application.Windows)
    {
    if(window is IReadOnly)
    window.ShowReadOnly();
    }

    +++ sa takie że edytujemy wtedy tylko te okna które sa przewidywane do trybu read-only.

    Pozdrawiam,

    1. Tak, dokładnie 🙂 To jest kolejny, bardzo dobry przykład zastosowania interfejsów. Tak jak wspomniałeś, ułatwia to czytelność kodu i jego utrzymanie (omijamy konieczność sprawdzania readonly w każdym oknie). Jeśli Ci to nie przeszkadza, to w wolnej chwili dodam tę informację w powyższym poście (oczywiście zaznaczając, że jest to dodatek Twojego autorstwa), ponieważ widzę, że cieszy się dość sporym zainteresowaniem.

      Dodając ten wpis chodziło mi też przede wszystkim o to, żeby każdy mógł w jak najprostszy sposób zobaczyć o co chodzi w interfejsach, ponieważ bardzo często spotkać można pytanie z nimi związane podczas rozmowy kwalifikacyjnej – np. o zastosowanie w praktyce. 🙂

  2. Interfaces are invented to allow easy substitution of instances. If you create common library and you put some logic in there and you couple it with some class other classes which use that library are forced to inherit that class, and sometimes it is impossible. If you use interfaces you can put there almost whatever you want.

Zostaw komentarz

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

Connecting to %s