Чи достатньо, щоб методи розрізняли лише за назвою аргументу (а не за типом)?


36

Чи достатньо, щоб методи розрізняли лише за назвою аргументу (а не типом) чи краще називати його більш чітко?

Так , наприклад T Find<T>(int id)проти T FindById<T>(int id).

Чи є якась вагома причина назвати це більш чітко (тобто додавати ById) проти збереження лише імені аргументу?

Я можу подумати, коли підписи методів однакові, але вони мають інше значення.

FindByFirstName(string name) і FindByLastName(string name)


4
Отже, коли ви перевантажуєте Знайдіть, щоб включити, T Find<T>(string name)або (int size)як плануєте вирішити неминучі проблеми?
UKMonkey

3
@UKMonkey які неминучі проблеми?
Конрад

3
у першому випадку: якщо кілька записів мають однакове ім'я, то вам доведеться змінити підпис функції; а це означає, що люди, ймовірно, плутаються з тим, що означає повернутися; В останньому випадку аргумент той самий - і, отже, незаконне перевантаження. Ви або починаєте називати функцію "byX", або робите об'єкт для аргументу, щоб у вас був еквівалент перевантаження тим же аргументом. Або добре працює в різних ситуаціях.
UKMonkey

2
@UKMonkey ви можете опублікувати відповідь з кількома прикладами коду, якщо хочете
Конрад

3
Ідентифікатори, ймовірно, повинні бути непрозорими IDоб’єктами, а не просто аніме int. У такий спосіб перевірте, чи не використовуєте ви ідентифікатор для int або viceversa в якійсь частині вашого коду. І з цим можна мати find(int value)і find(ID id).
Бакуріу

Відповіді:


68

Впевнені, що є вагомі підстави назвати це більш чітко.

Це не в першу чергу бути метод визначення , які повинні бути очевидні, але метод використання . І в той час , findById(string id)і find(string id)обидва очевидні, є величезна різниця між findById("BOB")і find("BOB"). У першому випадку ви знаєте, що випадковий буквал насправді є Id. В останньому випадку ви не впевнені - це насправді може бути дане ім’я або щось інше цілком.


9
За винятком випадків, в 99% інших випадків , коли у вас є ім'я змінної або властивість є точкою відліку: findById(id)проти find(id). На цьому ви можете піти будь-яким шляхом.
Грег Бургхардт

16
@GregBurghardt: Певне значення не обов'язково називається однаково для методу та його виклику. Наприклад, розглянемо double Divide(int numerator, int denominator)використовується в методі: double murdersPerCapita = Divide(murderCount, citizenCount). Ви не можете розраховувати на два способи, використовуючи одне й те саме ім'я змінної, оскільки є маса випадків, коли це не так (або коли це так, це неправильно називати)
Flater

1
@Flater: Враховуючи код у запитанні (знаходження матеріалів із якогось постійного сховища), я думаю, що ви можете назвати цей метод "muritedCitizenId" або "CitizenId" ... Я дійсно не думаю, що імена аргументів чи змінних є тут неоднозначне. І чесно кажучи, я міг піти на цьому будь-яким шляхом. Це насправді дуже впевнене питання.
Грег Бургхардт

4
@GregBurghardt: Не можна перекрити глобальне правило з одного прикладу. Питання ОП взагалі не стосується наведеного прикладу. Так, бувають випадки, коли використання одного імені має сенс, але бувають випадки, коли цього немає. Звідси ця відповідь, найкраще прагнути до послідовності, навіть якщо це не потрібно в наборі випадків використання.
Flater

1
Параметри імен усувають плутанину після того, як плутанина вже існувала , оскільки потрібно переглянути визначення методу, тоді як явно названі методи цілком уникають плутанини , якщо ім'я присутнє у виклику методу. Крім того, у вас не може бути двох методів з тим самим іменем та типом аргументу, але різним ім'ям аргументу, а значить, у певних випадках вам знадобляться явні імена.
Darkhogg

36

Переваги FindById () .

  1. Майбутнє теплоізолюючі : Якщо почати з Find(int), а потім повинні додати інші методи ( FindByName(string), FindByLegacyId(int), FindByCustomerId(int), FindByOrderId(int), і т.д.), люди , як я , як правило , витрачати віків шукають FindById(int). Не дійсно проблема , якщо ви можете і буде змінюватися , Find(int)щоб , FindById(int)як тільки це стане необхідним - майбутнє коректури про них , якщо с.

  2. Легше читати . Findідеально добре, якщо дзвінок виглядає, що record = Find(customerId);все-таки FindByIdтрохи легше для читання, якщо він є record = FindById(AFunction());.

  3. Послідовність . Ви можете послідовно застосовувати FindByX(int)/ FindByY(int)шаблони скрізь, але Find(int X)/ Find(int Y)це неможливо, оскільки вони суперечать.

Переваги Find ()

  • KISS. Findє простим і простим, і поряд з operator[]цим є одним із 2 найочікуваніших імен функцій у цьому контексті. (Деякі популярні варіанти того get, lookupчи fetch, в залежності від контексту).
  • Як правило, якщо у вас є назва функції, це єдине відоме слово, яке точно описує, що функція виконує, використовуйте її. Навіть якщо є довше багатословне ім'я, яке трохи краще описує те, що робить функція. Приклад: Довжина проти NumberOfElements . Існує компроміс, і де провести межу, є предметом постійної дискусії.
  • Як правило, добре уникати надмірностей. Якщо ми подивимось FindById(int id), ми можемо легко усунути надмірність, змінивши його на Find(int id), але є торгівля - ми втрачаємо деяку чіткість.

Ви також можете отримати переваги обох за допомогою сильно набраних ідентифікаторів:

CustomerRecord Find(Id<Customer> id) 
// Or, depending on local coding standards
CustomerRecord Find(CustomerId id) 

Реалізація Id<>: Сильно вводити значення ідентифікаторів у C #

Коментарі тут, як і посилання вище, викликали численні занепокоєння щодо Id<Customer>того, про що я хотів би звернутися:

  • Концерн 1: Це зловживання дженериками. CustomerIdі OrderIDрізні типи ( customerId1 = customerId2;=> хороший, customerId1 = orderId1;=> поганий), але їх реалізація майже однакова, тому ми можемо реалізувати їх або за допомогою копіювальної пасти, або за допомогою метапрограмування. Незважаючи на те, що в дискусії про викриття або приховування загального значення існує цінність, метапрограмування - це те, для чого потрібні дженерики.
  • Концерн 2: Це не зупиняє прості mistakes./It's рішення в пошуках проблеми Основне питання , який видаляється за допомогою сильно типізованих Ідентифікатори неправильний порядок аргументів у виклику DoSomething(int customerId, int orderId, int productId). Сильно набрані ідентифікатори також запобігають іншим проблемам, включаючи ту, про яку було задано ОП.
  • Занепокоєння 3: Це дійсно просто затьмарює код. Важко сказати, чи зберігається ідентифікатор int aVariable. Неважко сказати, що Id зберігається Id<Customer> aVariable, і ми навіть можемо сказати, що це ідентифікатор клієнта.
  • Концерн 4: Ці ідентифікатори не є сильними типами, а лише обгортками. Stringце просто обгортка навколо byte[]. Обгортання або інкапсуляція не суперечить сильному набору тексту.
  • Побоювання 5: Це сконструйовано. Ось мінімальна версія, хоча я рекомендую додавати operator==і operator!=, якщо ви не хочете покладатися виключно на Equals:

.

public struct Id<T>: {
    private readonly int _value ;
    public Id(int value) { _value = value; }
    public static explicit operator int(Id<T> id) { return id._value; }
}

10

Інший спосіб думати про це - використовувати безпеку типу мови.

Ви можете реалізувати такий метод, як:

Find(FirstName name);

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


4
Не знаєте, яка ваша відповідь на питання про ОП. Чи рекомендуєте ви використовувати ім’я типу "Знайти", спираючись на тип аргументу? Або ви рекомендуєте використовувати такі імена лише тоді, коли для аргументів (яв) є явний тип, а також використовувати більш чітке ім'я, наприклад, "FindById" в інших місцях? Або ви рекомендуєте ввести явні типи, щоб зробити ім'я типу "Знайти" більш можливим?
Док Браун

2
@DocBrown Я думаю, що останнє, і мені це подобається. Це насправді схоже на відповідь Петра, iiuc. Як я розумію, це обгрунтування є двома: (1) з типу аргументу зрозуміло, що робить функція; (2) Ви не можете помилитися, як. Що string name = "Smith"; findById(name);можливо, якщо ви використовуєте загальні типи, що не описуються.
Пітер - Відновіть Моніку

5
Хоча я загалом прихильник безпеки типу компіляції, будьте обережні з типами обгортки. Введення класів обгортки задля безпеки типу може часом суттєво ускладнити ваш API, якщо це зроблено в надлишку. наприклад, уся проблема "художника, раніше відома як" int ", яка є у winapi; в кінцевому рахунку я б сказав, що більшість людей просто дивляться на нескінченні DWORD LPCSTRклони тощо. І думають, що "це int / string / etc.", це доходить до того, що ви витрачаєте більше часу на підсилення своїх інструментів, ніж ви насправді розробляєте код .
jrh

1
@jrh Правда. Мій лакмусовий тест на введення "номінальних" типів (що відрізняється лише назвою) - це коли загальні функції / методи не мають сенсу в нашому випадку використання, наприклад, ints часто підсумовуються, множуються тощо, що для ідентифікаторів не має сенсу; тож я б IDвідрізнявся від int. Це може спростити API, звужуючи , що ми можемо зробити з урахуванням значення (наприклад , якщо у нас є ID, він буде працювати тільки з find, а НЕ , наприклад , ageабо highscore). І навпаки, якщо ми виявимо, що багато перетворюємо або пишемо одну і ту ж функцію / метод (наприклад find) для декількох типів, це знак того, що наші відмінності занадто тонкі
Warbo

1

Я буду голосувати за явну декларацію, як FindByID .... Програмне забезпечення має бути створене для змін. Він повинен бути відкритим і закритим (SOLID). Тож клас відкритий для додавання подібного методу пошуку, наприклад, FindByName .. тощо.

Але FindByID закритий, і його реалізація перевірена.

Я не пропоную методів із предикатами, вони хороші на загальному рівні. Що робити, якщо на основі поля (ByID) у вас є повна інша методологія.


0

Я здивований, що ніхто не запропонував використовувати присудок, наприклад:

User Find(Predicate<User> predicate)

При такому підході ви не тільки зменшуєте поверхню свого API, але і надаєте більше контролю користувачеві, який його використовує.

Якщо цього недостатньо, ви завжди можете розширити його під свої потреби.


1
Проблема полягає в тому, що вона менш ефективна через те, що вона не може скористатися такими речами, як індекси.
Соломон Учко
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.