Qual é a diferença entre os prefixos "to" e "as" do nome do método, como
- listar(),
- asList (),
- etc ...
Quando usar qual ao projetar um método?
Qual é a diferença entre os prefixos "to" e "as" do nome do método, como
Quando usar qual ao projetar um método?
Respostas:
A toXYZ()
função é esperado para fazer uma conversão, e para retornar uma nova independente objeto (embora imutabilidade permite a otimização, java.lang.String.toString()
apenas retorna o objeto).
Como exemplo, em C ++, temos o std::bitset::to_ulong()
que pode falhar facilmente e toda uma infinidade de to_string()
, todos fazendo uma conversão (mais ou menos) complexa e alocando memória.
Uma asXYZ()
função, por outro lado é esperado para retornar uma visão (potencialmente diferente) da fonte, fazendo o mínimo de trabalho.
Como exemplo, em C ++, temos o std::as_const()
que apenas retorna uma referência constante e o mais envolvido, std::forward_as_tuple
que também se refere a seus argumentos por referência.
std::to_string(x)
cria um novo objeto de seqüência de caracteres, mas std::as_const(x)
cria uma referência (uma exibição) do objeto existente.
Honestamente, pode ser apenas nomear inconsistência. Se olhar para objetos de biblioteca padrão em Smalltalk, por exemplo, todos os métodos que fazem "conversões complexas" ou "retornar representações simples em outro tipo" são prefixados com as
, como em asString
, asFloat
, asSeconds
, e o método padrão para converter qualquer coisa para qualquer outra coisa, as: aClass
.
Em Ruby, os mesmos tipos de métodos têm o prefixo to_
, como em to_s
, to_a
, to_h
, para curto string
, array
e hash
respectivamente.
Nenhuma das bibliotecas padrão parece diferenciar entre diferentes tipos de conversões, provavelmente porque deve ser considerada como um detalhe de implementação.
No entanto, em Java, vemos muitas confusões. Como você mencionou, há toString
, asList
e assim por diante. Acredito que essas são apenas uma inconsistência de nomes, porque se você tentar definir um significado diferente para cada prefixo, sempre encontrará um contra-exemplo em algum outro lugar da biblioteca padrão.
Portanto, em qualquer caso, eu diria que o importante é que você e sua equipe escolham um prefixo e o usem consistentemente em todo o código. A consistência é a chave, para que as pessoas não se perguntem como você precisava.
toString
cria uma nova string totalmente desconectada do objeto (e não há outra maneira por causa da imutabilidade). O mesmo vale, por exemplo, para Collection#toArray
, enquanto Arrays#asList
retorna uma visão da matriz, que é bidirecionalmente conectada (a mutação da matriz altera a lista e vice-versa). Portanto, é bastante consistente, embora possa haver exceções. Escolher um prefixo estaria errado. Se houvesse Arrays#toList
, esperaria criar uma nova lista com uma nova matriz subjacente.
Embora já exista uma resposta aceita, parece focar em C ++, enquanto a pergunta está marcada com java . Em Java, o primeiro exemplo que vem à mente para esse tipo de coisa é Arrays.asList , que retorna, essencialmente, uma visão de uma matriz, agrupada em uma lista. A matriz subjacente e a lista ainda estão conectadas; as alterações na matriz são refletidas na lista e vice-versa. No entanto, a matriz retornada pelo método toArray da lista é independente da matriz original e da lista:
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"
}
Dito isso, não há garantia de que todos os desenvolvedores de bibliotecas sigam essa convenção; portanto, você ainda precisa verificar a documentação para descobrir se esse é o comportamento que você obterá do código desconhecido.
O outro lugar que eu vi como métodos ... () usado com freqüência é nos tipos de downcast para subtipos. Por exemplo, se você tiver um conjunto enumerado de subtipos, poderá acabar com um código como:
/**
* 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();
}
}
}
A diferença que notei (agora pensando nisso) é
Então, vemos AsInteger e AsString e ToArray e ToStringList.
Implica uma conversão, que faz sentido (é um movimento, um processo). Como implica uma representação, uma maneira de expressar o objeto original.
Outra maneira de olhar para isso:
E depois há "arte anterior" (ou legado) para lidar. Antes que os idiomas fossem totalmente OO desde o início, você teria funções de biblioteca como StrToInt () e IntToStr (). Eles realizaram conversões, eram operações, por isso fazia sentido chamá-los de SomethingToSomethingelse (). Afinal, To é mais ativo que As. Estou pensando particularmente em Delphi aqui.
Quando o C # foi projetado com a ambição de fazer OO até o fim, fazia sentido ter um método no objeto agora inteiro que converteria o número inteiro em uma string. Embora também tenhamos uma classe Convert, a conversão em string é tão comum que se tornou um método virtual no objeto. Os designers podem ter imaginado que o ToString seria mais familiar para as pessoas do antigo paradigma e talvez seja por isso que obtivemos um método virtual ToString () e não uma propriedade virtual AsString.
toString()
?