Как обойти то, что в Java нет видимости подпакетов - PullRequest
0 голосов
/ 04 марта 2019

Когда я пишу новый компонент с использованием DDD, я пытаюсь иметь один открытый класс в пакете со всеми соавторами моего компонента пакет защищен .

Это обычно очень хорошо получается, потому что есть только одна точка входа, которую могут использовать клиенты моего компонента.Все (внутренние) соавторы будут скрыты.

Рассмотрим пример, когда клиент может ездить с моей специально созданной машиной Java.Я не хочу, чтобы клиент видел все внутренние части транспортного средства, поэтому только класс Car доступен для общего доступа:

org.automobile
|- Car           <-- only Car is public
|- Engine        <-- all collaborators have default (package-protected) visibility
\- Battery

Теперь, как правило, все усложняется по мере развития домена, поэтомуЯ хочу переместить классы с их соавторами в подпакеты, чтобы сохранить мою структуру красивой и чистой:

org.automobile
|- Car
|- drive.Engine           <-- how to make this only available to Car
|- drive.Spark
|- drive.Belt
|- electric.Battery       <-- and this
\- electric.BatteryCell

Теперь я хотел бы сделать Engine и Battery видимыми для Car только , потому что клиент моего компонента по-прежнему не сможет напрямую использовать эти классы.

Я знаю, что в Java нет видимости "подпакета", но есть ли другой легкийшаблон достижения того, что я хочу, если не использовать модули Java 9?

1 Ответ

0 голосов
/ 04 марта 2019

Я бы сказал, что есть 2 варианта.Любой может не стесняться, поскольку этот вопрос интересен.

Используйте один файл для кода Java вместо пакетов

Идея состоит в том, что вы можете использовать одинJava-файл для объявления классов и API, доступных для Car.java (Engine и Battery).Классы, объявляющие понятия, скрытые от Car (Spark, Belt, BatteryCell), должны быть закрытыми и статичными, чтобы у них не было неявных связей с декларирующим классом.

Этот подход может масштабироваться, но требует больше работы.Это также полезно до некоторой степени, оно не подходит для больших баз кода или для баз кода, которые будут масштабироваться в будущем, чтобы быть большими.

 org.automobile
|- Car
|- Engine.java           <-- how to make this only available to Car
|- Engine.java-Spark     <--private static class in File Engine.java
|- Engine.java-Belt      <--private static class in File Engine.java
|- Battery.java               <-- package private class
\- Battery.java - BatteryCell <--private static class in File Battery.java

Объедините использование абстрактных и защищенных модификаторов вместе с подпакетами

Идея состоит в том, что вы создаете публичные абстрактные классы, функциональность которых предоставляется защищенными методами.Например, AbstractBattery и AbstractEngine.Затем вы можете создать некоторые классы, которые действуют как «прокси», вы расширяете абстрактные классы частными реализациями пакета в пакете Car и переопределяете методы, которые вы хотите сделать доступными.Например, двигатель и аккумулятор.Автомобиль будет иметь доступ к переопределенным методам абстрактных классов.Другим побочным эффектом является то, что вы не можете иметь окончательные методы API в своих AbstractClasses.

Этот подход больше подходит для больших баз кода и направлен на то, чтобы скрыть функциональность и абстракции от непреднамеренного использования.Однако это требует дополнительной работы.Конечно, другие по-прежнему могут расширять AbstractBattery и AbstractEngine и использовать их.

org.automobile
|- Car
|- Engine      <-- extends AbstractEngine, is package private, overrides methods that Car needs to  access
|- Battery     <-- extends AbstractBattery,is package private, overrides methods that Car needs to access
|- drive.AbstractEngine <-- Public abstract class with no public methods, methods that are needed by Engine and Car are protected.
|- drive.Spark <-package private
|- drive.Belt <-package private
|- electric.AbstractBattery <--Public abstract class with no public methods, methods that are needed by Battery and Car are protected.
\- electric.BatteryCell <-package private

Вот пример того, как это может выглядеть:

org.automobile.engine.AbstractEngine

package org.automobile.engine;

public abstract class AbstractEngine {

    protected void startEngine(){
        System.out.println("Zoom Zooomm Zoommm");
    }
}

org.automobile.Engine

package org.automobile;

import org.automobile.engine.AbstractEngine;

final  class Engine extends AbstractEngine {

    @Override
    protected void startEngine(){
        super.startEngine();
    }
}
...