Jaka jest różnica między prefiksami nazw metod „do” i „as” , np
- notować(),
- asList (),
- itp...
Kiedy stosować, który przy projektowaniu metody?
Jaka jest różnica między prefiksami nazw metod „do” i „as” , np
Kiedy stosować, który przy projektowaniu metody?
Odpowiedzi:
toXYZ()
Oczekuje się funkcja zrobić konwersję, i powrócić nowego niezależnego obiektu (choć niezmienność pozwala na optymalizację, java.lang.String.toString()
po prostu zwraca obiekt).
Na przykład w C ++ mamy coś, std::bitset::to_ulong()
co może łatwo zawieść, i całą masę to_string()
, wszyscy wykonują (mniej lub bardziej) złożoną konwersję i przydzielają pamięć.
Z asXYZ()
drugiej strony oczekuje się, że zwróci (potencjalnie inny) widok źródła, wykonując minimalną pracę.
Na przykład w C ++ mamy, std::as_const()
która po prostu zwraca stałą referencję, a bardziej zaangażowana, std::forward_as_tuple
która również odwołuje się do jej argumentów przez referencję.
std::to_string(x)
tworzy nowy ciąg znaków, ale std::as_const(x)
tworzy odwołanie (widok) do istniejącego obiektu.
Szczerze mówiąc, może to być tylko niekonsekwencja w nazewnictwie. Jeśli spojrzeć na standardowych obiektów bibliotecznych w Smalltalk, na przykład, wszystkie metody, które robią „kompleks konwersje” lub „powrót prostych reprezentacje w innego rodzaju” są poprzedzone as
, jak w asString
, asFloat
, asSeconds
, a średnia metoda przekształcania niczego do niczego innego, as: aClass
.
Ruby te same rodzaje metod są poprzedzone to_
, jak w to_s
, to_a
, to_h
, skrót string
, array
oraz hash
odpowiednio.
Wydaje się, że żadna standardowa biblioteka nie rozróżnia różnych rodzajów konwersji, prawdopodobnie dlatego, że należy ją traktować jako szczegół implementacji.
Jednak w Javie widzimy wiele pomyłek. Jak już wspomniano, istnieje toString
, asList
i tak dalej. Uważam, że to tylko niespójność w nazewnictwie, ponieważ jeśli spróbujesz zdefiniować inne znaczenie dla każdego prefiksu, zawsze znajdziesz kontrprzykład gdzieś indziej w standardowej bibliotece.
W każdym razie powiedziałbym, że ważne jest, abyś ty i twój zespół wybrali jeden prefiks i używali go konsekwentnie w całym kodzie. Spójność jest kluczem, więc ludzie nie mogą się zastanawiać, tak jak musieliście.
toString
tworzy nowy ciąg całkowicie odłączony od obiektu (i nie ma innego wyjścia z powodu niezmienności). To samo dotyczy np. For Collection#toArray
, podczas gdy Arrays#asList
zwraca widok tablicy, która jest dwukierunkowo połączona (mutacja tablicy zmienia listę i odwrotnie). Jest to więc dość spójne, choć mogą istnieć wyjątki. Wybór jednego prefiksu byłby nieprawidłowy. Jeśli tak Arrays#toList
, to spodziewam się, że utworzy nową listę z nową podstawową tablicą.
Chociaż istnieje już akceptowana odpowiedź, wydaje się, że koncentruje się na C ++, podczas gdy pytanie jest oznaczone java . W Javie pierwszym przykładem tego rodzaju pomysłów jest Arrays.asList , który zwraca w zasadzie widok tablicy zawiniętej w listę. Podstawowa tablica i lista są jednak nadal połączone; zmiany w tablicy są odzwierciedlone na liście i odwrotnie. Jednak tablica zwrócona przez metodę toArray listy jest niezależna od tablicy oryginalnej i od listy:
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"
}
To powiedziawszy, nie ma gwarancji, że każdy programista biblioteki przestrzega tej konwencji, więc nadal musisz sprawdzić dokumentację, aby dowiedzieć się, czy takie zachowanie otrzymasz od nieznanego kodu.
Innym miejscem, które często widziałem jako ... () metody, jest obniżanie typów do podtypów. Na przykład, jeśli masz wyliczony zestaw podtypów, możesz otrzymać kod taki jak:
/**
* 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();
}
}
}
Różnica, którą zauważyłem (właśnie teraz o tym myśląc), jest
Widzimy więc AsInteger i AsString oraz widzimy ToArray i ToStringList.
Implikować konwersję, która ma sens (jest to ruch, proces). Jak sugeruje reprezentacja, sposób wyrażenia oryginalnego obiektu.
Kolejny sposób na to:
I jest jeszcze „stan techniki” (lub spuścizna) do rozwiązania. Zanim języki byłyby od początku całkowicie OO, miałbyś funkcje biblioteczne takie jak StrToInt () i IntToStr (). Przeprowadzali konwersje, były operacjami, więc sensownie było nazywać je SomethingToSomethingelse (). W końcu To jest bardziej aktywne niż As. Szczególnie myślę tutaj o Delphi.
Kiedy C # został zaprojektowany z myślą o całkowitym przejściu OO, sensowne było posiadanie metody na obiekcie typu integer, który przekształciłby liczbę całkowitą w ciąg. Chociaż mamy również klasę Convert, konwersja na ciąg znaków jest tak powszechna, że została stworzona wirtualna metoda na obiekcie. Projektanci mogli zorientować się, że ToString byłby bardziej znany ludziom ze starego paradygmatu i być może dlatego otrzymaliśmy wirtualną metodę ToString (), a nie wirtualną właściwość AsString.
toString()
?