Коли ви повинні і не повинні використовувати ключове слово "нове"?


15

Я переглянув презентацію Google Tech Talk на тестуванні підрозділів , проведену Місько Гевери, і він сказав не уникати використання newключового слова в коді бізнес-логіки.

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

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


2
Чи можете ви додати тег, пов’язаний з мовою програмування? Нове існує у багатьох мовах (C ++, Java, Ruby, щоб назвати декілька) та має різну семантику.
sakisk

Відповіді:


16

Це більше настанов, ніж жорстке правило.

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

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

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

Основне питання, яке ви повинні задати собі, - це "головна відповідальність цього бітового коду за створення об'єктів такого типу, або це лише деталі реалізації, які я міг би розумно перемістити кудись інше?"


1
Добре, якщо ви хочете, щоб це був непорушний список, вам слід скористатися Collections.unmodifiableListчи іншим . Але я знаю, що ти маєш на увазі :)
MatrixFrog

Так, але вам потрібно якось створити оригінальний список, який потім перетворите на немодифікуючий ...
Білл Мішелл

5

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

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


5

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

Не завжди слід уникати щільного зчеплення, тобто предмета, що володіє знаннями іншого конкретного класу; на деякому рівні дещо, ДЕЙШЕ, повинно знати, як створити цей об’єкт, навіть якщо все інше має справу з об'єктом, надаючи його копію з іншого місця. Однак, коли клас, який створюється, змінюється, будь-який клас, який знає про конкретну реалізацію цього класу, повинен бути оновлений, щоб правильно боротися зі змінами цього класу.

Питання, яке вам слід завжди задавати, - це: "Чи буде цей клас знати, як створити цей інший клас, стане відповідальністю при підтримці програми?" Обидві основні методології проектування (SOLID та GRASP) зазвичай відповідали "так" з тонко різних причин. Однак це лише методології, і обидві мають крайнє обмеження, що вони не були сформульовані на основі знань вашої унікальної програми. Таким чином, вони можуть помилятися лише на стороні обережності, і припускати, що будь-яка точка щільного з’єднання НАРУЧНО спричинить вам проблему, пов’язану із внесенням змін в ту чи іншу сторону цієї точки. Ви повинні прийняти остаточне рішення, знаючи три речі; найкраща теоретична практика (яка полягає в тому, щоб вільно з'єднати все, тому що все може змінитися); витрати на впровадження теоретичної найкращої практики (яка може включати кілька нових шарів абстрагування, що полегшить зміну одного типу, перешкоджаючи іншому); і реальна ймовірність того, що тип змін, який ви передбачаєте, коли-небудь буде необхідний.

Деякі загальні вказівки:

  • Уникайте тісного з'єднання між зібраними бібліотеками кодів. Інтерфейс між DLL (або EXE та його DLL) є головним місцем, де щільна муфта представлятиме недолік. Якщо ви внесете зміни до класу A в DLL X, а клас B в основному EXE знає про клас A, вам доведеться перекомпілювати та випустити обидва бінарні файли. У межах одного двійкового файла більш жорстке з'єднання, як правило, є більш допустимим, оскільки весь бінарний файл повинен бути відновлений для будь-якої зміни. Іноді необхідність відновлення декількох бінарних файлів неминуча, але ви повинні структурувати свій код так, щоб уникнути цього, де це можливо, особливо в ситуаціях, коли пропускна здатність переважає (наприклад, розгортання мобільних додатків; натискання нової DLL в оновлення набагато дешевше ніж натискання на всю програму).

  • Уникайте тісних зв'язків між основними "логічними центрами" вашої програми. Ви можете думати про добре структуровану програму, що складається з горизонтальних і вертикальних фрагментів. Горизонтальні зрізи можуть бути традиційними рівнями додатків, такими як інтерфейс користувача, контролер, домен, DAO, дані; вертикальні фрагменти можуть бути визначені для окремих вікон або представлень, або для окремих "історій користувачів" (наприклад, створення нового запису якогось базового типу). Під час здійснення дзвінка, який рухається вгору, вниз, вліво або вправо у добре структурованій системі, слід загалом абстрагувати зазначений виклик. Наприклад, коли під час перевірки потрібно отримати дані, вона не повинна мати доступ до БД безпосередньо, але повинна робити виклик до інтерфейсу для пошуку даних, який підтримується фактичним об'єктом, який знає, як це зробити. Коли деякий елемент управління користувачем інтерфейсу повинен виконувати розширену логіку, що включає інше вікно, він повинен абстрагувати запуск цієї логіки через подію та / або зворотний виклик; не потрібно знати, що буде зроблено в результаті, що дозволяє змінити те, що буде зроблено, не змінюючи керування, яке його запускає.

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


3

Об'єкти, що містять лише дані, або DTO (об'єкти передачі даних) є прекрасними, створюйте їх цілий день. Там, де ви хочете уникати newкласів, які виконують дії, ви хочете, щоб споживаючі класи натомість програмували проти інтерфейсу , де вони можуть викликати цю логіку і споживати її, але не нести відповідальності за фактичне створення примірників класів, що містять логіку . Класи, що виконують дії або логіки, що містять залежність. Розмова Місько спрямована на те, щоб ти вводив ці залежності і дозволяв якомусь іншому суб'єкту бути відповідальним за те, що вони фактично їх створюють.


2

Інші вже згадували цю тему, але хотіли цитувати це з Чистого кодексу дядька Боба (Боб Мартін), оскільки це може полегшити розуміння поняття:

"Потужним механізмом відокремлення конструкції від використання є впорскування введення (DI), застосування інверсії управління (IoC) до управління залежностями. Інверсія управління переміщує вторинні обов'язки від об'єкта до інших об'єктів, призначених цілі, тим самим підтримуючи Single відповідальність Принцип . У контексті управління залежностями, об'єкт не повинен брати на себе відповідальність за інстанцірованія залежності самого. Замість цього він повинен передати цю відповідальність іншому «авторитетному» механізму, тим самим перевертаючи контроль. Оскільки установка є глобальною проблемою, це Авторитетним механізмом зазвичай буде або "основний" розпорядок, або контейнер спеціального призначення ".

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

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