Коли я повинен використовувати клас 2-властивості над попередньо побудованою структурою, як KeyValuePair?


31

Коли слід помістити тип ключа / значення даних у свій власний клас замість використання попередньо побудованої загальної структури, наприклад a KeyValuePairчи a Tuple?

Наприклад, більшість створених мною створених ComboBoxes містять DisplayName та Value. Це такий тип даних, який я намагаюся вирішити, коли ввести новий клас і коли просто використовувати KeyValuePair.

Зараз я працюю над тим, що використовує iCalendar, і дані вибраного користувача в кінцевому рахунку об’єднуються у key1=value1;key2=value2;тип рядка. Я почав із введення даних у KeyValuePair<string,string>, але зараз мені цікаво, чи це повинен бути власний клас.

В цілому, мені цікаво дізнатися, які вказівки використовуються при вирішенні використання існуючої структури / класу, як об'єкт KeyValuePairнад 2 властивостями, і в яких ситуаціях ви б використовували один над іншим.


3
Яка мова? У Python у нас немає цієї дилеми, оскільки ми маємо tupleтип.
С.Лотт

3
@ S.Lott - .NET BCL має кортежі з версії 4.0.
Одід

1
.NET 4 також має тип кортежу. msdn.microsoft.com/en-us/library/system.tuple.aspx
Dave Nay

1
@Oded У цьому випадку я щось будую, iCalendarі я хотів об'єкти для BYDAYі BYSETPOS. Вони з'являються у ComboBoxes, але фактичні дані об'єднуються у рядки, що повторюються, що є key=value;типом рядка
Рейчел

4
@Rachel: Будь ласка, оновіть питання, щоб бути більш конкретним. Купка коментарів - не найкращий спосіб з’ясувати речі.
S.Lott

Відповіді:


26

Зазвичай я використовую об'єкт, а не KeyValuePair або Tuple у більшості випадків. По-перше, коли ви приїжджаєте через 6 місяців, щоб внести зміни, набагато простіше зрозуміти, який був ваш задум, а не цікавитись, що Tuple tтаке і чому він має ці смішні значення. По-друге, по мірі того, як все росте і змінюється, ви можете легко наводити просту поведінку об'єктів для передачі даних за необхідності. Потрібно мати два формати імен? Легко, просто додайте відповідні перевантаження ToString (). Потрібно, щоб реалізувати якийсь інтерфейс? Без проблем. Нарешті, дійсно майже нульові накладні витрати на створення простого об’єкта, особливо з автоматичними властивостями та заповненням коду.

Бонусна підказка: якщо ви хочете, щоб ці об’єкти не забруднювали простір імен, приватні заняття всередині класів - це прекрасний спосіб тримати речі під загортанням та запобігати дивним залежностям.


1
DTO = Об'єкти передачі даних ? - Я ненавиджу TLAs ;-)
Бен

3
@Ben - TFTFY. . .
Wyatt Barnett

7

Правило визначення нового класу просте: Це узагальнено "Бритвою Оккама".

http://c2.com/cgi/wiki?OccamsRazor

Не вводьте нові заняття без поважних причин. Або максимально використовуйте попередньо побудовані класи. Або вигадуйте якомога менше. Однак вам зручніше писати менше коду.

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

А tupleабо KeyValuePairє кращим.

Поки.

Вам потрібна певна функціональність, яка не є частиною А tupleабо KeyValuePair. Тоді ви повинні визначити свій власний клас.


3
" Ніколи не конструюйте те, що ви можете вкрасти " - це мій улюблений спосіб фразування цього.
SingleNegationElimination

1
Чи вважаєте ви семантику "функціональністю, яка не є частиною tupleабо KeyValuePair"? У KeyValuePair принаймні є обмежена форма семантики, але кортежі рідко (можливо, можливо, залежно від контексту) імхо. Введення нового класу, безумовно, повинно дати вам чітку семантику.
Мал Росс

+1 Не заклеюйте ціле у човні за допомогою клейкої стрічки, якщо вона може вмістити вилку.
Еван Плейс

4
Я думаю, що це неправильне використання бритви Occam. По-друге, важливо знати, яка інформація міститься в змінній. -1.
Вигнувся

4

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

 public class MyPair : Tuple<string, string>

Мені це подобається, тому що MyPairвизначає, що таке значення Tuple і для чого вони використовуються.
IАнотація

2
Але тоді ваші властивості будуть називатися Item1і Item2! Чи не так просто визначити весь клас? public class SideStrings { public string Left { get; set; } public string Right { get; set; } }
конфігуратор

@configurator Я писав відповідь на це і зауважив, що Tuple читається лише тому я погоджуюсь, який, на мою думку, підкреслює всю справу. Хоча ви можете обернути кортеж, щоб назвати значення, що вам потрібно.
Увійти

2
@ Підпис: Але в чому сенс? Створення власного класу - це менше роботи, ніж загортання кортежу.
конфігуратор

2
@configurator ви отримуєте деякі матеріали щодо рівності та порівняння, які працюють краще, ніж призначений для користувача об’єкт, але якщо потрібна установка, кортеж, безумовно, є неправильним шляхом.
Увійти

4

С.Лотт писав

Не вводьте нові заняття без поважних причин. Або максимально використовуйте попередньо побудовані класи. Вигадуйте якомога менше.

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

Дозвольте сказати, чому у мене серйозне питання з цим. З тих пір

KeyValuePair [рядок, рядок]

здається, що все в порядку .... чи KeyValue [рядок, KeyValue [рядок, KeyValuePair [рядок, рядок]]] також добре? Я не знаю , що С. Лотт буде говорити це, але мій бос думає , що це нормально.

Я наважуся не погодитися. І ось чому: Це зменшує читабельність коду, який буде надалі. Функція, яка заповнить таку структуру даних, буде набагато складнішою та схильною до помилок (помилок. Виключення) (лише уявіть хоч якусь логіку бізнесу). Я не надто сильно сперечався зі своїм начальником, але я скажу це тут: читабельність козирує хвилинну економію місця (що було його аргументом). Так би не був об’єкт класу, в якому є деякі поля; але деякі залишаються порожніми, а іноді краще?

PS Я є Ultra_Noob, тому, будь ласка, скажіть мені, якщо я помиляюся.


2
Я думаю, що KeyValuePair<string,string>це добре, якщо припустити, що вкладені речі є дійсно ключовими та цінними. Тут повторне використання існуючого класу - виграш, оскільки ви зберігаєте код написання та отримуєте сумісність. OTOH, використовуючи щось таке складне, як KeyValuePair<string,KeyValuePair<string,string>>і більшість часу просто занадто складне, щоб бути практичним. Іноді це може бути правильно - коли вам не потрібна додаткова функціональність, коли сенс очевидний і коли це добре працює з іншими класами. YMMV, це лише зважування плюсів і протилежностей.
maaartinus

Якщо ви використовуєте C #, ось виступ Tuple vs KeyValuePair . Щось, що ви можете поділитися зі своїм начальником?
Бен

3

Коли ми говоримо пара ключ / значення , я зазвичай думаю про хеш-таблиці , або асоціативні масиви , або просто об’єкт KeyValuePair . Я використовую їх усі, і різниці в тому, коли я використовую, немає різниці.

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

Окрім цього, я хочу шукати за клавішами або робити список (масив) стильових дій, таких як push і pop.

Отже, моя відповідь - НІ , і я не створюю об’єктів явно для пар ключів / значень, оскільки багато вбудованих структур вже роблять це для мене.


3

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


2

Я б, можливо, погодився з Вайлдінгом тут , але тоді я теж трохи нуб у подібній справі.

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

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

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

На мій досвід, немає нічого гіршого, якщо бачити, що Tuple [рядок, рядок] передається методом і не має безпосереднього способу пізнати, що таке Item1 і Item2. Найкраще використовувати кортежі в межах методів або лише як приватних членів класу.

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