Interfaccia / implementazione "Duck-type-y"

2

Non conosco il nome "corretto" di quel pattern, quindi mi piacerebbe descriverlo con un semplice esempio.

In C #, System.Windows.Window contiene un metodo ShowDialog . Posso definire un'interfaccia contenente questo metodo (più alcune altre funzionalità). Quando creo una nuova classe Window , erediterà da Window e potrò aggiungere la mia interfaccia. Ora, non devo assolutamente preoccuparmi del metodo ShowDialog : "magicamente" viene usato il metodo di Window , sebbene Window non conosca la mia interfaccia.

Un semplice codice di esempio:

public interface IMyWindow
{
    bool? ShowDialog();
    // some additional other methods/properties
}

public class MyWindow : Window, IMyWindow
{
    // ShowDialog is "magically" implemented by Window
    #region additional other methods/properties
    #endregion
}

public class MyClass
{
    public void DoSomething()
    {
        IWindow w = new MyWindow();
        bool? result = w.ShowDialog();
    }
}

Come si chiama quel modello? Quanto è comune il suo utilizzo? O è solo qualche effetto collaterale di altre funzionalità di. Netto, in realtà niente progettato intenzionalmente? In che modo altri linguaggi orientati agli oggetti si occupano di questo?

Modifica:

Molto tempo fa ho posto la domanda link - Ora utilizzerei un approccio basato sul metodo descritto sopra.

    
posta Bernhard Hiller 12.11.2018 - 11:01
fonte

4 risposte

1

Questa è un'istanza del modello di adattatore di classe , in cui si utilizza l'ereditarietà multipla da ereditare sia da una classe base sia da un'interfaccia a cui si desidera adattare la classe base. Il fatto che non sia necessario implementare esplicitamente la funzione dell'interfaccia è semplicemente un effetto collaterale di come le interfacce funzionano in C #.

    
risposta data 10.12.2018 - 14:54
fonte
5

Questo non è in realtà "magico", e per quanto ne so non esiste un nome specifico per questo. È il comportamento predefinito dell'implementazione dell'interfaccia.

Il problema principale della tua domanda non è che esista una caratteristica esplicita di "digitazione anatra" che abilita questo comportamento. Il problema principale è che fraintendete ciò che un contratto di interfaccia stipula e si aspetta da qualsiasi tipo che lo implementa.

public class MyWindow : Window, IMyWindow
{
    // ShowDialog is "magically" implemented by Window
}

Il fatto che tu lo chiami "magico" suggerisce che ti aspetti che un contratto di interfaccia richieda che questa classe implementi esplicitamente un determinato metodo, ma non è questo il caso.

Un esempio simile ma leggermente più semplice:

public interface ITest
{
    string ToString();
}

public class Test : ITest
{

}

Il compilatore non si lamenta. Poiché ogni classe eredita intrinsecamente da object e object ha già un metodo string ToString() , la classe Test soddisfa il contratto di interfaccia perché Test ha un metodo string ToString() .

È un equivoco piuttosto comune di ereditarietà, in cui gli sviluppatori pensano a una classe derivata e alla sua classe base come se fossero due elementi separati di "il pacchetto completo". Ma non è questo il caso.

A tutti gli effetti, quando si considera la classe derivata, le caratteristiche che sono definite nella classe base sono uguali in ogni modo alle caratteristiche che sono definite nella classe derivata stessa. La classe derivata funzionerebbe esattamente nello stesso modo se dovessi copiare / incollare la definizione della classe base all'interno della definizione della classe derivata (invece di usare l'ereditarietà).

Consideralo come una "classe parziale parziale". Due classi parziali operano esattamente come se fossero una singola definizione di classe - non c'è differenza tra i due (a parte la possibilità di diffonderlo su più file). Per l'esempio di ereditarietà, lo chiamo "one way" perché la classe derivata include la classe base, ma la classe base non include la classe derivata.

Da un commento che hai fatto:

System.Windows.Window does not know anything about my interface - from its point of view, the method declared in my interface just happens to coincide with one of its methods.

Ma non ti aspetti System.Windows.Window per implementare la tua interfaccia, motivo per cui le tue aspettative sono irrilevanti.

Tutto quello che stai facendo è aspettare MyWindow per implementare l'interfaccia IWindow , il cui contratto può essere riepilogato come "deve avere un metodo bool? ShowDialog() ".

MyWindow ha infatti un metodo bool? ShowDialog() . Se definisce esplicitamente il proprio metodo bool? ShowDialog() o ne eredita uno è assolutamente irrilevante. Il compilatore non si preoccupa del source del metodo, solo che esiste .

Pertanto il contratto ( MyWindow : IMyWindow ) è soddisfatto, quindi non si verifica alcun errore.

Come un'analogia molto semplice (e alquanto semplificata): quando voglio comprare una bevanda da $ 5, il negoziante si preoccupa da dove viene il denaro? Per esempio. Potrei pagare dalla mia eredità, avrei potuto guadagnare io stesso i soldi, l'avrei preso in prestito da un amico.
Al negoziante non importa da dove viene il denaro. A tutti i negozianti importa che ho $ 5 per pagare la bevanda.

    
risposta data 14.11.2018 - 10:04
fonte
1

Non penso che questo abbia un nome.

L'implementazione dell'interfaccia C # si basa sui metodi disponibili. I metodi di base sono disponibili. Mentre questo è in contrasto con C ++, dove un metodo da una base non sovrascrive il metodo astratto da un altro, C ++ non ha interfacce designate come tali. Java funziona allo stesso modo di C #.

A meno che non si riesca a trovare un linguaggio che abbia interfacce designate e si comportino diversamente da C # e Java, non è necessario nominare questa funzione; è solo il modo in cui le interfacce funzionano.

Se si desidera veramente richiamare la questione, è possibile chiamarla binding del metodo dell'interfaccia esplicita con il binding del metodo dell'interfaccia implicita. Nota che C # ha la funzione "implementazione dell'interfaccia esplicita".

    
risposta data 14.11.2018 - 10:09
fonte
0

Non sono sicuro di quale sia il punto di questa costruzione. Tutto ciò che implementa un'interfaccia è una promessa che esiste una certa firma in quella classe - non importa se la classe definisce il metodo stesso o se lo eredita.

Ora, MyWindow garantisce già che il metodo esiste perché estende Window , quindi l'ulteriore promessa fatta tramite IMyWindow non fa nulla. Questo ha senso solo se si desidera utilizzare tali oggetti in un contesto in cui preferisci non conoscere gli oggetti Window , solo circa IMyWindow . Questo potrebbe essere chiamato una forma di segregazione di interfaccia .

Ma è probabile? Anche se non vuoi gestire tutta la complessità dell'API di Window , vorresti probabilmente mostrare le finestre di dialogo senza ricorrere alla classe Window di sistema? Pianifichi altre classi che mostrano dialoghi tramite un canale completamente diverso?

    
risposta data 12.11.2018 - 11:55
fonte

Leggi altre domande sui tag