Qual è il vantaggio di utilizzare un'interfaccia che non impone nulla (interfaccia marker)?

3

Il codice base su cui sto lavorando fa un sacco di uso di interfacce che in realtà non impongono nulla. Sono in atto più per assicurarsi che un tipo 'sia un' qualcosa. Ad esempio:

   public class MyBatchTask : Task, ITask<MyTaskType>
   {
       ...

   public interface ITask<TId> : ITask where TId : ITaskId
   {}

   public interface ITaskId {}

   public abstract class Task : ITask
   {
     .... base methods

Quindi, ci stiamo assicurando che "MyBatchTask" sia un 'ITask, e che il' MyTaskType 'che dichiariamo nel parametro generico' sia un 'ITaskId', tuttavia queste stesse interfacce non impongono in realtà nulla specifica.

Quindi, OK questo è 'marcare' certi tipi come aventi un particolare significato semantico (o essere parte di una struttura / schema riconosciuta all'interno del codice), ma come può davvero aiutare quando l'interfaccia non impone alcun contratto? Rende il codice più astratto e più difficile da comprendere, quindi perché utilizzare questo tipo di modello? In pratica, nessuna delle interfacce è stata estesa nel tempo per far rispettare effettivamente qualsiasi contratto.

    
posta Johnny 14.06.2017 - 06:24
fonte

2 risposte

4

Questo modello può essere usato con buoni risultati, ma questo non sembra un esempio. Un buon esempio potrebbe essere quello di comunicare vincoli semantici / garanzie che altrimenti non cambiano l'API. Ad esempio, potresti avere un'interfaccia che rappresenta un tipo di operazione e un'interfaccia secondaria che indica che l'operazione è idempotente. Quindi restituire un IIdempotentOperation indica garanzie (previste) al consumatore e ricevere IIdempotentOperation indica ulteriori vincoli all'utente.

Ma devi avere qualcosa di cui parlare. Se l'interfaccia non ha (direttamente o indirettamente) alcun metodo, allora sta dicendo qualcosa sui metodi su tutti gli oggetti, ad es. Equals , o sta dicendo che l'oggetto è uno di un insieme di classi fisse e conosciute ai fini del type-casing tramite instanceof o simili. Forse questa è l'idea, ma poi è abbastanza brutto. Se non si fa riferimento a una situazione come quella di cui sopra, non c'è assolutamente alcun motivo per cui i parametri non siano completamente parametrici e non dice nulla per implementare tale interfaccia.

Dovrei chiarire che è ITaskId che sembra completamente inutile per me. Posso vedere che cosa ITask<> sta cercando di ottenere. Sarebbe necessario più contesto per stabilire se tali interfacce stanno aggiungendo valore. Ad eccezione degli scenari che ho descritto sopra, non c'è letteralmente alcuna differenza tra class Foo e class Foo : ITaskId . Allo stesso modo, avere un parametro di un metodo di tipo ITaskId non è diverso dall'avere un parametro di tipo Object (o, preferibilmente, astrarlo in un parametro di tipo generico). Semplicemente non c'è alcun vincolo semantico che sia persino informalmente espressivo perché non ci sono metodi per limitare. Di nuovo, a meno che non indichi in modo informale un vincolo su un metodo come Equals o ToString , semplicemente non c'è un comportamento per vincolare un vincolo. Direi anche che non è solo inutile avere il vincolo ITaskId , ad es. su TId , ma in realtà è un errore. Puoi sempre vincolare il parametro di tipo TId in qualsiasi uso particolare se necessario, ma può essere utile consentire a TId di essere tipi che non implementano ITaskId , come String , anche se solo durante un intermediario calcolo. La comunità Haskell si è imbattuta nei problemi di vincoli non necessari che limitano la flessibilità in modo doloroso con l'esempio più notevole essendo il tipo Complex che utilizzato per essere limitato ma ora non è (e in effetti il la funzione della lingua che consente di rimuovere i vincoli in tali posizioni poiché erano sempre non necessari).

    
risposta data 14.06.2017 - 06:56
fonte
-7

Non ci sono vantaggi, se non quello di fare appello ad altri sviluppatori che credono che ci sia un vantaggio. Leggerete molto su come le interfacce non sono le stesse delle semplici classi di base astratte, ma alla fine, l'unico scopo per le interfacce è fornire eredità multiple. Cioè, in quei linguaggi che forniscono interfacce, l'ereditarietà multipla delle classi non è implementata, e le interfacce forniscono un rimedio per questo difetto.

    
risposta data 15.06.2017 - 00:55
fonte

Leggi altre domande sui tag