Jaka jest różnica między prefiksami nazw metod „to” i „as”? [Zamknięte]

78

Jaka jest różnica między prefiksami nazw metod „do” i „as” , np

  • notować(),
  • asList (),
  • itp...

Kiedy stosować, który przy projektowaniu metody?

Daniel Hári
źródło

Odpowiedzi:

120

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_tuplektóra również odwołuje się do jej argumentów przez referencję.

Deduplikator
źródło
19
Okazuje się, że istnieje jakiś precedens w tym zakresie. Ogólnie rzecz biorąc, As [coś] będzie podobne do obsady, natomiast To [coś] buduje nowy obiekt (innego typu) niż istniejący. W przypadku ToList będzie to O (n) i prawie na pewno droższe niż „As”. Zobacz stackoverflow.com/questions/17968469/…
Robert Harvey
5
Jest to część wybierania opisowych nazw i nawet jeśli to szczególne rozróżnienie nie jest skodyfikowane w standardzie kodowania, jego naruszenie łamie zasadę najmniejszego zdziwienia .
Deduplicator
11
Opisałbym to jako instynktownie, pomyślałbym o „do” jako „zmiana na” i „jak” jako „traktować jak”. Pierwsze z nich oznacza pracę nad zmianą, drugie oznacza, że ​​jest to tylko różnica w sposobie pracy z tym.
Latty
6
Jeśli to coś znaczy, to powinno to znaczyć. Sugerowałbym, że często to nic nie znaczy, więc nie polegałbym na tym w losowym kodzie strony trzeciej (bez zobaczenia czegoś w dokumentacji). Dobrą konwencją byłoby jednak przyjęcie w bazie kodu.
Ben
4
Ta odpowiedź jest również poprawna w C ++: na przykład std::to_string(x)tworzy nowy ciąg znaków, ale std::as_const(x)tworzy odwołanie (widok) do istniejącego obiektu.
Quuxplusone
13

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, arrayoraz hashodpowiednio.

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, asListi 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.

MichelHenrich
źródło
1
Nie wierzę w: wybieranie jednego stylu dla całego zespołu, raczej konsekwentnie wybieranie jednego stylu dla podobnych przypadków w module.
Daniel Hári
12
W Javie toStringtworzy 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#asListzwraca 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ą.
maaartinus
Myślę, że Smalltalk popełnił tam błąd, nie zrozumieli konwencji. Jest to trudna konwencja do zrozumienia (a nawet zauważenia), ponieważ jest tak abstrakcyjna i nie ma szczególnego wpływu. Nawet sam czyn zadania tego pytania wymaga wglądu.
usr
3
@usr Smalltalk mógł zostać zaprojektowany, zanim stał się konwencją
Bergi
6

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();
      }
    }
  }
Joshua Taylor
źródło
1

Różnica, którą zauważyłem (właśnie teraz o tym myśląc), jest

  • Zwykle konwertuje na inny typ odwołania (nieco złożony obiekt)
  • Jak zwykle zwraca prosty typ wartości

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:

  • To jest operacją, więc użyłbyś jej do metod.
  • Jest to prosta reprezentacja, więc można jej użyć do właściwości.

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.

Martin Maat
źródło
3
Co toString()?
Deduplicator
Tu mnie masz. Myślę, że AsString byłby bardziej odpowiedni. Mam kilka myśli dodatków, zaktualizuję swoją odpowiedź.
Martin Maat
Nie sądzę, że ta odpowiedź naprawdę pasuje do konwencji w języku C #. Na przykład. Zarówno ToList (), jak i AsEnumerable () zwracają złożone obiekty, różnica polega na tym, że ToList () zawsze zwraca nowy obiekt, podczas gdy AsEnumerable () zwraca widok lub adapter nad oryginalnym obiektem.
JacquesB,
@JaquesB Widocznie zastosowano tu różne pomysły. Delphi ma właściwości AsInteger i AsString na obiektach TField (które zawierają pola bazy danych). Mogłem być przez to stronniczy. Ale z drugiej strony pytanie jest oznaczone Java, a nie C # lub Delphi.
Martin Maat,