InterfejsyCzęść NR.13

Interfejs to typ, którego zadaniem jest rozłączenie implementacji działania od definicji parametrów wyjścia.wejścia.

Jest to specyficzny kontrakt, który jest implementowany przez klasy. Kontrakt ten zawiera tylko informacje o co dana metoda ma się zwrócić i co ma ona przyjąć. Definicja działania jest już określona w klasie.

Aby zdefiniować interfejs wystarczy użyć słowa kluczowego interface zamiast słowa class.

Nazewnictwo Interfejsów powinno zaczynać się z dużej litery. W C# konwencja mówi by interfejsy zaczynały się od litery “I”.

Gdy interfejs nie jest zagnieżdżony wewnątrz innego typu, to może mieć tylko dwa poziomy dostępu. Publiczny i na poziomie paczki/biblioteki.

interface MyInterface {}

Elementy interfejsu

Blok kodu wewnątrz interfejsu może posiadać tylko sygnatury metod. Te metody nie mogą mieć żadnych implementacji. Ich ciała są zastępowane średnikiem.

Metody interfejsu zawsze są publiczne dlatego nie można nadać im poziomu dostępu.

Interfejsy mogą zawierać stałe. Tyczy się to jednak tylko Javy.

Interfjs nie może zawierać pól

interface MyInterface {
    int cx = 10; // constant
}

Interfejs w Javie też może mieć zagnieżdżone klasy i interfejsy. W C# nie ma takiej opcji.

Interfejs nie może deklarować pól

interface MyInterface
{
    // Typy
    class Class {}
    interface Interface {}
    enum Enum {}
}
interface MyInterface
{
    class HelperClass {
        public static void helperMethod() {}
    }
}

W C#, w interfejsie można umieszczać tylko metody, delegaty, zdarzenia, indexery oraz właściwości. Właściwości to tak naprawdę dwie metody GET; SET; więc nie powinno to nikogo dziwić.

W Javie nie ma właściwości, delegat, zdarzeń i indexerów więc nie ma ich w interfejsie.

interface IMyInterface
{
    // metoda
    int GetArea();
    // Właściwość
    int Area { get; set; }
    // Indexer
    int this[int index] { get; set; }
    // Zdarzenie
    event System.EventHandler MyEvent;
}
public delegate void UpdateStatusEventHandler(string status);
public delegate void StartedEventHandler();

public interface IMyInterface
{       
    event UpdateStatusEventHandler StatusUpdated;    
    event StartedEventHandler Started;
}

Przykłady interfejsów

W C# mamy interfejs IComparable, który definiuje pojedynczą metodę Compare.

interface IComparable
{
    int Compare(object o);
}

Klasa Circle, która znajduje się poniżej implementuje ten interfejs używając tej samej notacji co dziedziczenie.

Klasa Circle musi definiować metodę Compare. Dla tej klasy będzie to radius koła. Zaimplementowana metoda musi być publiczna. Dodatkowo sygnatura musi być identyczna do tej w interfejsie.

C# i Java może implementować wiele interfejsów.

W Javie istnieje podobny interfejs Comparable

Posiada on jedną metodę o nazwie “compare”.

interface Comparable
{
    int compare(Object o);
}

Klasa poniżej implementuje ten interfejs używając słowa kluczowego implements po nazwie klasy.

Konwencja mówi by słowo kluczowe implements stawiać po wyrażaniu extends.

Klasa może implementować wiele interfejsów, ale może dziedziczyć tylko po jednej klasie.

Aby zadeklarować kolejne implementacje interfejsów używamy przecinka.

class Circle implements Comparable
{
    public int r;
}

Klasa implantująca interfejs musi stworzyć definicję metod z interfejsów. Oczywiście.

class Circle implements Comparable
{
    public int r;
    public int compare(Object o) {
        return r - ( (Circle)o ).r;
    }
}

Funkcjonalność interfejsów

Te interfejsy obrazują i demonstrują jedno z użyć interfejsów. Definiują one specyficzną funkcjonalność wielu klas.

Istnieje możliwość używania interfejsów bez wiedzy jak dokładny typ klasy tam się znajduje.

Circle c1 = new Circle();
c1.r = 10;
Circle c2 = new Circle();
c2.r = 11;

IComparable compa1 =  c1;
IComparable compa2 =  c2;

Aby było to łatwiej zrozumieć poniżej znajduje się metoda, która spośród dwóch obiektów, które implementują ten interfejs wybierze największy z nich.

public static Object largest(Comparable a, Comparable b)
{
    return (a.compare(b) > 0) ? a : b;
}
static object Largest(IComparable a, IComparable b)
{
    return (a.Compare(b) > 0) ? a : b;
}

Interfejsy klas

Drugim sposobem użycia interfejsu jest dostarczenie kontraktu/spisu metod danej klasy. Interfejs wtedy opisuje, co dana klasa potrafi.

interface IMyClass
{
    void Widoczne();
}

class MyClass : IMyClass
{
    public void Wiidoczne() {}
    public void Ukryte() {}
}

Programiści też wtedy potrafią widzieć daną klasę przez interfejs.

IMyInterface m = new MyClass();

Taka abstrakcja ma dwie zalety. Po pierwsze ułatwia ona pracę z klasami programistom, którzy chcą skorzystać tylko z konkretnych metod danej klasy.

Po drugie pozwala na uplastycznienie implementacji zakładając, że to, co jest w interfejsie nie ulegnie zmianie.