Qual è la differenza tra "to" e "as" come i prefissi dei nomi dei metodi
- elencare(),
- asList (),
- eccetera...
Quando usare quale quando si progetta un metodo?
Qual è la differenza tra "to" e "as" come i prefissi dei nomi dei metodi
Quando usare quale quando si progetta un metodo?
Risposte:
Si toXYZ()
prevede che una funzione esegua una conversione e restituisca un nuovo oggetto indipendente (sebbene l'immutabilità consenta l'ottimizzazione, java.lang.String.toString()
restituisce semplicemente l'oggetto).
Ad esempio, in C ++ abbiamo std::bitset::to_ulong()
che può facilmente fallire, e un'intera pletora to_string()
, facendo una conversione (più o meno) complessa e allocando memoria.
asXYZ()
D'altra parte, una funzione dovrebbe restituire una vista (potenzialmente diversa) della sorgente, facendo un lavoro minimo.
Ad esempio, in C ++ abbiamo std::as_const()
che restituisce solo un riferimento costante, e più coinvolto, std::forward_as_tuple
che fa riferimento anche ai suoi argomenti per riferimento.
std::to_string(x)
crea un nuovo oggetto stringa, ma std::as_const(x)
crea un riferimento (una vista) dell'oggetto esistente.
Onestamente, potrebbe essere solo nominare l'incoerenza. Se ad alcuni oggetti di libreria standard di Smalltalk, per esempio, tutti i metodi che fanno "conversioni complesse" o "ritorno rappresentazioni semplici in un altro tipo" sono preceduti dal prefisso as
, come in asString
, asFloat
, asSeconds
, e il metodo standard per la conversione di qualsiasi cosa a qualsiasi altra cosa, as: aClass
.
In Ruby, gli stessi tipi di metodi sono precedute to_
, come to_s
, to_a
, to_h
, abbreviazione di string
, array
e hash
rispettivamente.
Nessuna delle librerie standard sembra distinguere tra diversi tipi di conversioni, probabilmente perché dovrebbe essere considerata come un dettaglio di implementazione.
Tuttavia, in Java vediamo un sacco di confusione. Come lei ha ricordato, c'è toString
, asList
e così via. Credo che queste siano solo un'incoerenza nella denominazione, perché se provi a definire un significato diverso per ciascun prefisso, troverai sempre un contro-esempio da qualche altra parte nella libreria standard.
Quindi, in ogni caso, direi che è importante che tu e il tuo team scegliate un prefisso e lo utilizziate in modo coerente in tutto il codice. La coerenza è la chiave, quindi le persone non sono lasciate a meravigliarsi, come dovevi.
toString
crea una nuova stringa completamente disconnessa dall'oggetto (e non c'è altro modo a causa dell'immutabilità). Lo stesso vale, ad esempio, per Collection#toArray
, mentre Arrays#asList
restituisce una vista dell'array, che è collegata in modo bidirezionale (la modifica dell'array modifica l'elenco e viceversa). Quindi è abbastanza coerente, anche se potrebbero esserci delle eccezioni. Scegliere un prefisso sarebbe sbagliato. Se ci fosse Arrays#toList
, mi aspetto che crei un nuovo elenco con un nuovo array sottostante.
Anche se c'è già una risposta accettata, sembra concentrarsi sul C ++, mentre la domanda è taggata con Java . In Java, il primo esempio che viene in mente per questo tipo di cose è Arrays.asList , che restituisce, essenzialmente, una vista di un array, racchiuso in un elenco. L'array sottostante e l'elenco sono comunque connessi; le modifiche all'array si riflettono nell'elenco e viceversa. Tuttavia, l'array restituito dal metodo toArray dell'elenco è indipendente dall'array originale e dall'elenco:
String[] wordArray = {"one", "fine", "day"};
List<String> wordList = Arrays.asList(wordArray);
// changes to the array are visible in the list
System.out.println(wordList); // prints "[one, fine, day]"
wordArray[1] = "horrible";
System.out.println(wordList); // prints "[one, horrible, day]"
// changes to the list are visible in the array
wordList.set(1, "beautiful");
System.out.println(wordArray[1]); // prints "beautiful"
// but changes to the list or array don't affect the
// result from the list's toArray method.
String[] moreWords = wordList.toArray(new String[] {});
wordList.set(0, "the");
wordArray[1] = "best";
for (int i=0; i<3; i++) {
System.out.println(moreWords[i]); // prints "one", "beautiful", and "day"
}
Detto questo, non c'è garanzia che ogni sviluppatore di biblioteche segua questa convenzione, quindi è comunque necessario controllare la documentazione per scoprire se questo è il comportamento che si otterrà da un codice sconosciuto.
L'altro posto che ho visto come metodi ... () usati frequentemente è nei tipi di downcasting ai sottotipi. Ad esempio, se si dispone di un insieme enumerato di sottotipi, si potrebbe finire con un codice come:
/**
* Every Node is either an ANode or a BNode.
*/
interface Node {
/**
* Returns this Node as an ANode.
*
* @return this node
*/
default ANode asANode() {
if (this instanceof ANode) {
return (ANode) this;
}
else {
throw new UnsupportedOperationException();
}
// Or, in Java8 style, perhaps:
// return Optional.of(this)
// .filter(ANode.class::isInstance)
// .map(ANode.class::cast)
// .orElseThrow(UnsupportedOperationException::new);
}
/**
* Returns this Node as a BNode.
*
* @return this node
*/
default BNode asBNode() {
if (this instanceof BNode) {
return (BNode) this;
}
else {
throw new UnsupportedOperationException();
}
}
}
La differenza che ho notato (solo ora pensandoci) è
Quindi vediamo AsInteger e AsString e vediamo ToArray e ToStringList.
Implica una conversione, che ha senso (è un movimento, un processo). Come implica una rappresentazione, un modo di esprimere l'oggetto originale.
Un altro modo di guardare a questo:
E poi c'è "arte nota" (o eredità) da affrontare. Prima che le lingue fossero completamente OO da zero, avresti funzioni di libreria come StrToInt () e IntToStr (). Eseguivano conversioni, erano operazioni, quindi aveva senso chiamarle SomethingToSomethingelse (). Dopotutto, To è più attivo di As. Sto pensando in particolare a Delphi qui.
Quando C # è stato progettato con l'ambizione di andare OO fino in fondo, aveva senso avere un metodo sull'oggetto ora intero che convertisse l'intero in una stringa. Anche se abbiamo anche una classe Convert, la conversione in stringa è così comune che è stato creato un metodo virtuale sull'oggetto. I progettisti potrebbero aver capito che ToString sarebbe più familiare alle persone del vecchio paradigma e forse questo è il motivo per cui abbiamo ottenuto un metodo virtuale ToString () e non una proprietà virtuale AsString.
toString()
?