Чи корисний обсяг рівня пакету Java?


11

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

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

Наприклад, у мене може бути модель Місії, і я хочу використовувати лише інші інструменти Місії, як-от моя місія Сервіси, використовувати деякі методи. Однак я закінчую Missions.models і Missions.services як мої пакети, тому MissionModel і MissionService не є однаковою сферою пакету. Ніколи не здається, що існує ситуація, коли пакети належним чином містять речі, для яких я хотів би мати підвищені дозволи, не включаючи також численні речі, я не хочу мати цих дозволів; і рідко я відчуваю перевагу методу визначення обсягу пакунків, що виправдовує зміну моєї архітектури проекту, щоб розмістити все в одному пакеті. Часто або аспекти, або якась інверсія управління виявляються кращим підходом до будь-якої проблеми, яку я коротко розглянув, як визначати обсяг пакету.

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

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


Продуманий експеримент: як виглядали б програми Java, якби у вас не було пакетів? Можливо, ви не переглядали і не працювали над якимись великими програмами Java.
Роберт Харві

Подивіться на код для java.util.Stringта java.util.Integer.


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

2
Я зовсім не переконаний у дублікатах. Це запитання задає "Для чого призначений обсяг пакета?" в той час як інший запитує (серед іншого) "Даний обсяг пакету є типовим, для чого приватна сфера застосування?" Плюс прийнята відповідь на дупі та прийнята відповідь тут вносять абсолютно різні моменти.
Іксрек

Відповіді:


2

Протягом усього java.util.*пакету є випадки, коли код пишеться із захистом рівня пакету. Наприклад, цей біт java.util.String- конструктор на Java 6 :

// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}

або це метод getChars :

/** Copy characters from this string into dst starting at dstBegin. 
    This method doesn't perform any range checking. */
void getChars(char dst[], int dstBegin) {
    System.arraycopy(value, offset, dst, dstBegin, count);
}

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

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

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

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


1
Я переглядав java.util, і я це бачу. Однак я також помічаю, що це велика бібліотека. Зараз здається, що великі бібліотеки рідко пишуться без використання підпакетів; і саме ті підрозділи підпакетів призводять до обмежень. Я не кажу, що java.util помиляється, але здається, що вони могли б піти з великим пакетом лише тому, що вони мали НАДІЙНИХ хороших програмістів, яким вони могли довіритися, щоб зробити все правильно з досить обмеженою інкапсуляцією всередині пакету; Я відчував би голі довіри, що великий потенціал може заподіяти шкоду середнім розробникам, які можуть працювати на подібних пакетах, як я.
dsollen

1
@dsollen Якщо ви копаєтесь до Spring, Hibernate або подібних великих бібліотек, ви знайдете подібні речі. Бувають випадки, коли потрібна тісніша муфта. Один повинен мати можливість перевірки коду представлені матеріали і переконайтеся , що все правильно. Якщо вам не потрібно більш тісне з'єднання або взагалі не довіряєте іншим кодерам, тоді публічні поля, пакет або захищені поля чи методи не завжди підходять. Однак це не означає, що це не корисно.

коротше кажучи, я б спокусився зробити більш обмежені пакети і не турбуватися про рівень оптимізації (що є лише марною тратою в 95% проектів) для моїх повсякденних потреб. Таким чином, моїм наступним питанням стає те, чи є на рівні пакетів специфічний потенціал оптимізації, який використовується лише у певних широко використовуваних масових API? Тобто лише великим знадобиться чи захочуть послабити захист до такої міри? Чи є причини, що хороші програмісти, які працюють над рівним «стандартним» API з меншими базами користувачів, знайдуть для цього користь?
dsollen

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

2
@dsollen мова не йде про ефективність (хоча це одна з причин викриття реалізації), а скоріше інкапсуляцію. Ви робите це, щоб уникнути повторення коду Integer.toString()та String.valueOf(int)можете ділитися кодом, не піддаючи його світові. Ці java.utilкласи повинні працювати спільно , щоб забезпечити більше всієї функціональності а не окремі класи, які повністю острова до себе - вони разом в пакет і частка функціональних можливостей реалізації через рівень пакета оглядового.

5

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

Оскільки junit-test має той самий пакет, що й тест-предмет, він може отримати доступ до цих деталей реалізації

приклад

  public class MyClass {
    public MyClass() {
        this(new MyDependency());
    }

    /* package level to allow junit-tests to insert mock/fake implementations */ 
    MyClass(IDependency someDepenency) {...}
  }

Дискусійним є те, чи це «добре» використання чи ні, але це прагматично


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

Я ніколи не роблю це методами, але приємну особливість використовувати для введених залежностей. Наприклад, під час тестування EJB, ін'єктованих EntityManagers можна знущатися, встановивши ЕМ рівня пакету з об'єктом Mock, куди він під час виконання повинен бути введений сервером додатків.
jwenting

Навіщо підніматись protectedдо пакету? protected вже постачає доступ до пакету. Це трохи дивна химерність, але я думаю, що вони не хотіли вимагати складних оголошень про сферу, таких як protected packagescope void doSomething()(що також вимагає нового ключового слова).
tgm1024 - Моніку обратили

2

Це не все так корисно, особливо як за замовчуванням, у світі, де люди, як правило, використовують пунктирні назви пакунків так, як ніби вони були підпакетами. Оскільки у Java немає такого поняття, як підпакет, тому xyinternals не має більше доступу до xy, ніж це стосується ab Імена пакетів є однаковими або різними, часткова відповідність не відрізняється від того, що вони не мають нічого спільного.

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

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

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


Я вважаю коментар Java 9 цікавим. Думаю, було б непоганою здатність розпізнавати ірахії пакунків і якось визначати область пакета відносно якогось батьківського пакету (використовуючи анотації?).
dsollen

1
@dsollen, можливо, але моє перше схильність полягає в тому, що ми б починали забивати шини праскою шини з цим. Набагато кращим першим кроком до ясності (який певною мірою сприяє безпеці), на мій погляд, було б винайдення ключового слова фактичного пакету. Це може бути навіть "пакет" :)
tgm1024 - Моніку жорстоко зверталися

2

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

Ось приблизний приклад сценарію. Припустимо, ваш код був реорганізований так, щоб він був довше функціональної згуртованості та компонентності. Можливо, 3 банки, як:

**MissionManager.jar** - an application which uses the Java Service Provider Interface to load some implementation of missions, possible provided by a 3rd party vendor.

**missions-api.jar** - All interfaces, for services and model
    com...missions
        MissionBuilder.java   - has a createMission method
        Mission.java - interface for a mission domain object
    com...missions.strategy
        ... interfaces that attach strategies to missions ...
    com...missions.reports
        .... interfaces todo with mission reports ....

   **MCo-missionizer-5000.jar** -  provides MCo's Missionizer 5000 brand mission implementation.
       com...missions.mco
                  Mission5000.java - implements the Mission interface.
       com...missions.strategy.mco
              ... strategy stuff etc ...

Використовуючи рівень пакету в Mission5000.java, ви можете впевнитись, що жоден інший пакет або компонент, такий як MissionManager, не може зв'язати пару з реалізацією місії. Тобто лише "третя сторона", надана складовою "M co", фактично створює там власну спеціальну фірмову реалізацію Місії. Менеджер місій повинен викликати MissionBuiler.createMission (...) та використовувати визначений інтерфейс.

Таким чином, якщо компонент реалізації Mission буде замінено, ми знаємо, що реалізатори MissionManager.jar не обійшли api і безпосередньо використали реалізацію MCo.

Отже, ми можемо замінити MCo-missionizer5000.jar конкуруючим продуктом. (Або, можливо, макет для тестування підрозділу Mission Manager)

І навпаки, MCo може виконати деяку кількість приховування своїх торгових таємниць місіонізатора.

(З цим пов’язано виконання ідей щодо нестабільності та абстрактності в компонентах.)


-1

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

Натомість ми використовуємо власні правила доступу, засновані на ієрархії пакунків та заздалегідь визначеними назвами пакетів.

Якщо вас цікавлять деталі google для "CODERU-Правил".

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