Чи "уникнути проблеми йо-йо" є вагомою причиною, щоб дозволити "примітивну одержимість"?


42

Згідно Коли коли примітивна одержимість не є кодовим запахом? , Я повинен створити об'єкт ZipCode, щоб представляти поштовий індекс, а не об'єкт String.

Однак, зі свого досвіду, я волію бачити

public class Address{
    public String zipCode;
}

замість

public class Address{
    public ZipCode zipCode;
}

тому що я думаю, що останній вимагає від мене перейти до класу ZipCode, щоб зрозуміти програму.

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

Тому я хотів би перенести методи ZipCode в новий клас, наприклад:

Старий:

public class ZipCode{
    public boolean validate(String zipCode){
    }
}

Нове:

public class ZipCodeHelper{
    public static boolean validate(String zipCode){
    }
}

так що тільки той, кому потрібно перевірити поштовий індекс, залежав би від класу ZipCodeHelper. І я знайшов ще одну «користь» від збереження примітивної одержимості: він зберігає клас схожим на його серіалізовану форму, якщо така є, наприклад: таблиця адрес із стовпчиком zipCode.

Моє запитання: чи "уникнення проблеми йо-йо" (переміщення між визначеннями класів) є вагомою причиною, щоб дозволити "примітивну одержимість"?


9
@ jpmc26 Тоді ви були б шоковані, побачивши, наскільки складний наш об’єкт поштового індексу - не кажучи, що це правильно, але він існує
Джаред Гогуен

9
@ jpmc26, я не бачу, як ви переходите від "складного" до "погано розробленого". Складний код часто є результатом простого коду, що контактує зі складністю реального світу, а не ідеального світу, який ми, можливо, хотіли б існувати. "Назад до цієї функції на двох сторінках. Так, я знаю, це просто проста функція відображення вікна, але на ній виросли маленькі волоски та інше, і ніхто не знає чому. Ну, я скажу вам, чому: це помилка виправлення ».
Kyralessa

19
@ jpmc26 - точка обгортання об'єктів типу ZipCode - це безпека типу. Поштовий індекс - це не рядок, це поштовий індекс. Якщо функція очікує поштовий індекс, ви повинні мати можливість передавати лише поштовий індекс, а не рядок.
Давор Ждрало

4
Це відчуває особливу специфіку мови, різні мови тут роблять різні речі. @ DavorŽdralo У цьому ж розрізі ми також повинні додати багато числових типів. "тільки натуральні числа", "тільки парні числа" також можуть бути типами.
paul23

6
@ paul23 Так, і головна причина, що у нас таких немає , - це те, що багато мов не підтримують елегантних способів їх визначення. Цілком розумно визначати "вік" як різний тип від "температура в градусах Цельсія", хоча б тільки так, щоб "userAge == currentTemperature" був визнаний нісенітницею.
IMSoP

Відповіді:


116

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

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

Наприклад, я впевнений, що ви не будете йо-йо читати вихідний код для String кожного разу, коли стикаєтеся з String в коді.

Перейменування класу з ZipCode на ZipCodeHelper дозволяє припустити, що зараз існує два окремих поняття: поштовий індекс та помічник поштового індексу. Так удвічі складніше. А тепер система типів не може допомогти вам розрізнити довільну рядок та дійсний поштовий індекс, оскільки вони мають один і той же тип. Тут доречна "одержимість": Ви пропонуєте більш складну і менш безпечну альтернативу лише тому, що хочете уникнути простого типу обгортки навколо примітиву.

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

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


2
Я погоджуюсь з "змістовними одиницями" (основною) частиною, але не настільки, що поштовий індекс та перевірка поштового індексу - це те саме поняття. ZipCodeHelper(яку я б швидше закликав ZipCodeValidator), цілком може встановити зв’язок із веб-сервісом, щоб зробити це своєю справою. Це не буде частиною єдиної відповідальності "зберігати дані поштового коду". Якщо система типу заборонить недійсні поштові індекси, все ще можна досягти, зробивши ZipCodeконструктор еквівалентом пакета Java приватним і викликаючи той, ZipCodeFactoryякий завжди викликає валідатор.
Р. Шмітц

16
@ Р.Шмітц: Це не те, що означає "відповідальність" у розумінні принципу єдиної відповідальності. Але в будь-якому випадку, звичайно, ви повинні використовувати стільки класів, скільки вам потрібно, доки ви інкапсулюєте поштовий індекс та його перевірку. ОП пропонують помічника замість інкапсуляції поштового коду, що є поганою ідеєю.
ЖакБ

1
Я хочу з повагою не погодитися. SRP означає, що клас повинен мати "одну, і лише одну, причину для зміни" (зміна в "з чого складається поштовий індекс" проти "як він перевірений"). Цей конкретний випадок тут далі докладно розглядаються в книзі Clean Code : « Об'єкти приховують свої дані позаду абстракцій і надати функції , які працюють на цих структуру даних Data експонувати свої дані і не має ніяких значимих функцій .. » - ZipCodeбуде «структурою даних» і ZipCodeHelper"об'єкт". У будь-якому випадку, я думаю, ми погоджуємося, що нам не потрібно було передавати веб-з'єднання конструктору ZipCode.
Р. Шмітц,

9
Використання примітиву IMHO виправдано у випадках, коли немає перевірки чи іншої логіки залежно від конкретного типу. => Я не згоден. Навіть якщо всі значення справедливі, я все-таки вважаю за краще передавати семантику мові, а не використовувати примітиви. Якщо функція може бути викликана примітивним типом, який є безглуздим для її поточного смислового використання, то він не повинен бути примітивним типом, він повинен бути належного типу з визначеними лише чутливими функціями. (Наприклад, використання intяк ID дозволяє множити ідентифікатор на ідентифікатор ...)
Матьє М.

@ R.Schmitz Я думаю, що поштові індекси є поганим прикладом для відмінності, яку ви робите. Щось, що зміни часто може бути кандидатом на окремі Fooта FooValidatorзаняття. У нас може бути ZipCodeклас, який перевіряє формат і той, ZipCodeValidatorякий потрапляє на якусь веб-службу, щоб перевірити, чи правильно відформатований ZipCodeнасправді поточний. Ми знаємо, що поштові індекси змінюються. Але практично у нас буде список дійсних поштових індексів, інкапсульований у ZipCodeабо в якійсь локальній базі даних.
Ні U

55

Якщо можете зробити:

new ZipCode("totally invalid zip code");

І конструктор для ZipCode робить:

ZipCodeHelper.validate("totally invalid zip code");

Потім ви порушили інкапсуляцію і додали досить нерозумну залежність до класу ZipCode. Якщо конструктор не дзвонить, ZipCodeHelper.validate(...)то у вас є окрема логіка на власному острові, фактично не застосовуючи її. Ви можете створити недійсні поштові індекси.

validateМетод повинен бути статичним методом на класі ZipCode. Тепер знання "дійсного" поштового коду поєднуються разом із класом ZipCode. З огляду на те, що ваші приклади коду виглядають як Java, конструктор ZipCode повинен кинути виняток, якщо надано неправильний формат:

public class ZipCode {
    private String zipCode;

    public ZipCode(string zipCode) {
        if (!validate(zipCode))
            throw new IllegalFormatException("Invalid zip code");

        this.zipCode = zipCode;
    }

    public static bool validate(String zipCode) {
        // logic to check format
    }

    @Override
    public String toString() {
        return zipCode;
    }
}

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

У цьому варіанті класу ZipCode немає "йо-йо". Це просто називається правильним об'єктно-орієнтованим програмуванням.


Ми також будемо ігнорувати тут інтернаціоналізацію, що може зажадати іншого класу під назвою ZipCodeFormat або PostalService (наприклад PostalService.isValidPostalCode (...), PostalService.parsePostalCode (...) тощо).


28
Примітка. Основна перевага підходу @Greg Burkhardt тут полягає в тому, що якщо хтось дає вам об'єкт ZipCode, ви можете довіряти, що він містить дійсну рядок, не потребуючи її ще раз перевіряти, оскільки її тип та факт успішного побудови дає вам що гарантія. Якщо ви замість цього передавали рядки навколо, ви можете відчути необхідність "стверджувати валідацію (zipCode)" у різних місцях вашого коду, щоб бути впевненим, що у вас дійсний поштовий індекс, але з успішно сконструйованим об'єктом ZipCode ви можете довіряти цьому його вміст дійсний без необхідності їх повторної перевірки.
Якийсь Гай

3
@ R.Schmitz: ZipCode.validateМетод - це попередня перевірка, яку можна виконати перед викликом конструктора, який видає виняток.
Грег Бургхардт

10
@ R.Schmitz: Якщо вас турбує неприємний виняток, альтернативний підхід до побудови полягає в тому, щоб зробити конструктор ZipCode приватним і надати загальнодоступну статичну функцію заводу (Zipcode.create?), Яка виконує перевірку переданих параметрів, повертає null, якщо не вдалося, інакше будує об'єкт ZipCode і повертає його. Зрозуміло, хто телефонує, завжди повинен перевіряти нульове значення повернення. З іншого боку, якщо ви маєте звичку, наприклад, завжди перевіряти (regex? Validate? Тощо) перед побудовою ZipCode, виняток може бути не таким неприємним на практиці.
Якийсь Гай

11
Фабрична функція, яка повертає необов'язковий <ZipCode>, також є можливістю. Тоді абоненту не залишається іншого вибору, окрім як явно впоратися з можливим збоєм заводської функції. Незважаючи на те, що в будь-якому випадку помилка буде виявлена ​​десь поблизу, де вона була створена, а не можливо набагато пізніше, за допомогою клієнтського коду, далекого від початкової проблеми.
Якийсь Гай

6
Ви не можете перевірити ZipCode самостійно, тому не робіть. Вам дійсно потрібен об’єкт Country, щоб шукати правила перевірки ZipCode / PostCode.
Джошуа

11

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

Там ви могли, наприклад, написати:

type ZipCode = ZipCode of string
type Town = Town of string

type Adress = {
  zipCode: ZipCode
  town: Town
  //etc
}

let adress1 = {
  zipCode = ZipCode "90210"
  town = Town "Beverly Hills"
}

let faultyAdress = {
  zipCode = "12345"  // <-Compiler error
  town = adress1.zipCode // <- Compiler error
}

Це дійсно корисно для уникнення поширених помилок, як порівняння ідентифікаторів різних сутностей. А оскільки ці типові примітиви набагато легші, ніж клас C # або Java, ви в кінцевому підсумку використовуєте їх.


Цікаво - як це буде виглядати , якщо ви хочете , щоб забезпечити дотримання перевірки ZipCode?
Халк

4
@Hulk Ви можете написати OO-стиль у F # і скласти типи в класи. Однак я віддаю перевагу функціональному стилю, оголосивши тип типу ZipCode = приватний рядок ZipCode і додавши модуль ZipCode з функцією створення. Тут є кілька прикладів: gist.github.com/swlaschin/54cfff886669ccab895a
Гуран

@ Bent-Tranberg Дякую за редагування Ви маєте рацію, проста абревіатура типу не забезпечує безпеку типу компіляції.
Гуран

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

Так. Моє оригінальне джерело було дійсно нормальним, на жаль, включаючи приклад, який ПОДАТКОВУВАННЯ недійсним. До! Якщо hav просто пов’язаний із Wlaschin, а не вводити код :) fsharpforfunandprofit.com/posts/…
Гуран

6

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

(1) Усі адреси гарантовано знаходяться в одній країні. Жодних винятків. (Наприклад, немає іноземних клієнтів, або немає працівників, приватна адреса яких знаходиться за кордоном, поки вони працюють для іноземного замовника.) У цій країні є поштові індекси, і від них можна очікувати, що вони ніколи не будуть серйозно проблемними (тобто вони не потребують введення у вільній формі наприклад "зараз D4B 6N2, але це змінюється кожні 2 тижні"). Поштові індекси використовуються не лише для адреси, але для перевірки платіжної інформації або подібних цілей. - За цих обставин клас поштового індексу має багато сенсу.

(2) Адреси можуть бути майже в кожній країні, тому десятки чи сотні адресних схем із поштовими індексами або без них (і з тисячами дивних винятків та особливих випадків) є актуальними. "Поштовий код" дійсно просять лише нагадувати людям з країн, де поштові індекси використовуються, щоб не забути вказати свої. Адреси використовуються лише для того, що якщо хтось втратить доступ до свого акаунта, і він зможе підтвердити своє ім’я та адресу, доступ буде відновлено. - За цих обставин класи поштових індексів для всіх відповідних країн будуть зусиллями величезними. На щастя, вони зовсім не потрібні.


3

Інші відповіді говорили про моделювання домену OO та використання більш багатого типу для представлення вашої цінності.

Я не погоджуюся, особливо з огляду на приклад коду, який ви опублікували.

Але мені також цікаво, чи це насправді відповідає назви вашого питання.

Розглянемо наступний сценарій (витягнутий із фактичного проекту, над яким я працюю):

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

У цьому сценарії багато чого, крім перевірки вставки, з обмеженням зворотного виразів SQL (або його еквівалентом ORM), ймовірно, є надмірним для різноманітності YAGNI.


6
Ваше обмеження для регулярних виразів SQL може розглядатися як кваліфікований тип - у вашій базі даних поштовий індекс не зберігається як "VarChar", а "VarChar, обмежений цим правилом". У деяких СУБД ви можете легко надати цьому типу + обмеження ім'я як багаторазовий "тип домену", і ми повернулися до рекомендованого місця, щоб надати дані значущого типу. Я принципово згоден з вашою відповіддю, але не думаю, що приклад відповідає; кращим прикладом може бути, якщо ваші дані "необроблені дані датчика", а найбільш значущим типом є "байтовий масив", оскільки ви не маєте поняття, що означають дані.
IMSoP

@IMSoP цікавий момент. Не впевнений, що я згоден: ви можете перевірити поштовий індекс-код на Java (або будь-якій іншій мові) за допомогою регулярного вираження, але все-таки матимете справу з ним як рядок замість більшого типу. Залежно від логіки домену, можуть знадобитися подальші маніпуляції (наприклад, забезпечення того, щоб поштовий індекс відповідав стану, що було б важко / неможливо перевірити з допомогою регулярного вираження).
Джаред Сміт

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

Ви можете моделювати таке поняття, як a RegexValidatedString, що містить саму рядок і регулярний вираз, який використовується для його перевірки. Але якщо кожен екземпляр не має унікального регулярного вираження (що можливо, але малоймовірно), це здається трохи нерозумним і марнотратним на пам’ять (і, можливо, час компіляції регулярного виразу). Таким чином, ви або помістіть регулярний вираз в окрему таблицю і залиште після себе ключ пошуку в кожному випадку, щоб знайти його (що, можливо, гірше через непрямість), або ви знайдете спосіб зберегти його один раз для кожного загального типу спільного використання значення цього правила - - напр. статичне поле типу домену або еквівалентний метод, як сказав IMSoP.
Міраль

2

ZipCodeАбстракція може мати сенс , тільки якщо ваш Addressкласі не також TownNameвласність. В іншому випадку у вас є половина абстракції: поштовий індекс позначає місто, але ці два пов'язані біти інформації знаходяться в різних класах. Це не зовсім має сенс.

Однак навіть тоді це все-таки не правильне застосування (а точніше рішення) примітивної одержимості; яка, як я розумію, в основному зосереджена на двох речах:

  1. Використання примітивів у якості вхідних (або навіть вихідних) значень методу, особливо коли потрібна колекція примітивів.
  2. Класи, які з часом отримують додаткові властивості, не замислюючись над тим, чи слід деякі з них групувати у свій підклас.

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

Ось як ви знаєте, що не потрібно більше підрозділятись: їх розбиття ще більше погіршить функціональний намір Addressкласу. Так само вам не потрібен Nameпідклас, щоб використовувати його у Personкласі, якщо тільки Name(без особи, що додається) є вагомим поняттям у вашому домені. Що це (як правило) не є. Імена використовуються для ідентифікації людей, вони зазвичай не мають значення самостійно.


1
@RikD: З відповіді: "Вам не потрібен Nameпідклас для використання в Personкласі, якщо Ім'я (без особи, що додається) є значущим поняттям у вашому домені ." Коли у вас є спеціальна перевірка імен, то ім'я потім стало важливим поняттям у вашому домені; який я чітко згадував як дійсний випадок використання для використання підтипу. По-друге, для перевірки поштового індексу ви вводите додаткові припущення, наприклад, поштові індекси, які потребують відповідності формату країни. Ви обговорюєте тему, яка набагато ширша, ніж наміри питання ОП.
Флатер

5
" Адреса - це чітко визначене поняття з чітко необхідними властивостями (вулиця, номер, поштовий індекс, місто, штат, країна). " - Ну, це просто неправильно. Щоб добре впоратися з цим, подивіться форму адреси компанії Amazon.
Р. Шмітц

4
@Flater Ну я не буду звинувачувати вас у тому, що ви не прочитали повний список неправди, тому що він досить довгий, але він буквально містить "Адреси матимуть вулицю", "Адреса вимагає і міста, і країни", "Адреса матиме поштовий індекс "тощо., що суперечить тому, що йдеться у цитованому реченні.
Р. Шмітц

8
@GregBurghardt "Поштовий індекс передбачає поштову службу Сполучених Штатів, і ви можете назвати місто з поштового індексу. Міста можуть мати кілька поштових індексів, але кожен поштовий індекс прив’язаний лише до 1 міста." Це взагалі неправильно. У мене є поштовий індекс, який використовується в основному для сусіднього міста, але моя резиденція там не знаходиться. Поштові індекси не завжди узгоджуються з урядовими межами. Наприклад, 42223 містить округи як TN, так і KY .
JimmyJames

2
В Австрії існує долина, доступна лише з Німеччини ( en.wikipedia.org/wiki/Kleinwalsertal ). Для цього регіону існує спеціальний договір, який, серед іншого, також передбачає, що адреси в цій області мають як австрійські, так і німецькі поштові індекси. Тож загалом ви навіть не можете припустити, що адреса містить лише один дійсний поштовий індекс;)
Халк,

1

Зі статті:

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

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

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

Однак - так , важливо уникати занадто багато шарів абстракції!

Всі нетривіальні абстракції, певною мірою, є герметичними. - Закон про проникнення абстракцій.

Наприклад, я не погоджуюся з припущенням, зробленим у відповіді mmmaaa, що "вам не потрібно йо-йо, щоб [(відвідати)] клас ZipCode, щоб зрозуміти клас адреси". Мій досвід полягав у тому, що ви це робите - принаймні перші кілька разів читаєте код. Однак, як зазначали інші, бувають випадки, коли ZipCodeклас підходить.

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

Я особисто прагну "зберегти рядки коду" (і, звичайно, пов'язані "збереження файлів / модулів / класів" тощо). Я впевнений, що є такі, хто застосував би до мене епітет "примітивних одержимих" - мені здається, важливіше мати код, про який легко міркувати, ніж турбуватися про мітки, шаблони та анти-шаблони. Правильний вибір, коли створити функцію, модуль / файл / клас або поставити функцію у загальне місце розташування, дуже ситуативний. Я орієнтуюсь приблизно на 3-100 функцій рядків, 80-500 рядкових файлів та "1, 2, n" для багаторазового використання бібліотечного коду ( SLOC - не включаючи коментарів чи котлован; я, як правило, хочу хоча б 1 додатковий мінімум SLOC на рядок обов'язкового котельня).

Більшість позитивних зразків виникають у розробників, які роблять саме це, коли їм це потрібно . Набагато важливіше навчитися писати читабельний код, ніж намагатися застосовувати шаблони без тієї самої проблеми для вирішення. Будь-який хороший розробник може реалізувати заводський зразок, не бачивши його раніше, в тому незвичайному випадку, коли це правильно підходить для їхньої проблеми. Я використовував заводський зразок, модель спостерігача і, мабуть, сотні, крім того, не знаючи їх назви (тобто чи існує "змінна схема присвоєння"?). Для цікавого експерименту - подивіться, скільки моделей GoF вбудовано в мову JS - я припинив рахувати приблизно через 12-15 років у 2009 році. Фабрична схема така ж проста, як повернення об'єкта з конструктора JS, наприклад - не потрібно a WidgetFactory.

Отже - так , іноді ZipCode це хороший клас. Однак ні , проблема йо-йо не є суто актуальною.


0

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

  1. Погане називання. ZipCode здається нормальним, ZoneImprovementPlanCode потребує огляду більшості людей (і тих, хто не вразить).
  2. Невідповідна муфта. Скажімо, у класу ZipCode є пошук регіонального коду. Ви можете подумати, що це має сенс, тому що це зручно, але це насправді не пов’язано з ZipCode, і вбрання його в нього означає, що зараз люди не знають, куди іти.

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


-1

Пам'ятайте, срібної кулі немає. Якщо ви пишете надзвичайно простий додаток, який потрібно швидко просканувати, то простий рядок може зробити цю роботу. Однак у 98% випадків ціннісний об’єкт, як описано Еріком Евансом у DDD, був би ідеальним. Ви можете легко побачити всі переваги, які надають об'єкти цінності, читаючи.

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