Яка різниця між префіксами назви методу "до" та "як"? [зачинено]


78

Яка різниця між префіксами назви методу "до" та "як"

  • toList (),
  • asList (),
  • тощо ...

Коли використовувати який при розробці методу?

Відповіді:


120

Очікується, що toXYZ()функція перетворить і поверне новий незалежний об'єкт (хоча незмінність дозволяє оптимізувати, java.lang.String.toString()просто повертає об'єкт).
Як приклад, у C ++ ми std::bitset::to_ulong()можемо легко вийти з ладу і цілу безліч to_string()усіх, які роблять (більш-менш) складне перетворення та розподіляють пам'ять.

Очікується, що asXYZ()функція з іншого боку повертає (потенційно інший) погляд на джерело, виконуючи мінімальну роботу.
Як приклад, у C ++ ми маємо, std::as_const()що просто повертає постійну посилання, і тим більше, що бере участь, std::forward_as_tupleщо також посилається на свої аргументи шляхом посилання.


19
Виявляється, для цього є якийсь існуючий прецедент. Загалом, як [щось] буде схожим на акторський склад, тоді як до [чогось] будує новий об'єкт (іншого типу) з існуючого. У випадку з ToList це буде O (n) і майже напевно дорожче, ніж "As". Дивіться stackoverflow.com/questions/17968469/…
Роберт Харві

5
Це частина вибору описових імен, і навіть якщо ця специфічна відмінність не кодифікована в стандарті кодування, порушення її порушує Принцип найменшого здивування .
Дедуплікатор

11
Я б описав це як, інстинктивно, я вважав би "на" як "зміну на" і "як" як "трактувати як". Перший передбачає роботу над зміною речі, а другий означає, що це лише різниця в тому, як ви працюєте з нею.
Latty

6
Якщо це щось означає, це повинно означати це. Я б припустив, що це часто нічого не означає, тому я б не покладався на нього у випадковому коді сторонньої сторони (не бачивши чогось у документах). Хоча було б добре прийняти конвенцію в кодовій базі.
Бен

4
Ця відповідь є точною також у C ++: наприклад, std::to_string(x)створюється новий рядковий об'єкт, але std::as_const(x)створюється посилання (вид) на існуючий об'єкт.
Quuxplusone

13

Чесно кажучи, це може просто назвати невідповідність. Якщо подивитися на стандартних бібліотечних об'єктів в Smalltalk, наприклад, всі методи , які роблять «складні перетворення» або «повертати прості уявлення в іншому типі» починаються з as, як asString, asFloat, asSecondsі стандартний метод для перетворення нічого до чого -то ще, as: aClass.

В Ruby, одні і ті ж види методів з префіксом to_, як і в to_s, to_a, to_h, скорочення string, arrayі hashвідповідно.

Жодна зі стандартних бібліотек не відрізняється різними видами перетворень, ймовірно, тому, що це слід розглядати як деталі реалізації.

Однак у Java ми бачимо багато змішань. Як уже згадувалося, є toString, asListі так далі. Я вважаю, що це лише невідповідність іменування, тому що якщо ви спробуєте визначити інше значення для кожного префікса, ви завжди знайдете зустрічний приклад десь в стандартній бібліотеці.

Тож у будь-якому випадку я б сказав, що для вас та вашої команди важливо вибрати один префікс та послідовно використовувати його у всьому коді. Послідовність - це ключ, тому люди не залишаються дивуватися, як вам довелося.


1
Я не вірю в: вибирати один стиль для всієї команди, а обирати один модуль для подібних випадків у модулі послідовно.
Даніель Харі

12
У Java toStringстворюється нова рядок, повністю відключена від об'єкта (і іншого способу немає через незмінність). Те ж саме, наприклад, для Collection#toArray, тоді як Arrays#asListповертає вигляд масиву, який двосторонній пов'язаний (мутація масиву змінює список і навпаки). Тож це досить послідовно, хоча можуть бути винятки. Вибір одного префікса був би неправильним. Якби був Arrays#toList, то я б очікував, що він створить новий список з новим базовим масивом.
maaartinus

Я думаю, що Smalltalk просто помилився там, вони не зрозуміли конвенцію. Це складна конвенція зрозуміти (і навіть помітити), оскільки вона така абстрактна і не особливо вражаюча. Навіть сам акт задавання цього питання потребує певного розуміння.
usr

3
@usr Smalltalk, можливо, був розроблений до того, як він став конвенцією
Бергі

6

Хоча вже є прийнята відповідь, схоже, вона зосереджена на C ++, тоді як питання позначено як java . У Java перший приклад, який спадає на думку подібного роду, - Arrays.asList , який, по суті, повертає перегляд масиву, загорнутого у список. Базовий масив і список все ще пов'язані; зміни масиву відображаються у списку, і навпаки. Однак масив, повернутий методом toArray списку, не залежить від вихідного масиву та від списку:

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"
}

Все, що було сказано, немає гарантії, що кожен розробник бібліотеки дотримується цієї конвенції, тому вам потрібно перевірити документацію, щоб з’ясувати, чи це поведінка, яку ви отримаєте з невідомого коду.

Інше місце, яке я бачив як методи ... (), які часто використовуються, - це типи, що знижуються на підтипи. Наприклад, якщо у вас є перелічений набір підтипів, ви можете отримати код типу:

  /**
   * 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();
      }
    }
  }

1

Різниця, яку я помітив (лише зараз, думаючи про це), є

  • Як правило, перетворюється на інший тип посилання (дещо складний об'єкт)
  • Як правило, повертає простий тип значення

Отже, ми бачимо AsInteger і AsString і бачимо ToArray і ToStringList.

Мати на увазі перетворення, яке має сенс (це рух, процес). Як передбачає подання, спосіб вираження оригінального об'єкта.

Ще один спосіб погляду на це:

  • Це операція, тому ви використовуєте її для методів.
  • Як це просте подання, так ви б використовували його для властивостей.

І тоді є "попереднє мистецтво" (або спадщина) для вирішення. Перш ніж мови були повністю OO з нуля, ви мали б функції бібліотеки, такі як StrToInt () та IntToStr (). Вони виконували перетворення, вони були операціями, тому було сенсом називати їх SomethingToSomethingelse (). Зрештою, To більш активний, ніж As. Я особливо думаю про Delphi тут.

Коли C # був розроблений з амбіцією пройти OO до кінця, мав сенс мати метод на теперішньому цілому об'єкті, який би перетворив ціле число на рядок. Хоча у нас також є клас Convert, перетворення в рядок настільки поширене, що він був зроблений віртуальним методом на об'єкті. Дизайнери, можливо, подумали, що ToString буде більш знайомим людям зі старої парадигми, і, можливо, саме тому ми отримали віртуальний метод ToString (), а не віртуальну властивість AsString.


3
Про що toString()?
Дедуплікатор

Ти мене туди завів. Я думаю, що AsString був би доречнішим. Якщо я маю кілька додаткових думок, я оновлю свою відповідь.
Мартін Мейт

Я не думаю, що ця відповідь насправді відповідає умовам у C #. Напр. ToList () і AsEnumerable () обидва повертають складні об'єкти, різниця полягає в тому, що ToList () завжди повертає новий об'єкт, тоді як AsEnumerable () повертає вигляд або адаптер над вихідним об'єктом.
ЖакБ

@JaquesB Очевидно, тут і там були застосовані різні ідеї. Delphi має властивості AsInteger та AsString на об'єктах TField (які інкапсулюють поля бази даних). Я, можливо, був упереджений цим. Але знову ж таки, питання позначається Java, а не ані C, ані Delphi.
Мартін Мейт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.