In Ruby, che cosa è l'equivalente di un'interfaccia in C #?
-
29-09-2019 - |
Domanda
Al momento sto cercando di imparare Ruby e sto cercando di capire di più su ciò che offre in termini di incapsulamento e contratti.
In C # un contratto può essere definito utilizzando un'interfaccia. Una classe che implementa l'interfaccia deve soddisfare le condizioni all'interno del contratto, fornendo un'implementazione per ciascun metodo e proprietà (e forse altre cose) definito. La classe individuo che implementa un'interfaccia possono fare ciò di cui ha bisogno nell'ambito di applicazione dei metodi definiti dal contratto, a patto che accetti gli stessi tipi di argomenti e restituisce lo stesso tipo di risultato.
C'è un modo per far rispettare questo genere di cose in Ruby?
Grazie
Un semplice esempio di ciò che intendo in C #:
interface IConsole { int MaxControllers {get;} void PlayGame(IGame game); } class Xbox360 : IConsole { public int MaxControllers { get { return 4; } } public void PlayGame(IGame game) { InsertDisc(game); NavigateToMenuItem(); Click(); } } class NES : IConsole { public int MaxControllers { get { return 2; } } public void PlayGame(IGame game) { InsertCartridge(game); TurnOn(); } }
Soluzione
Non ci sono interfacce in rubino dal rubino è un linguaggio tipizzato in modo dinamico. Interfacce sono fondamentalmente utilizzati per rendere classi diverse intercambiabile senza rompersi sicurezza tipo. Il tuo codice può lavorare con tutte le console il più a lungo si comporta come una console, che in C # mezzi attrezzi IConsole. "Duck typing" è una parola chiave è possibile utilizzare per recuperare il ritardo con il linguaggi dinamici modo di trattare con questo tipo di problema.
Inoltre si può e deve scrivere unit test per verificare il comportamento del codice. Ogni oggetto ha un metodo respond_to?
è possibile utilizzare nel vostro assert.
Altri suggerimenti
Ruby ha Interfacce , proprio come qualsiasi altra lingua.
Nota non che bisogna stare attenti a confondere il concetto di Interfaccia , che è una specifica astratta delle responsabilità, garanzie e protocolli di un'unità con il concetto di interface
che è un parola chiave nel Java, C # e VB.NET linguaggi di programmazione. In Ruby, usiamo l'ex tutto il tempo, ma quest'ultimo semplicemente non esiste.
E 'molto importante distinguere i due. Quello che è importante è il Interfaccia , non il interface
. Il interface
ti dice praticamente nulla di utile. Nulla lo dimostra meglio del Marker interfacce in Java, che sono interfacce che non hanno membri a tutti: basta dare un'occhiata a java.io.Serializable
e java.lang.Cloneable
; quei due interface
s significano molto cose diverse, eppure hanno il esattamente lo stesso firma.
Quindi, se due interface
s che le cose medi diverse, hanno la stessa firma, che cosa esattamente è il interface
anche garantendovi?
Un altro buon esempio:
interface ICollection<T>: IEnumerable<T>, IEnumerable
{
void Add(T item);
}
Qual è la Interfaccia di System.Collections.Generic.ICollection<T>.Add
?
- che la lunghezza della collezione non diminuisce
- che tutti gli elementi che erano nella collezione prima che sono ancora lì
- che
item
è nella collezione
E che di quegli spettacoli in realtà nella interface
? Nessuna! Non c'è nulla nella interface
che dice che il metodo Add
deve anche Aggiungi a tutti, potrebbe altrettanto bene Rimuovi un elemento della collezione.
Questo è un perfettamente valida attuazione di tale interface
:
class MyCollection<T>: ICollection<T>
{
void Add(T item)
{
Remove(item);
}
}
Un altro esempio: dove nel java.util.Set<E>
vuol davvero dire che è, si sa, un set ? Da nessuna parte! O più precisamente, nella documentazione. In inglese.
In quasi tutti i casi di interfaces
, sia da Java e .NET, tutto il rilevanti informazioni è in realtà nella documentazione, non nei tipi. Quindi, se i tipi non dicono nulla di interessante in ogni caso, perché tenerli a tutti? Perché non attaccare solo alla documentazione? E questo è esattamente quello che fa Ruby.
Si noti che ci sono altri lingue in cui il Interfaccia può effettivamente essere descritto in modo significativo. Tuttavia, queste lingue in genere non chiamano il costrutto che descrive il Interfaccia "interface
", lo chiamano type
. In un linguaggio di programmazione dipendente tipizzato, è possibile ad esempio esprimere le proprietà che una funzione sort
restituisce un insieme della stessa lunghezza dell'originale, che ogni elemento che è in originale è anche nella raccolta differenziata e che non appare elemento più grandi prima di un elemento più piccolo.
Così, in breve: Rubino non ha un equivalente ad un interface
Java. E ' ha tuttavia avere un equivalente ad un Java Interfaccia , e la sua esattamente come in Java:. Documentazione
Inoltre, proprio come in Java, Test di collaudo può essere utilizzato per specificare Interfaccia S pure.
In particolare, in rubino, il Interfaccia di un oggetto è determinato da ciò che possono do , non quello class
si è, o quali module
mescola in. Qualsiasi oggetto che ha un metodo <<
può essere aggiunto a. Questo è molto utile nel test di unità, dove si can semplicemente passano in un Array
o un String
al posto di un Logger
più complicata, anche se Array
e Logger
non condividono un interface
esplicito a parte il fatto che entrambi hanno un metodo chiamato <<
.
Un altro esempio è StringIO
, che implementa la stessa Interfaccia come IO
e quindi una grande porzione del Interfaccia di File
, ma senza condividere alcun antenato comune oltre Object
.
Interfacce di solito sono introdotti ai linguaggi OO digitato statiche, al fine di compensare la mancanza di ereditarietà multipla. In altre parole, sono più di un male necessario che qualcosa di utile per se .
Ruby, d'altra parte:
- è dinamicamente tipizzato lingua con "duck typing", quindi se si desidera chiamare il metodo
foo
su due oggetti, non hanno bisogno di nessuno eredita stessa classe antenata, né implementare la stessa interfaccia. - supporta l'ereditarietà multipla attraverso concetto di mixins, ancora una volta senza necessità di interfacce qui.
Ruby non hanno davvero di loro; interfacce e contratti in genere vivono più nel mondo statico, piuttosto che la dinamica.
C'è una gemma chiamata Stretta di mano in grado di implementare i contratti informali, se si ha realmente bisogno.
rubino utilizza il concetto di moduli come stand-in (pò) per le interfacce. Design Patterns in Ruby ha un sacco di veramente grandi esempi sulle differenze tra i due concetti e perché rubino sceglie l'alternativa più flessibile alle interfacce.
http://www.amazon.com/Design-Patterns-Ruby-Russ -Olsen / dp / 0321490452
Jorg ha un buon punto, Ruby ha interfacce, non solo la parola chiave. Nel letto alcune delle risposte, credo che questo è un aspetto negativo in linguaggi dinamici. Invece di far rispettare un'interfaccia attraverso il linguaggio, è necessario creare unit test invece di avere un compilatore metodi di cattura non in corso di attuazione. E 'anche il metodo comprensione più difficile ragionare su, come si deve dare la caccia a quello che un oggetto è quando si sta cercando di chiamarlo.
Prendete come esempio:
def my_func(options)
...
end
Se si guarda alla funzione, non avete idea di cosa opzioni è e quali metodi o proprietà che dovrebbe chiamare, senza la caccia per i test di unità, in altri luoghi è chiamato, e ancora di guardare il metodo. Peggio ancora, il metodo può anche non utilizzare queste opzioni, ma passarlo a ulteriori metodi. Perché unità di scrivere i test quando questo avrebbe dovuto essere catturato da un compilatore. Il problema è che è necessario scrivere codice in modo diverso per esprimere questo aspetto negativo in linguaggi dinamici.
C'è un rialzo per questo, però, e questo è linguaggi di programmazione dinamici sono FAST per scrivere un pezzo di codice. Non ho di scrivere qualsiasi dichiarazione di interfaccia e poi posso nuovi metodi e parametri senza andare al interfaccia per esporlo. I compromessi sono la velocità per la manutenzione.