Che cosa significa la seguente definizione di interfaccia?

2

Sto leggendo Laboratorio UML in tempo reale per sistemi embedded e non capisco cosa stanno dicendo qui . Ho evidenziato in grassetto le parti del testo che non comprendo completamente. Sto cercando di capirlo dal punto di vista del punto C.

An interface is a named collection of services. Services come in two basic flavors. Operations are synchronous services that are invoked, or called by clients. Event receptions are asynchronous services that are invoked by sending an asynchronous signal to the object accepting that event. An interface can contain either or both operations and event receptions. Both operations and event signals can contain data, called parameters, passed with the invocation. The set of parameters, along with the name of the service, is called the signature of the service. A class that is compliant with an interface provides a method for every operation and an event reception for every signal specified in the interface.

Interfaces allow you to separate the specification of services that may be called on a class from the implementation of those services. A class defines methods (for operations) and event receptions (for signals, specified on the state machine). Both methods and event receptions include the lines of code that implement the service. An operation or signal is a specification only, and does not include such implementation detail.

Interfaces may not have implementation (either attributes or methods) and are not directly instantiable. A class is said to realize an interface if it provides a method for every operation specified in the interface, and those methods have the same names, parameters, return values, preconditions, and postconditions of the corresponding operations in the interface.

Che cos'è un esempio (o due!) di implementazione di un'interfaccia in C?
Da quello che sembra, è solo un prototipo di funzioni specifiche nel file di intestazione.

Ho rimosso UML e aggiunto l'interfaccia e il design orientato agli oggetti perché penso che la domanda gira attorno a questi argomenti piuttosto che su UML

    
posta efox29 14.10.2016 - 02:59
fonte

3 risposte

6

I linguaggi OOP lo fanno molto meglio, e anche in C ci sono modi migliori per farlo, ma qui c'è un esempio grezzo. Mostrerò un'interfaccia solo con i metodi - il concetto di ricezioni di eventi è più complesso, ma ortogonale a quello delle interfacce, e anche accanto a metodi e ricezioni di eventi ci possono essere altre cose che l'implementazione dell'interfaccia deve soddisfare, e io posso ' t mostrali tutti qui (sicuramente non in C!)

#include<stdio.h>

typedef struct {
    /// Prints a key-value pair, where value is an integer
    void (*printIntItem)(char key[], int value);
    /// Prints a key-value pair, where the value is a string
    void (*printStringItem)(char key[], char value[]);
} PrintInterface;


void json_printIntItem(char key[], int value) {
    printf("{\"%s\": %d}\n", key, value);
}
void json_printStringItem(char key[], char value[]) {
    printf("{\"%s\": \"%s\"}\n", key, value);
}
PrintInterface PrintJson() {
    PrintInterface interface;
    interface.printIntItem = json_printIntItem;
    interface.printStringItem = json_printStringItem;
    return interface;
}


void xml_printIntItem(char key[], int value) {
    printf("<%s>%d</%s>\n", key, value, key);
}
void xml_printStringItem(char key[], char value[]) {
    printf("<%s>%s</%s>\n", key, value, key);
}
PrintInterface PrintXml() {
    PrintInterface interface;
    interface.printIntItem = xml_printIntItem;
    interface.printStringItem = xml_printStringItem;
    return interface;
}


void printStuff(PrintInterface implementation) {
    implementation.printIntItem("one", 1);
    implementation.printStringItem("two", "2");
}

int main() {
    PrintInterface jsonImpl = PrintJson();
    printStuff(jsonImpl);

    PrintInterface xmlImpl = PrintXml();
    printStuff(xmlImpl);
    return 0;
}

PrintInterface è l'interfaccia. Ha due metodi: printIntItem e printStringItem . Il loro contratto può essere diviso in due parti:

  • Contratto esplicito - può essere applicato dalla lingua. Questa è la firma, ciò che accettano e ciò che restituiscono. Alcune lingue consentono di aggiungere più cose da applicare in questo contratto, ad es. quali eccezioni (errori) possono essere generate, come il metodo può interagire con altri dati, ecc. In questo caso tutto ciò che viene applicato è che i metodi accettano due argomenti - una stringa e una stringa / int - e non restituiscono nulla.
  • Contratto implicito - la documentazione, compreso ciò che può essere compreso dai nomi dei metodi e dai nomi dei loro argomenti. Il linguaggio non può far rispettare questo, quindi spetta al programmatore rispettare. È quasi sempre una cattiva idea ignorare quella parte del contratto - se l'autore si preoccupa di scrivere qualcosa nella documentazione di solito per un motivo, e anche gli utenti dell'interfaccia si aspettano che il contratto sia rispettato.

Ho anche scritto due implementazioni - PrintJson e %codice%. Quello che fanno è semplicemente mettere le funzioni dentro a PrintXml struct. I linguaggi / le librerie OOP corretti hanno molto di più modi efficienti e convenienti per farlo, ma questo è per il gusto di essere facile da seguire. Entrambi restituiscono un valore dello stesso tipo - PrintInterface - e quel tipo può essere passato agli utenti dell'interfaccia, come PrintInterface .

Quando si esegue questo programma, questo verrà stampato:

{"one": 1}
{"two": "2"}
<one>1</one>
<two>2</two>

Il primo printStuff viene chiamato con l'implementazione JSON. Utilizza l'API per stampare la coppia chiave-valore printStuff e quindi la coppia chiave-valore "one"->1 , e quindi "two"->"2" e {"one": 1} vengono stampati perché utilizza un'implementazione JSON.

Quindi viene chiamato {"two": "2"} con l'implementazione XML. Utilizza l'API per stampare la coppia chiave-valore printStuff e quindi la coppia chiave-valore "one"->1 , e quindi "two"->"2" e <one>1</one> vengono stampati perché ora utilizza un'implementazione XML.

    
risposta data 14.10.2016 - 05:13
fonte
1

Questo tipo di interfaccia è un concetto che non funziona molto bene al di fuori di un linguaggio almeno minimamente orientato agli oggetti.

Nel senso orientato agli oggetti, l'interfaccia sarà una classe su queste linee:

class/interface IEatable {
  public mustOverride void eatMe();
}

L'idea è che se qualche altra classe eredita / implementa l'interfaccia, il compilatore eseguirà un adattamento a meno che non fornisca una funzione eatMe corrispondente a tale firma. E poiché sai che è il caso, puoi in seguito fare qualcosa di simile

IEatable myEatable = some_function_returning_some_eatable_subclass();
myEatable.eatMe();

Senza preoccuparsi di quale tipo di commestibile hai a che fare in quel momento, perché il compilatore si sarà assicurato che quella funzione fosse valida su qualunque oggetto rotoli giù per la pipe.

Ora in C, non hai il supporto per la lingua praticamente per niente. Non è possibile dichiarare variabili che puntano a versioni leggermente diverse di quanto richiesto e non è possibile dichiarare tipi di dati che hanno funzioni incorporate. Ora probabilmente si potrebbe simulare questo comportamento con le strutture che contengono tabelle di puntatori di funzione, ma a quel punto si sta costruendo un sottosistema OO all'interno di C comunque. Questo è il genere di cose che i linguaggi OO fanno sotto il cofano, comunque.

    
risposta data 14.10.2016 - 04:27
fonte
0

C non supporta questo tipo di cose, in particolare perché è un concetto di OOP con un ruolo molto specifico. Penso che la spiegazione che hai ottenuto fosse molto scarsa, soprattutto perché non si parla mai del perché esistano interfacce. Quindi lo menzionerò qui.

Prima di tutto, un'interfaccia è molto simile a una classe, tranne che non puoi specificare alcuna implementazione. Qualsiasi classe che implementa un'interfaccia DEVE implementare TUTTI i metodi in essa contenuti. Questo è il modo più semplice per metterlo.

Ora un'interfaccia è un modo per designare concetti estremamente astratti che non condividono la stessa implementazione, pur mantenendo il polimorfismo. Un oggetto geometrico 2D è un esempio di qualcosa che potrebbe essere un'interfaccia. La ragione è che condividono tutti lo stesso concetto di un'area, ma il modo in cui si andrebbe a ottenere l'area dipende dalla forma specifica. Un quadrato è W H, un cerchio è pi r ^ 2, ecc. Quindi qualsiasi classe che implementa questa interfaccia sarebbe costretta ad implementare il proprio metodo di area. Un altro esempio potrebbe essere un veicolo, dal momento che tutti i veicoli hanno una proprietà simile: in movimento. Tuttavia un'auto, una barca e un aereo si muovono in modi completamente diversi.

Le interfacce sono spesso mal utilizzate. Molte persone useranno le interfacce per qualcosa che è troppo specifico. Un esempio che ho visto di recente stava usando un'interfaccia per rappresentare "alimenti congelabili". Questo è un esempio di uso improprio di un'interfaccia. Tutti i cibi posso pensare di congelare nello stesso modo. La loro temperatura viene ridotta in modo da rallentare la riproduzione dei batteri. Ora se doveva essere un "oggetto congelabile" Questo è un buon esempio di un'interfaccia, perché l'implementazione dell'acqua gelata non è la stessa cosa del congelamento della carne, né l'uno o l'altro sono uguali al congelamento dell'idrogeno (il che si traduce in un fenomeno interessante noto come super solido)

Se l'implementazione è la stessa per tutte le istanze, dovrebbe andare direttamente in una classe ed essere implementata. Inserirlo in un'interfaccia comporta la ripetizione del codice ed è un design estremamente scadente.

    
risposta data 14.10.2016 - 13:30
fonte

Leggi altre domande sui tag