Чи існують якісь фактичні недоліки в ланцюжку самореференційних методів?


14

Нещодавно я запропонував метод певного класу реалізувати для певного класу в певному проекті, щоб можна було покращити читабельність коду. Я отримав "вільний інтерфейс не повинен бути реалізований просто для зручності, а для семантики", і моя пропозиція була знята. Я відповів, що не пропоную вільний інтерфейс, а метод прив'язування себе (обидва можна плутати один з одним, читати внизу), щоб поліпшити читабельність та комфорт кодування. Пропозиція знову була знята.

Так чи інакше, це змусило мене думати, що, можливо, я можу зазнати поганої практики, завжди повертаючи "це" методами, які не повинні повертати нічого (наприклад, сетери).

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


2
Подивіться на це питання, щоб приємно обговорити programmers.stackexchange.com/questions/48419/…
KeesDijk

@KeesDijk Дякую, я трохи відредагував своє запитання, щоб воно не було схожим на те, що мене більше цікавить випадок прив'язування методів того ж класу
герцогство, що відбулося

1
в SO, вони сказали мені, що ланцюжок не для C ++ - stackoverflow.com/questions/5760551/… - про що ви думаєте?
kagali-san

1
@mhambra Схоже, вам потрібно бути обережними лише при впровадженні ланцюжків методів та визначенні чітких стандартів для цього.
герцогство з

Відповіді:


10

Ні

Як вказує Кент Бек , код читається набагато частіше, ніж написано.

Якщо ланцюжок методів робить ваш код більш читабельним, тоді використовуйте метод ланцюжка.


1
Чудова книга .. +1
Рейн Генріхс

5
Але що робити, якщо ваш єдиний метод пошуку, який є більш читабельним? Якщо це питання силістичного питання, то вам доведеться дотримуватися набору умов кодування: це означає, щоб писати так само, як і існуючий код, для послідовності.
coredump

@coredump Це здається, що операторам вже було сказано це робити, але я думаю, що Стівен просто говорив про це, якщо ланцюжок методів робить його більш читабельним.
Panzercrisis

1
@Panzercrisis OP сказали утримуватися від використання методу ланцюга через зручність проти семантики. Відповідь Стівена в основному говорить "зробіть це все одно" і розглядайте лише читабельність коду ОП самостійно, не враховуючи думку чи послідовність команди. Що робити, якщо ОП хоче переписати кожен існуючий клас у проекті, щоб він відповідав його смаку щодо читабельності коду? Ось як я розумію аргумент зручності / семантики: має бути "технічна" причина, щоб мати метод ланцюга (btw, цей аргумент також звучить так, ніби інша людина виправдовує свої власні переваги)
coredump

9

Так, є і недоліки

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

  1. Мені потрібна розширена конфігурація, яка не обов'язково очевидна, в якому порядку слід встановлювати або налаштовувати речі
  2. Кожен наступний виклик методу будується на останньому

Дійсний випадок використання: Спеціальні запити до бази даних

Бібліотеки класів існують майже всіма мовами, що дозволяє запитувати базу даних, не вдаючись до жорстко кодованого SQL. Візьмемо приклад Entity Framework для .NET:

DBContext db = new DBContext();
List<Post> posts = db.Posts
    .Where(post => post.Title.Contains("Test"))
    .OrderBy(post => post.DateCreated)
    .ToList();

Це вільний інтерфейс, де кожен наступний виклик методу будується на попередньому. Читання цих дзвінків логічно має сенс у контексті запитів до бази даних.

Недійсний випадок використання: синтаксичний цукор для налаштування властивостей

Тепер давайте скористаємось тим же шаблоном, що і для Postкласу:

public class Post
{
    public string Title { get; set; }
    public DateTime DateCreated { get; set; }
    public string Body { get; set; }

    public Post SetTitle(string title)
    {
        Title = title;

        return this;
    }

    public Post SetDateCreated(DateTime created)
    {
        DateCreated = created;

        return this;
    }

    public Post SetBody(string body)
    {
        Body = body;

        return this;
    }
}

Тепер давайте розглянемо, як би ви використовували цей клас:

Post post = new Post()
    .SetTitle("Test")
    .SetDateCreated(DateTime.Now)
    .SetBody("Just a test");

Коли я бачу цей код, я одразу задаю це запитання: "Після дзвінка SetBodyчи запитує базу даних? Чи потрібно мені викликати інший метод, щоб сказати:" Я закінчую? "

Що ланцюжкові дзвінки методу повідомляють коду за допомогою Postкласу?

  1. У мене складна установка
  2. Кожен виклик методу будується на попередньому

Це насправді правда? Ні. PostКлас не має складних налаштувань. Визначаючи назву, створену дату та тіло, не будуйте один одного на більш складній кінцевій цілі. Ви розім'яли квадратний кілочок в круглий отвір.

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

Коли ваші колеги сказали:

Вільні інтерфейси повинні бути реалізовані не для зручності, а для семантики

Вони були абсолютно правильні. Вільний інтерфейс або ланцюжок методів передає щось саме по собі, що може бути неправдою.


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

Це не лише "складна конфігурація", це також "подальший виклик методу, який вибудовує попередній". Ланцюжок методів має мета-спілкування про це, що не завжди відповідає цілі класу.
Грег Бургхардт

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

1
Я розумію, ви вважаєте, що ланцюжок методів є окремим, але я кажу, що інші програмісти, які не були у вас в голові та використовують інші бібліотеки класів, які реалізують ланцюжок методів з цих причин, можуть в кінцевому підсумку зробити припущення щодо вашого коду, які не відповідають дійсності. Майте на увазі, що ланцюжок методів може означати те, чого ви, автор коду, не мали наміру. Код, який чітко передається, так само важливий, як і код, який легко читати. Не жертвуйте один за одного.
Грег Бургхардт

1
When an object's methods always return the object, it communicates a couple of things- Я думаю, це особиста думка; важко стверджувати, що кожен, хто дивиться на ланцюгові методи, буде припускати однакові речі.
Сем Дюфель

1

Основний недолік - втрата чіткості. Наприклад:

x.foo();
x.bar();
x.baz();

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

x.foo()
 .bar()
 .baz();

По-перше, не ясно, що barі bazдіяти над об'єктами того ж типу, як x, якщо ви не знаєте на факт, що xклас є єдиним класом з цими методами. Навіть якщо це так, не зрозуміло x, чи діють методи чи нові об’єкти.

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


0

Розглянемо всі стилістичні елементи мов програмування (на відміну від машинної мови машинного кодування), і це послаблює аргумент "семантика не зручність".

Дуже багато того, що ми робимо як інженери, - це надання зручності щодо семантики.

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