Do czego służą interface w C#

0

Witam.

Nurtuje mnie takie pytanie. Wręcz nie daje mi spać po nocach. Do czego służą Interfejsy w C#. Wiem mniej więcej, jak Interface jest skonstruowany, wiem, jak go użyć, ale za diabła nie mogę wymyślić żadnego praktycznego zastosowania dla niego. Przecież jak mogę zaimplementować obiekt jakiejś klasy dziedziczącej po interfejsie, to równie dobrze mogę bez interfejsu, i powinno działać identycznie. Przecież w interfejsie są tylko puste deklaracje metod. W dodatku klasa, która po nim dziedziczy, MUSI zawierać definicje wszystkich metod tego interfejsu. Czyli jak pominiemy interfejs, wszystko powinno działać identycznie. Więc jaka jest ich funkcja? Do czego one służą? Jedyne co mi przychodzi do głowy, to przypadek, kiedy klasa dziedziczy po kilku interfejsach. Ale widziałem też wiele kodów żródłowych, gdzie było dziedziczenie po pojedynczym. I proszę mnie nie odsyłać do tutoriali (ani tym bardziej na google), bo obejrzałem ich chyba z tysiąc. Mam też kilka książek na temat C#, i wszędzie wygląda to identycznie - pokazane jest, jak używać interfejsów, jak je zaimplementować, jak się po nich dziedziczy, ale nigdzie (słownie NIGDZIE) nie znalazłem ani słowa na temat tego, jaka jest praktyczna korzyść (lub konieczność) z ich używania. Na jednym z forów widziałem podobne pytanie. Ktoś pytał o to, do czego one służą, a w odpowiedzi dostał... opis, jak je używać :)

3

Hmm, załóżmy, że mamy interfejs Comparable czy tam IComparable (nie wiem jak jest w C#), który ma metodę compareTo. Ponadto mamy funkcję sort, która przyjmuje parametr typu Collection<T extends Comparable<? super T>> (sorry, że w Javie, ale C# nie znam). Dzięki temu może posortować wszystko co implementuje Comparable. Np możesz sobie wziąć jakąś klasę i zrobić jej podklasę, która implementuje Comparable. Dzięki temu że można dziedziczyć wiele interfejsów jest to możliwe.

Przykład 2:
Mamy interfejsy IKolorowy i IZważony z metodami odpowiednio weźKolor/nadajKolor i weźWagę/nadajWagę. Mam metodę która działa na interfejsie IKolorowy i drugą która działa na interfejsie IZważony. Mam serię klas, z których część implementuje jeden interfejs, część drugi, część oba, a część wcale. Jak to ugryziesz bez interfejsów?

0

Dzięki interfejsowi masz pewność że klasa która go implementuje, udostępnia pewne metody.
Dzięki temu możesz np. traktować klasy polimorficznie. Albo wprowadzić pewne ograniczenia co do przyjmowanych obiektów.

0

Interfejsy umożliwiają luźne połączenia pomiędzy klasami czy ogólnie modułami w systemie czy pomiędzy różnymi systemami. Luźne połączenie w takim sensie, że nie tworzymy nadmiarowych i niepotrzebnych zależności jednej rzeczy od drugiej. Jeżeli jedna klasa potrzebuje użyć obiektu, na którym wywoła dwie konkretne metody to znaczy, że innych nie potrzebuje. Gdyby nie było interfejsów to klasa ta musiałaby znać absolutnie całą deklarację tej potrzebnej klasy i na dodatek wymuszałaby stosowanie tej jednej. Tak na dobrą sprawę nawet nie obchodzi nas co to będzie za klasa. Chcemy jedynie by posiadała te dwie metody.

Poszukaj sobie informacji w internecie o loose coupling.

0

Wibowit - dałeś mi do myślenia. Muszę to przetrawić, żeby lepiej zrozumieć :) (W C# w definicji interfejsu też stosuje się literkę "I").

Ubuntuser ale przecież jak sam piszę klasę, to sam decyduję, do czego będzie dostęp używając modyfikatorów dostępu. Iterfejs nie jest mi do tego potrzebny.
Do polimorfizmu tez są odpowiednie mechanizmy (operatory), które nie wymagają interfejsów.

Przed chwilą na próbę napisałem sobie prościutki programik konsolowy. Jeden interfejs, jedna klasa dziedzicząca po nim, jedna metoda i dwa pola. Program zadziałał. Następnie wykomentowałem cały interfejs, i kod w którym klasa dziedziczyła po nim, i... program zadziałał IDENTYCZNIE.

0

No dobra, masz kod (w Javie):

interface A {
  int getA();
}

interface B {
  int getB();
}

class C implements A, B {
  public int getA() {
    return 5;
  }

  public int getB() {
    return 8;
  }
}

class CA implements A {
  public int getA() {
    return 5;
  }
}

class CB implements B {
  public int getB() {
    return 8;
  }
}

class Main {

  public static void testA(final A a) {
    assert(a.getA() == 5);
  }

  public static void testB(final B b) {
    assert(b.getB() == 8);
  }

  public static void main(final String[] args) {
    final C c = new C();
    testA(c);
    testB(c);
    final A a = new CA();
    testA(a);
    final B b = new CB();
    testB(b);
  }
}

W Javie właśnie nie stosuje się literki I, przynajmniej oficjalnie takiej konwencji nie ma. Nazwy są bardziej znaczące.

Przykład 2:
W Javie jest interfejs List, który implementują np LinkedList i ArrayList.

Załóżmy, że mam kod:

final List lista = new ArrayList();
(tutaj mnóstwo kodu korzystającego ze zmiennej lista)

i w pewnym momencie stwierdzam, że jednak chcę sobie użyć LinkedList. Jedyne co zmieniam to tą jedną linijkę z new.

Przykład 3:
W Javie foreach działa na wszystkim co implementuje Iterable (+ tablice). A więc jeśli zaimplementuję sobie Iterable w swojej klasie, to mogę jej użyć w foreach i nie muszę implementować innych metod, typu add, remove, itp itd Ostatnio tak właśnie zrobiłem jak zaimplementowałem sobie niemutowalną listę i nie chciało mi się implementować interfejsu List czy podobnych, a chciałem sobie użyć foreach na mojej liście.

0

@Amor_priv , żeby potraktować obiekty dwóch klas polimorficznie, klasy te muszą dziedziczyć po tej samej klasie, dzięki interfejsom już nie, wystarczy że obie go implementują.
Mówiąc "udostępnia pewne metody" nie mam na myśli ich widoczności (public, private, protected) tylko ich obecność w klasie.

Intefejs to troche jak klasa abstrakcyjna. Z tym że klasa może dziedziczyć tylko po jednej klasie, a interfejsów może implementować kilka.

3
Amor_priv napisał(a):

Ubuntuser ale przecież jak sam piszę klasę, to sam decyduję, do czego będzie dostęp używając modyfikatorów dostępu. Iterfejs nie jest mi do tego potrzebny.

Czy znasz wszystkie klasy na świecie, łącznie z tymi jeszcze nienapisanymi?

Jak napisałbyś taki kod, gdyby nie było interfejsu IEnumerable, który jest implementowany przez tablice i listy?

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] tablica = { 2, 4, 7, 12 };
            List<int> lista = new List<int>() { 4, 9, 1, 18 };

            WyświetlKolekcje(tablica);
            WyświetlKolekcje(lista);

            Console.ReadLine();
        }

        public static void WyświetlKolekcje<T>(IEnumerable<T> kolekcja)
        {
            foreach (var n in kolekcja)
            {
                Console.WriteLine(n);
            }
            Console.WriteLine();
        }
    }
}

Jeśli napiszesz swoją własną klasę kolekcji danych i zaimplementujesz w niej ten interfejs, to będziesz mógł ją przekazać do funkcji WyświetlKolekcję bez żadnych zmian w jej kodzie.
I o to głównie chodzi, dzięki interfejsom, w momencie implementowania funkcji operującej na nich, nie musisz uzależniać się od żadnych konkretnych klas, zwłaszcza tych, które jeszcze nie istnieją.

Do polimorfizmu tez są odpowiednie mechanizmy (operatory), które nie wymagają interfejsów.

Interfejs to taka klasa abstrakcyjna, tylko zupełnie bez żadnej implementacji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1