Чому Java зробила доступ до пакету за замовчуванням?


26

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

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

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

Я вважаю, що саме тому Java використовує доступ до пакету як "за замовчуванням". Але я не впевнений, чому вони також включили приватний доступ, я впевнений, що існує дійсний випадок використання ...



Доречно щодо раніше обговорених приватних методів тестування одиниць; як-робити-ти-блок-тест-приватний-методи . Відповідь; не варто
Річард Тінгл

Відповіді:


25

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

Якби вони зробили "загальнодоступним" доступ до типового, більшість програмістів ніколи б не намагалися використовувати щось інше. Результатом було б багато коду спагетті скрізь. (Тому що якщо вам технічно дозволено дзвонити з будь-якого місця, навіщо взагалі намагатися інкапсулювати якусь логіку в методі?)

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

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

Напевно, є й інші причини, але я б не недооцінював цю.


14

Доступ за замовчуванням не робить модифікатор приватного доступу зайвим.

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

Поради щодо вибору рівня доступу:

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

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

Ваше звернення до заповідності як виправдання для повного відмови від приватного модифікатора є помилковим, про що свідчать, наприклад, відповіді в Новому до TDD. Чи варто уникати приватних методів зараз?

Звичайно, ви можете мати приватні методи, і звичайно, ви можете їх перевірити.

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


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

Ви повинні поєднати ці класи та інтерфейс у пакет з кількох причин, включаючи наступне:

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

<rant "Я думаю, що я почув достатньо скуголення. Зрозуміло, прийшов час сказати голосно і чітко ...">

Приватні методи корисні для одиничного тестування.

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

Гаразд, тому у мене є тест приватного методу та одиниці тестування, і аналіз покриття говорить про те, що існує розрив, мій приватний метод не покривається тестами. Тепер ...

Що я отримую від збереження приватного життя

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

    void nonPrivateMethod(boolean condition) {
        if (condition) {
            privateMethod();
        }
        // other code...
    }

    // unit tests don't invoke nonPrivateMethod(true)
    //   => privateMethod isn't covered.

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

Тонко, щоб виправити розрив, я додаю тестовий блок для відсутнього сценарію, повторюю аналіз покриття та переконуюсь, що розрив зник. Що я маю зараз? У мене є новий тест для специфічного використання не приватного API.

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

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

  3. Новий тест толерантний до рефакторингу (чи я рефакторні приватні методи? Ти робиш ставку!) Що б я не робив privateMethod, я завжди хочу тестувати nonPrivateMethod(true). Незалежно від того, що я роблю privateMethod, не потрібно буде змінювати тест, оскільки метод не викликається безпосередньо.

Непогано? Будьте впевнені.

Що я втрачаю від ослаблення обмеження доступу

Тепер уявіть, що замість вище, я просто послаблюю обмеження доступу. Я пропускаю вивчення коду, який використовує метод, і переходжу безпосередньо до тесту, який викликає мій exPrivateMethod. Чудово? Ні!

  1. Чи можу я отримати тест на конкретне використання приватного API, згаданого вище? Ні: тестування nonPrivateMethod(true)раніше не було, і такого випробування зараз немає.

  2. Чи отримують зовнішні читачі можливості краще зрозуміти використання класу? Ні. "- Ей, яка мета випробуваного тут методу? - Забудьте це, він суворо для внутрішнього використання. - На жаль."

  3. Чи толерантний до рефакторингу? Ні в якому разі: що б я не змінився exPrivateMethod, це, ймовірно, зламає тест. Перейменуйте, об'єднайтеся в якийсь інший метод, змініть аргументи і тест просто перестане збирати. Головний біль? Будьте впевнені!

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

</rant>


7
Я ніколи не знаходив такого аргументу для тестування приватних методів, які є переконливими. Ви рефакторний код постійно перетворюєте на методи з причин, які не мають нічого спільного з загальнодоступним API API, і дуже приємно, що можна тестувати ці методи самостійно, не включаючи жодного іншого коду. Ось чому ви відремонтувались, правда? Щоб отримати частину незалежної функціональності. Ця функціональність повинна бути перевірена і незалежно.
Роберт Харві

Відповідь @RobertHarvey розширилася, роздувавши це. "Приватні методи корисні для одиничного тестування ..."
гнат

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

@RobertHarvey Я бачу. Здогадайтесь, вона зводиться до стилю кодування. За кількістю приватних методів, які я зазвичай виробляю, і за швидкістю їх рефакторингу, тестування на них - просто розкіш, яку я не можу собі дозволити. Неприватний API - інша справа, я, як правило, досить неохоче і повільно модифікую його
gnat

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

9

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

За винятком того, що приватне в Oak було еквівалентом приватного пакету на Java. Ви можете прочитати розділ 4.10 специфікації мови Дуба (моє наголос):

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

Тож, на ваш погляд, приватного доступу, як відомо на Java, спочатку не було. Але коли у вас є декілька класів в пакеті, не мати приватних, як ми це знаємо, це призведе до кошмару зіткнення імен (наприклад, java.until.concurrent має близько 60 класів), тому, ймовірно, вони представив його.

Однак семантика доступу до пакету за замовчуванням (спочатку називалася приватною) між Oak і Java не змінювалася.


5

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

Бувають ситуації, коли хотілося б мати два окремі класи, які є більш жорсткими, ніж викривати все публічно. Це схоже уявлення про «друзів» в C ++, коли інший клас, який оголошений як «друг» іншого, може отримати доступ до своїх приватних членів.

Якщо ви заглянете в внутрішні класи таких класів, як BigInteger, ви знайдете ряд полів захисту за замовчуванням на полях і методах (все, що є синім трикутником у списку). Це дозволяє іншим класам пакету java.math мати більш оптимальний доступ до своїх внутрішніх приміщень для конкретних операцій (ви можете знайти ці методи, що називаються у BigDecimal - BigDecimal підтримується BigInteger і зберігає знову повторне впровадження BigInteger . Що це рівні пакету не ' t проблема для захисту, тому що java.math є герметичним пакетом і до нього не можна додавати інші класи.

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

Зауважимо, тестування блоків не те, про що думали ще при створенні областей захисту. JUnit (рамка тестування XUnit для Java) була задумана до 1997 року (одне розповідь про історію цього можна прочитати на веб- сайті http://www.martinfowler.com/bliki/Xunit.html ). Альфа-бета-версії JDK були в 1995 році, а JDK 1.0 - в 1996 році, хоча рівень захисту насправді не був прибитий до JDK 1.0.2 (до цього ви могли мати private protectedрівень захисту).

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

public class Foo {
    /* package */ int bar = 42;
    ...
}

Зауважте коментар там.

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

Тож я здогадаюся. І ось це все - здогад.

По-перше, люди все ще намагалися з'ясувати мовний дизайн. Мови з тих пір вчилися на помилках і успіхах Java. Це може бути зазначено як помилка не мати щось, що потрібно визначити для всіх полів.

  • Дизайнери побачили періодичну потребу у відносинах "друг" C ++.
  • Дизайнери хотіли чітких заяв public, і privateоскільки вони мають найбільший вплив на доступ.

Таким чином, приватне не за замовчуванням і добре, все інше стало на свої місця. Область за замовчуванням залишилася за замовчуванням Це , можливо , було першою сферою , яка була створена і в інтересах сумісності суворої зворотних з старим кодом, залишилася таким чином.

Як я вже сказав, це все здогадки .


Ах, якби лише членська функція могла бути застосована до членів на індивідуальній основі, тож ви можете сказати, що недійсні деякіFunction () можна побачити лише класу X ..., що дійсно посилить інкапсуляцію!
newlogic

Зачекайте, ви можете це зробити на C ++, нам це потрібно на Java!
newlogic

2
@ user1037729 це дозволяє зробити більш тісне з'єднання між двома класами - клас з методом тепер повинен знати про інші класи, які є його друзями. Це, як правило, суперечить філософії дизайну, яку пропонує Java. Набір проблем, які можна вирішити з друзями, але не захист рівня пакунків, не такий вже й великий.

2

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

                 Access Levels
Modifier    Class   Package  Subclass   World
public        Y        Y        Y        Y
protected     Y        Y        Y        N
no modifier   Y        Y        N        N
private       Y        N        N        N

Розміщуючи їх нетехнічними термінами.

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

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

@KorayTugay: подивіться docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html . Внутрішній клас приватний. Прочитайте останній абзац.
jmoreno

0

Я не думаю, що вони зосередилися на тестуванні, просто тому, що тестування тоді було не дуже поширеним.

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

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


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