Jaka jest definicja „interfejsu” w programowaniu obiektowym

108

Ok, mój przyjaciel powtarza, co oznacza „interfejs” w programowaniu.

Jaki jest najlepszy opis „interfejsu”.

Dla mnie interfejs jest planem klasy, czy to najlepsza definicja?

Daniel Kivatinos
źródło
1
nie jest to oszustwo, ale rzuca dużo światła na to pytanie: stackoverflow.com/questions/444245/ ...
rmeador
Powiedziałbym, że jest to ogólne słowo, ale nadal oznacza to samo dla mnie. Jest jak ściana dla konkretnej lub bardziej abstrakcyjnej istoty, która dostarcza pewnych punktów wejściowych na zewnątrz i daje im wyjście bez żadnej wiedzy o wewnętrznych operacjach. Myślę, że można to nazwać abstrakcją do definiowania klas niższego do wyższego poziomu w OOP.
ikbal

Odpowiedzi:

180

Interfejs jest jednym z bardziej obciążonych i zagmatwanych terminów w fazie rozwoju.

W rzeczywistości jest to pojęcie abstrakcji i hermetyzacji. Dla danego „pudełka” deklaruje „wejścia” i „wyjścia” tego pudełka. W świecie oprogramowania zwykle oznacza to operacje, które można wywołać na pudełku (wraz z argumentami), aw niektórych przypadkach zwracane typy tych operacji.

To, czego nie robi, to zdefiniowanie semantyki tych operacji, chociaż powszechnym (i bardzo dobrą praktyką) jest dokumentowanie ich w pobliżu deklaracji (np. Poprzez komentarze) lub wybieranie dobrych konwencji nazewnictwa. Niemniej jednak nie ma gwarancji, że intencje te będą przestrzegane.

Oto analogia: spójrz na telewizor, kiedy jest wyłączony. Jego interfejs to przyciski, które ma, różne wtyczki i ekran. Jego semantyka i zachowanie polega na tym, że pobiera dane wejściowe (np. Programowanie kabli) i ma wyjścia (wyświetlanie na ekranie, dźwięk itp.). Jednak gdy patrzysz na telewizor, który nie jest podłączony, rzutujesz oczekiwaną semantykę na interfejs. Z tego, co wiesz, telewizor może po prostu eksplodować po podłączeniu. Jednak opierając się na jego „interfejsie” można założyć, że nie zaparzy kawy, ponieważ nie ma ujęcia wody.

W programowaniu obiektowym interfejs ogólnie definiuje zestaw metod (lub komunikatów), na które może odpowiedzieć instancja klasy posiadającej ten interfejs.

To, co dodaje do zamieszania, to fakt, że w niektórych językach, takich jak Java, istnieje rzeczywisty interfejs z semantyką specyficzną dla tego języka. Na przykład w Javie jest to zestaw deklaracji metod, bez implementacji, ale interfejs również odpowiada typowi i przestrzega różnych reguł typowania.

W innych językach, takich jak C ++, nie masz interfejsów. Klasa sama definiuje metody, ale można by pomyśleć o interfejsie klasy jako o deklaracjach metod nieprywatnych. Ze względu na sposób kompilacji C ++ otrzymujesz pliki nagłówkowe, w których możesz mieć „interfejs” klasy bez faktycznej implementacji. Możesz również naśladować interfejsy Java za pomocą klas abstrakcyjnych z czystymi funkcjami wirtualnymi itp.

Interfejs z pewnością nie jest planem dla klasy. Plan, z jednej definicji, to „szczegółowy plan działania”. Interfejs nie obiecuje nic o działaniu! Źródłem nieporozumień jest to, że w większości języków, jeśli masz typ interfejsu, który definiuje zestaw metod, klasa, która go implementuje, „powtarza” te same metody (ale zapewnia definicję), więc interfejs wygląda jak szkielet lub zarys zajęć.

Uri
źródło
Czytam książkę o Objective-C i wydaje mi się, że autorzy zamiennie używają terminów „protokół” i „interfejs”. Czy słuszne jest stwierdzenie, że „protokół” i „interfejs” to to samo, czy czegoś mi brakuje?
Fazzolini
1
Nie użyłbym słowa „protokół” na określenie „interfejsu”. Słowo „protokół” wskazuje na pewien poziom szczegółowości działań. „Interfejs” to naprawdę doskonałe słowo z czysto angielską definicją, która dokładnie opisuje, czym jest.
OCDev
W systemie Windows interfejsy programistyczne są używane dość szeroko, więc nawet w C ++ można spotkać „interfejsy” na zasadzie obiektów, które są odsprzężone od implementacji.
Victoria,
166

Rozważ następującą sytuację:

Znajdujesz się w środku dużego, pustego pokoju, gdy nagle atakuje cię zombie.

Nie masz broni.

Na szczęście w drzwiach pokoju stoi inny żyjący człowiek.

"Szybki!" krzyczysz na niego. „Rzuć mi coś, czym mogę uderzyć zombie!”

Zastanów się teraz:
nie sprecyzowałeś (ani nie obchodzi cię to) dokładnie, co twój przyjaciel zdecyduje się rzucić;
... Ale to nie ma znaczenia, o ile:

  • To coś, co może być rzucił (Nie może rzucać ci kanapa)

  • To coś, za co możesz się chwycić (miejmy nadzieję, że nie rzucił shurikena)

  • To coś, czego możesz użyć do rozbicia mózgu zombie (to wyklucza poduszki i tym podobne)

Nie ma znaczenia, czy dostaniesz kij bejsbolowy, czy młotek -
jeśli tylko spełnia twoje trzy warunki, jesteś dobry.

Podsumowując:

Pisząc interfejs, w zasadzie mówisz: „Potrzebuję czegoś, co ...”

Yehuda Shapira
źródło
13
Właściwie poduszka nadal by działała. Możesz nim trafić zombie. Rozwal mózg zombie ... cóż, to kwestia wydajności, która nigdy nie jest częścią interfejsu.
meustrus
35

Interfejs to umowa, której należy przestrzegać lub której należy się podporządkować, w zależności od tego, czy jest się wdrażającym, czy użytkownikiem.

Eugene Kuleshov
źródło
1
Właściwie nie podoba mi się tutaj bezwarunkowa umowa terminowa, ponieważ umowa często implikuje semantykę lub zachowanie (jak w przypadku projektowania przez umowę). Nie wszystkie interfejsy implikują jakąkolwiek semantykę lub zachowanie. Na przykład „dziura w ścianie” to interfejs w świecie rzeczywistym. To, czy postrzegasz to jako okno, czy jako wysypisko śmieci, czy cokolwiek, jest twoją interpretacją.
Uri
3
Prawdziwe. Interfejs jest „kontraktem na podpis metody”, co oznacza, że ​​gwarantuje implementację danych metod. Nie gwarantuje, że robi to w jakikolwiek sposób.
Erik Funkenbusch
Dokładnie, powinieneś bardziej wyjaśnić tę definicję. Ale interfejs to umowa między dwiema częściami. Kod według umowy .... +1
matiasnj
18

Nie sądzę, aby „plan” był dobrym słowem. Plan mówi ci, jak coś zbudować. Interfejs specjalnie unika mówienia ci, jak coś zbudować.

Interfejs definiuje sposób interakcji z klasą, tj. Jakie metody obsługuje.

Dave Costa
źródło
1
Uważam, że wnioskodawca zapytał, jaka jest definicja, a nie, czym nie jest. :)
Eugene Kuleshov
7

Dla mnie interfejs jest planem klasy, czy to najlepsza definicja?

Nie. Plan zazwyczaj zawiera elementy wewnętrzne. Ale interfejs dotyczy wyłącznie tego, co jest widoczne na zewnątrz klasy ... lub dokładniej, rodziny klas implementujących interfejs.

Interfejs składa się z sygnatur metod i wartości stałych, a także (zazwyczaj nieformalnej) „umowy behawioralnej” między klasami implementującymi interfejs i innymi, które go używają.

Stephen C.
źródło
6

W programowaniu interfejs definiuje zachowanie obiektu, ale w rzeczywistości nie określa zachowania. To umowa, która zagwarantuje, że dana klasa może coś zrobić.

Rozważmy ten fragment kodu C # tutaj:

using System;

public interface IGenerate
{
    int Generate();
}

// Dependencies
public class KnownNumber : IGenerate
{
    public int Generate() 
    {
        return 5;
    }   
}

public class SecretNumber : IGenerate
{
    public int Generate()
    {
        return new Random().Next(0, 10);
    }
}

// What you care about
class Game
{
    public Game(IGenerate generator) 
    {
        Console.WriteLine(generator.Generate())
    }
}

new Game(new SecretNumber());
new Game(new KnownNumber());

Klasa Game wymaga tajnej liczby. Aby go przetestować, chciałbyś wstrzyknąć to, co będzie używane jako tajna liczba (ta zasada nazywa się Odwróceniem kontroli).

Klasa gry chce mieć „otwarty umysł” na temat tego, co faktycznie utworzy liczbę losową, dlatego zapyta w swoim konstruktorze o „cokolwiek, co ma metodę Generate”.

Po pierwsze, interfejs określa, jakie operacje zapewni obiekt. Po prostu zawiera to, jak wygląda, ale nie podano rzeczywistej implementacji. To tylko podpis metody. Konwencjonalnie w języku C # interfejsy są poprzedzone literą I. Klasy teraz implementują interfejs IGenerate. Oznacza to, że kompilator upewni się, że oba mają metodę, która zwraca int i jest wywoływana Generate. Gra jest teraz nazywana dwoma różnymi obiektami, z których każdy implementuje właściwy interfejs. Inne klasy powodowałyby błąd podczas budowania kodu.

Tutaj zauważyłem analogię do schematu, której użyłeś:

Klasa jest powszechnie postrzegana jako plan obiektu. Interfejs określa coś, co klasa będzie musiała zrobić, więc można by argumentować, że rzeczywiście jest to tylko plan klasy, ale ponieważ klasa niekoniecznie potrzebuje interfejsu, argumentowałbym, że ta metafora jest zepsuta. Pomyśl o interfejsie jak o umowie. Klasa, która to „podpisze”, będzie prawnie zobowiązana (egzekwowana przez policję kompilatorów) do przestrzegania warunków umowy. Oznacza to, że będzie musiał zrobić to, co zostało określone w interfejsie.

Dzieje się tak z powodu statycznego charakteru niektórych języków obiektowych, jak ma to miejsce w przypadku Javy czy C #. Z drugiej strony w Pythonie zastosowano inny mechanizm:

import random

# Dependencies
class KnownNumber(object):
    def generate(self):
        return 5

class SecretNumber(object):
    def generate(self):
        return random.randint(0,10)

# What you care about
class SecretGame(object):
    def __init__(self, number_generator):
        number = number_generator.generate()
        print number

Tutaj żadna z klas nie implementuje interfejsu. Pythona to nie obchodzi, ponieważ SecretGameklasa po prostu spróbuje wywołać dowolny przekazany obiekt. Jeśli obiekt MA metodę gene (), wszystko jest w porządku. Jeśli nie: KAPUTT! Ten błąd nie będzie widoczny w czasie kompilacji, ale w czasie wykonywania, więc prawdopodobnie wtedy, gdy Twój program jest już wdrożony i działa. C # powiadomi Cię na długo, zanim się do tego zbliżysz.

Naiwnie podano powód, dla którego ten mechanizm jest używany, ponieważ w językach OO naturalnie funkcjonują nie obywatele pierwszej kategorii. Jak widać KnownNumberi SecretNumberzawiera TYLKO funkcje do generowania liczby. Tak naprawdę nie potrzeba w ogóle zajęć. Dlatego w Pythonie można je po prostu wyrzucić i samodzielnie wybrać funkcje:

# OO Approach
SecretGame(SecretNumber())
SecretGame(KnownNumber())

# Functional Approach

# Dependencies
class SecretGame(object):
    def __init__(self, generate):
        number =  generate()
        print number

SecretGame(lambda: random.randint(0,10))
SecretGame(lambda: 5)

Lambda to po prostu funkcja, która została zadeklarowana „w linii, na bieżąco”. Delegat jest taki sam w C #:

class Game
{
    public Game(Func<int> generate) 
    {
        Console.WriteLine(generate())
    }
}    

new Game(() => 5);
new Game(() => new Random().Next(0, 10));

Uwaga boczna: te ostatnie przykłady nie były możliwe aż do Java 7. Tam interfejsy były jedynym sposobem określenia tego zachowania. Jednak Java 8 wprowadziła wyrażenia lambda, więc przykład C # można bardzo łatwo przekonwertować na Javę ( Func<int>staje się java.util.function.IntSupplieri =>staje się ->).

cessor
źródło
4

Technicznie rzecz biorąc, opisałbym interfejs jako zbiór sposobów (metody, właściwości, akcesory ... słownictwo zależy od języka, którego używasz) do interakcji z obiektem. Jeśli obiekt obsługuje / implementuje interfejs, możesz użyć wszystkich sposobów określonych w interfejsie, aby współdziałać z tym obiektem.

Pod względem semantycznym interfejs może również zawierać konwencje dotyczące tego, co możesz, a czego nie możesz robić (np. Kolejność wywoływania metod) i co w zamian możesz założyć o stanie obiektu, biorąc pod uwagę sposób interakcji daleko.

Ghislain Fourny
źródło
2

Osobiście widzę interfejs jak szablon. Jeśli interfejs zawiera definicję metod foo () i bar (), to wiesz, że każda klasa, która używa tego interfejsu, ma metody foo () i bar ().

Thomas Winsnes
źródło
2

Rozważmy, że człowiek (użytkownik lub obiekt) chce wykonać jakąś pracę. Skontaktuje się z pośrednikiem (Interface), który będzie miał kontrakt z firmami (obiekty świata rzeczywistego utworzone za pomocą zaimplementowanych klas). Kilka rodzajów prac zostanie przez niego określonych, które firmy będą realizować i dadzą mu efekty. Każda firma zrealizuje pracę na swój sposób, ale efekt będzie taki sam. Tak jak ten użytkownik będzie wykonywał swoją pracę za pomocą jednego interfejsu. Myślę, że interfejs będzie działał jako widoczna część systemów z kilkoma poleceniami, które zostaną zdefiniowane wewnętrznie przez implementujące wewnętrzne podsystemy.

Arun N
źródło
1

Interfejs oddziela operacje na klasie od implementacji wewnątrz. Dlatego niektóre implementacje mogą zapewniać wiele interfejsów.

Ludzie zwykle opisywaliby to jako „kontrakt” na to, co musi być dostępne w metodach klasy.

Absolutnie nie jest to plan, ponieważ od niego zależy również implementacja. Można powiedzieć, że pełna definicja klasy jest planem.

Szczeniak
źródło
1

Interfejs definiuje, co klasa, która po nim dziedziczy, musi implementować. W ten sposób wiele klas może dziedziczyć po interfejsie, a dzięki temu jest to możliwe

  • upewnij się, że wszystkie elementy składowe interfejsu są zaimplementowane w klasie pochodnej (nawet jeśli ma to tylko zgłosić wyjątek)
  • Wyodrębnij samą klasę z obiektu wywołującego (rzuć wystąpienie klasy do interfejsu i współdziałaj z nią bez konieczności poznania rzeczywistej klasy pochodnej IS)

Aby uzyskać więcej informacji, zobacz http://msdn.microsoft.com/en-us/library/ms173156.aspx

Greg Olmstead
źródło
1

Moim zdaniem interfejs ma szersze znaczenie niż to powszechnie kojarzone z nim w Javie. Zdefiniowałbym „interfejs” jako zbiór dostępnych operacji z pewnymi typowymi funkcjonalnościami, które umożliwiają sterowanie / monitorowanie modułu.

W tej definicji staram się uwzględnić zarówno interfejsy programowe, w których klientem jest jakiś moduł, jak i interfejsy ludzkie (na przykład GUI).

Jak już powiedzieli inni, interfejs zawsze ma za sobą jakiś kontrakt, jeśli chodzi o wejścia i wyjścia. Interfejs nie obiecuje niczego co do „sposobu” operacji; gwarantuje tylko pewne właściwości wyniku, biorąc pod uwagę aktualny stan, wybraną operację i jej parametry.

Eyal Schneider
źródło
1

Jak wyżej, odpowiednie są synonimy „umowy” i „protokołu”.

Interfejs zawiera metody i właściwości, których można oczekiwać, że zostaną ujawnione przez klasę.

Więc jeśli klasa Cheetos Bagimplementuje Chip Baginterfejs, powinieneś oczekiwać, że Cheetos Bagbędzie zachowywać się dokładnie tak, jak każda inna Chip Bag. (To znaczy ujawnij .attemptToOpenWithoutSpillingEverywhere()metodę itp.)

wlangstroth
źródło
1

Definicja konwencjonalna - interfejs to kontrakt, który określa metody, które muszą być zaimplementowane przez klasę implementującą go.

Definicja interfejsu zmieniała się w czasie. Czy myślisz, że interfejs ma tylko deklaracje metod? A co ze statycznymi zmiennymi końcowymi i domyślnymi definicjami po Javie 5.

Interfejsy zostały wprowadzone do Javy z powodu problemu Diamond z wielokrotnym dziedziczeniem i właśnie to zamierzają zrobić.

Interfejsy to konstrukcje, które zostały utworzone, aby uciec przed problemem wielokrotnego dziedziczenia i mogą mieć abstrakcyjne metody, domyślne definicje i statyczne zmienne końcowe.

http://www.quora.com/Why-does-Java-allow-static-final-variables-in-interfaces-when-they-are-only-intended-to-be-contracts

Vivek Vermani
źródło
0

Krótko mówiąc, podstawowym problemem, który próbuje rozwiązać interfejs, jest oddzielenie tego, jak czegoś używamy, od tego, jak jest to zaimplementowane. Należy jednak wziąć pod uwagę, że interfejs nie jest umową . Przeczytaj więcej tutaj .

Alireza Rahmani Khalili
źródło