Se Class deve definire attributi e metodi e Interface deve definire (un insieme di) metodi, allora come pensare all'interfaccia che richiede nuovi attributi?

3

Ho pensato che una classe dovrebbe definire, o dare un progetto, attributi e metodi per un oggetto. E poi un'interfaccia è fornire un insieme di metodi, come un contratto per i suoi clienti. (e quindi anche una classe fornisce un'interfaccia, perché una classe definisce anche un insieme di metodi).

Ma diciamo, se abbiamo una classe chiamata Shape. Ora aggiungiamo un'interfaccia ad esso, chiamata Moveable. Ora potremmo dover aggiungere attributi alla classe, come velocity . Ma l'interfaccia riguarda solo i metodi, quindi come dovremmo pensare di aggiungere attributi alla classe a causa dell'interfaccia?

    
posta 太極者無極而生 03.01.2016 - 13:59
fonte

6 risposte

4

Dovresti pensare a un'interfaccia come a un requisito fatto da qualcun altro.

Dovresti pensare a un'implementazione che soddisfi i requisiti come una decisione che prendi per la tua classe.

Nella maggior parte dei linguaggi OO, lo stato della classe è un problema di implementazione.

Pertanto, getVelocity ben implementato è qualcosa che è necessario per fornire un comportamento che soddisfi i requisiti di qualcun altro. È possibile implementare tale requisito in qualsiasi tecnica che funzioni per voi. Se vuoi memorizzare velocity come intero, o calcolarlo al volo da una coda di eventi di posizione e tempo recentemente campionati, questa è la tua prerogativa.

Certo, non è necessario ricorrere costantemente a semplici metodi semplici. C'è una soluzione a questo in molte lingue OOP: il Mixin . A seconda della lingua, i Mixin possono avere vincoli molto diversi, in particolare lo stato w / r / t.

Le impls predefinite Java, ad esempio, non hanno uno stato proprio, ma possono accedere agli altri metodi dell'interfaccia. Quindi potrebbe essere richiesto di implementare getVelocity, ma tutti i calcoli coinvolti con velocity potrebbero offrire un'implementazione predefinita.

Nel frattempo, i tratti in Scala sono così completi che è comune vedere programmi le cui implementazioni sono scritte quasi esclusivamente in tratti piuttosto che in classi (le realizzazioni concrete sono quindi fornite da oggetti e classi caso)

Nelle lingue senza mixin, la delega è una soluzione comune, in cui la classe che adotta un'interfaccia avrà anche una classe membro privata che fornisce il comportamento. La classe originale implementerà comunque direttamente i metodi dell'interfaccia, ma nel corpo di questi metodi semplicemente delegherà la chiamata al membro privato.

    
risposta data 03.01.2016 - 19:03
fonte
1

Un'interfaccia può essere pensata come un comportamento, o un ruolo, che uno o più oggetti possono mostrare.

Una forma potrebbe essere mobile , come molte altre cose. Con un'interfaccia mobile, si può iniziare a lavorare con cose che sono mobili senza riguardo a quello che sono.

Se ti rendi conto che l'implementazione interna del tuo oggetto deve cambiare, non influisce sul concetto separato di un particolare comportamento (interfaccia). Se, tuttavia, ti rendi conto che il comportamento deve cambiare, probabilmente dovrai modificare tutte quelle cose (oggetti) che hanno quel comportamento.

Se velocity è solo un dettaglio di implementazione interno di un oggetto, non ha alcuna interfaccia (comportamento). Se tuttavia ti rendi conto che il comportamento rappresentato dall'interfaccia è stato definito in modo errato e ora richiede velocità, è necessario modificare l'interfaccia e ciascun oggetto che presenta l'interfaccia di conseguenza.

Si spera che si possa iniziare a vedere che l'oggetto e l'interfaccia sono due concetti separati . Sono ortogonali tra loro.

    
risposta data 07.01.2016 - 08:47
fonte
1

Attributi come velocity sono dettagli di implementazione e quindi non appartengono alle interfacce. L'interfaccia non ti impone di aggiungere attributi, è l'implementazione scelta che lo fa. Un'implementazione può utilizzare l'attributo velocity e l'altro usa acceleration .

Quindi non si aggiungono attributi a causa dell'interfaccia, si aggiungono attributi a causa dell'implementazione selezionata. Di solito è il programmatore che decide come implementare un'interfaccia, non l'interfaccia stessa.

    
risposta data 03.01.2016 - 14:29
fonte
1

C'è già una bella risposta, ma ho notato questa parte:

I might think of Interface as just multiple inheritance, but just that we don't want to have the issues of multiple inheritance [...]

Immagino che tu stia lavorando in una lingua in cui la nozione di "interfaccia" è rigorosamente priva di status. Trovo spesso quelli in qualche modo pesanti e penso che l'ereditarietà multipla non sia così disordinata come alcuni lo fanno sembrare.

Tuttavia, a livello concettuale, l'interfaccia stateless è spesso la più generale, la più ideale dal punto di vista contrattuale e di manutenzione.

Robot con ruote

Ad esempio, immagina di aver scritto una barca di codice usando un'interfaccia robotica che comandava ai robot di andare in vari luoghi (stanze, edifici, paesi).

Se detta interfaccia includesse attributi come l'idea che un robot abbia ruote, ciò accoppiasse le mie richieste all'idea che un robot abbia ruote. Le mie richieste sarebbero quindi valide solo per i robot dotati di ruote (potrebbero comunque essere in grado di andare in nuove posizioni usando altri mezzi di trasporto, ma almeno richiedono possedere ruote per farlo) p>

Che degenera il concetto di robot a chi possiede almeno ruote e allo stesso modo degeneralizza tutte le richieste che ho fatto per i robot di andare in posti nuovi che potrebbero estendersi su decine di migliaia di linee di codice, ad es.

Ora diciamo che è stato introdotto un nuovo robot che ha gambe, o un jetpack, o un trasportatore molecolare e in realtà non aveva affatto bisogno di ruote. Questo crea problemi per tutte le classi di robot esistenti e tutti i codici esistenti che li utilizzano attraverso questa interfaccia. Ora siamo in una posizione piuttosto scomoda di dover riscrivere un sacco di codice che non saremmo in se l'interfaccia / contratto per i robot fosse senza stato.

Le interfacce flessibili consentono varietà

In generale, le interfacce più ideali dal punto di vista dell'uscita del codice che è resiliente al cambiamento lasceranno molto spazio a una ricca varietà di implementazioni concrete senza violare il contratto dell'interfaccia. Una volta che lo stato viene introdotto in un'interfaccia, spesso degrada molto rapidamente la ricchezza e può ridurre significativamente la varietà di possibili soluzioni.

Questo dovrebbe essere forzato in modo assoluto in una progettazione linguistica? Non lo so - sono prevenuto come uno che preferisce le lingue che non lo forzano. Tuttavia, penso che sia generalmente molto meglio se commettiamo errori verso interfacce senza stato. Un attributo / stato molto più rapidamente degraderà la generalità delle tue astrazioni rispetto alle funzioni.

But interface is only about methods, then how would we think about adding attributes to the class due to interface?

Questi sono problemi di implementazione. Se l'obiettivo di una classe che implementa un'interfaccia Movable è di spostarsi in nuove posizioni, è possibile implementare tutti i tipi di metodi e rappresentare anche i dati necessari per farlo. Cerca di apprezzare questa flessibilità / libertà.

Probabilmente una preoccupazione qui è che, dopo la dozzina di classe o giù di lì, ti sembra di duplicare molto lo stesso tipo di piastra per implementare un'interfaccia. In tal caso, puoi raggiungere potenzialmente una classe base astratta, o usare la composizione (memorizzare un membro che fa un sacco di gruntwork), possibilmente metodi statici (forse la più grossolana, comunque, se inizia ad assomigliare a una funzionalità di helper anonimo) , ecc.

Ma prova a tenere a mente quanto sia flessibile l'interfaccia in quanto è stateless, di non menzionare dettagli concreti come parte del suo contratto.

    
risposta data 03.01.2016 - 18:46
fonte
0

Non si crea una classe e quindi si crea un'interfaccia per essa. Si sta facendo completamente indietro. Il creatore di una classe non dovrebbe mai controllare la definizione di interfacce supportata dalla classe.

Un'interfaccia è definita da qualcuno al di fuori della classe. Qualcuno dice "Ho bisogno di un oggetto qui, e non mi interessa affatto che tipo di oggetto sia, purché abbia questo insieme di capacità". E quella persona definisce l'interfaccia.

Qualcun altro potrebbe poi arrivare e dicono "Voglio creare una nuova classe che possa essere usata quando qualcuno ha bisogno di un oggetto con quell'interfaccia, e non per altro", e creare una classe che corrisponda molto strettamente l'interfaccia e nient'altro.

In alternativa dicono "Ho qui questa istanza di una classe che ho scritto molto tempo fa, e mi piacerebbe quell'istanza in una situazione in cui è necessario un oggetto con quell'interfaccia". E poi aggiungono tutto il necessario per implementare l'interfaccia alla classe, possibilmente creando nuovi metodi che chiamano solo altri metodi che erano già presenti ma che non corrispondono ai requisiti dell'interfaccia o che aggiungono metodi completamente nuovi.

Specialmente nel secondo caso, l'interfaccia e i suoi metodi sono non come si suppone usino le istanze della classe; l'implementazione dell'interfaccia è un codice specializzato per poter collegare le istanze ad altri codici esistenti.

    
risposta data 07.01.2016 - 10:00
fonte
0

IMHO

Preferisco non esporre le variabili interne della classe, come in questo codice:

person.name="sampleName";
s = person.name;

Mi piace incapsulare le cose in modo che i consumatori non siano accoppiati ai componenti interni di una classe.

Significa che utilizzo getter e setter per accedere o modificare lo stato interno, in questo modo:

person.setName("sampleName");
s = person.getName();

In questo modo tengo i membri privati o protetti.

Che ha spiegato, un'interfaccia valida potrebbe essere:

public interface Person {
     public void setName(String value);
     public String getName();
     public void doSomething();
}

Che implica uno stato in una classe che lo ostacola. Forse gli implementatori avranno un membro di classe name di tipo String.

Bottom line:

Le interfacce possono in un certo senso costringere gli implementatori ad avere attributi, solo non esposti in modo pubblico ma usando getter e setter.

    
risposta data 07.01.2016 - 13:40
fonte

Leggi altre domande sui tag