Perché le interfacce non sono castable / ducktypeable?

4

Una cosa che mi ha sempre infastidito (in C #) è che c'è una dura dipendenza tra un'interfaccia / classe astratta e la classe e l'assembly di implementazione. Ciò significa che se due diversi assembly implementano la stessa interfaccia, uno di essi deve fare riferimento all'altro (dove si trova l'interfaccia) oppure entrambi devono fare riferimento a un terzo assieme con l'interfaccia.

Rende più difficile testare separatamente le diverse parti di un'applicazione e rende il codice molto meno flessibile dal momento che devi implementare quella specifica interfaccia. Inoltre, rende meno ordinate le librerie di distribuzione a terze parti, in quanto se si desidera distribuire solo parte delle proprie funzionalità, è necessario rielaborare la classe per terze parti per includere l'interfaccia oppure disporre in alcuni casi di qualche assemblaggio sciocco che contiene un'interfaccia tranne una.

Non dovrebbe esserci un modo per avere interfacce impalpabili? Quindi, ad esempio se hai due oggetti con un metodo che prende un'interfaccia come parametro, e ogni assembly ha interfacce separate ma identiche, allora potresti scambiare i due.

Sono sicuro che ci sono casi in cui vogliamo che le buone e rigorose dipendenze dell'interfaccia che abbiamo adesso, ma anche avere la possibilità di "interfacce morbide", possano essere una buona idea? Oppure il concetto è troppo contorto e applicabile in troppe poche situazioni (come ad esempio l'ereditarietà multipla). Ci sono linguaggi che non sono completamente anonimi che hanno risolto questo problema e c'è forse qualche design pattern da usare per evitare la dipendenza?

Esempio:

Assembly A:

public interface ISomeInterface 
{
    ReadBooks();
    WriteLetters();
}

Public ClassA : SomeInterface
{
}

Assembly B:

public interface ISomeOtherInterface 
{
    ReadBooks();
    WriteLetters();
}

public class ClassB
{
    public DoStuff (ISomeOtherInterface someOtherInterface)
    {
      ....
    }
}

Qui mi piacerebbe avere un assembly C che faccia riferimento a A e B e facciate:

  ClassA classA = new ClassA();
  ClassB classB = new ClassB()
  classB.DoStuff(classA as ISomeOtherInterface);

Non esiste una dipendenza diretta tra A e B, ma possono ancora essere usati insieme. Immagino che in questa istanza potrei fare una classe dell'adattatore, ma sembra goffo e in alcuni casi non appropriato.

Il casting specifico è un modo per andare, un altro sarebbe dichiarare un'interfaccia come dinamica (o qualsiasi altra cosa) e quindi controllerebbe solo che le interfacce siano identiche (ma non che siano la stessa interfaccia). Un terzo modo sarebbe di essere in grado di specificare "dinamici" sui parametri in modo che l'oggetto possa consentire o impedire quel tipo di interfacce.

Forse dovrebbe essere il contrario, a meno che tu dichiari un'interfaccia come "esplicita", puoi sempre fare quel tipo di digitazione.

    
posta Homde 07.02.2011 - 19:54
fonte

6 risposte

6

L'intento di un'interfaccia è di separare completamente la firma del metodo dalla sua implementazione. Se fai riferimento a un oggetto rigorosamente tramite un'interfaccia, ma devi chiamare metodi che non sono specificati come parte dell'interfaccia, allora forse dovresti riconsiderare il tuo design.

    
risposta data 07.02.2011 - 20:24
fonte
4

Sono sempre divertito quando qualcuno chiede "perché questa caratteristica non esiste" quando effettivamente esiste. : -)

Sembra che tu voglia l'equivalenza di tipo "no pia", che è una funzionalità che abbiamo aggiunto in C # 4. Vedi questo articolo del blog per una breve introduzione:

link

Ti sembra il tipo di cosa che stai cercando?

    
risposta data 11.02.2011 - 01:04
fonte
3

Se più di una classe utilizza la stessa interfaccia, tale interfaccia deve essere pubblica e nel proprio file sorgente. Quindi le due classi sono completamente intercambiabili. Questo concetto è noto come polimorfismo. Puoi avere molte implementazioni, ma un modo per usarle.

Le API usano questo concetto. Java ha l'API del database. Definisce le operazioni sui database, ma non ha codice di impianto. Ciò è lasciato ai singoli fornitori di database che sanno come interfacciarsi con quel particolare database.

L'interfaccia è solitamente distribuita separatamente dalle implementazioni. Ciò consente all'utente di scegliere quale implementazione desidera semplicemente passando l'interfaccia piuttosto che l'impianto, cioè un Connection piuttosto che un AS400DatabaseConnection .

    
risposta data 07.02.2011 - 20:30
fonte
2

Quello che stai chiedendo è la tipizzazione strutturale. Un tipo implementa un'interfaccia se la firma del tipo (cioè la struttura) corrisponde all'interfaccia. Questo è molto utile quando si ha una dipendenza logica da un sottoinsieme di un'interfaccia o di una classe, ma non si vuole dipendere dall'intera interfaccia / classe.

Ecco una domanda di overflow dello stack simile: controlla il primo e il secondo risposte. Il secondo link a una libreria per farlo, anche se con la corrispondenza del tipo di runtime.

Questa sarebbe un'estensione molto utile, in quanto riduce l'accoppiamento, portando a un codice più comprensibile e rendendo più semplice il mocking.

    
risposta data 08.02.2011 - 21:15
fonte
0

Forse non capisco il tuo esempio correttamente, ma sembra che tu possa ottenere un po 'di ciò con le funzionalità che sono state aggiunte in .Net 4 come il tipo Dinamico. Non sono sicuro che tu possa fare tutto questo, ma alcuni dei parametri controllati sono possibili con l'uso di DynamicMetaObject.

    
risposta data 07.02.2011 - 20:55
fonte
0

Penso che quello che vuoi sia la parola chiave Dynamic. Ad esempio, di recente ho avuto un'istanza in cui i miei oggetti dominio avevano tutti 4 proprietà standard per convenzione ma non avevano un antenato comune. Sapendo che avevano queste proprietà, avevo una funzione che poteva prendere qualsiasi oggetto dominio come dinamico e manipolare quelle proprietà prima di passarlo al successivo nella catena. Quindi ho il ducktyping senza bisogno di una classe base o di un'interfaccia.

Puoi fare lo stesso nel tuo scenario.

    
risposta data 07.02.2011 - 20:57
fonte

Leggi altre domande sui tag