Как скрыть публичный метод? - PullRequest
3 голосов
/ 19 июля 2011

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

Ответы [ 10 ]

5 голосов
/ 19 июля 2011

Вы не можете сделать публичный метод скрытым (если вы не можете объявить его закрытым).Однако вы можете поместить в подкласс и только позволить пользователям объекта знать тип суперкласса, а именно:

class A {
   //Externally visible members
}

class B extends A {
   //Secret public members
}

Затем вы создаете экземпляр класса B, но только для того, чтобы тип A был известендругие ...

4 голосов
/ 19 июля 2011

Как только вы объявляете публичный метод, он становится частью контракта вашего класса.Вы не можете скрыть это, потому что все пользователи класса ожидают, что этот метод будет доступен.

1 голос
/ 20 апреля 2016

Идиоматический подход к этому состоит в использовании интерфейсов для ограничения видимости ваших методов.

Например, допустим, у вас есть следующий класс:

public class MyClass {
    public void method1() {
        // ...
    }
    public void method2() {
        // ...
    }
}

Если вы хотитеограничьте некоторые части проекта только просмотром method1(), тогда вы просто опишите его в интерфейсе и попросите класс реализовать этот интерфейс:

public interface Method1Interface {
    public void method1();
}

...

public class MyClass implements Method1Interface {
    public void method1() {
        // ...
    }
    public void method2() {
        // ...
    }
}

Затем вы можете ограничить видимостьметоды, выбирая передачу класса либо как MyClass ссылку, либо как Method1Interface ссылку:

public class OtherClass {
    public void otherMethod1(MyClass obj) {
        // can access both obj.method1() and obj.method2()
    }
    public void otherMethod2(Method1Interface obj) {
        // can only access obj.method1(), obj.method2() is hidden.
    }
}

Преимущество этого подхода в том, что он также может быть легко расширен.Скажем, например, теперь вы также хотите независимо контролировать доступ к method2().Все, что вам нужно сделать, это создать новый Method2Interface по той же схеме, что и Method1Interface, и заставить MyClass реализовать его.Затем вы можете контролировать доступ к method2() точно так же, как и method1().

. Этот подход аналогичен тому, который был предложен в ответе @ MathiasSchwarz , но гораздо более гибок:

  • Независимый контроль доступа, описанный в предыдущем абзаце, невозможен при использовании техники Матиаса, поскольку Java не поддерживает множественное наследование.
  • Отсутствие отношения наследования также позволяет болеегибкость в проектировании иерархии классов.
  • Единственное изменение, которое необходимо внести в исходный класс, - это добавление implements Method1Interface, что означает, что это очень рефактор с низким уровнем воздействия, поскольку существующие пользователи MyClass вообще не нужно менять (по крайней мере, до тех пор, пока не будет сделан выбор изменить их на Method1Interface).
1 голос
/ 19 июля 2011

Если метод публичный, его нельзя скрыть.То, что вы действительно можете искать, это просто способ ограничить доступ к вызову метода.Есть и другие способы достижения подобного эффекта.

Если есть некоторые вещи, которые ваш конечный автомат выполняет, которые «используются только один раз, когда моё приложение запускается впервые», это звучит так, как будто эти вещи могутслучиться в конструкторе.Хотя это зависит от того, насколько сложны эти задачи, вы, возможно, не захотите делать это во время сборки.

Поскольку вы сказали, что ваш конечный автомат статичен, это также Singleton ?Возможно, вы могли бы использовать шаблон Singleton .

public class SimpleStateMachine {

  private static SimpleStateMachine instance = new SimpleStateMachine();

  private SimpleStateMachine() {
      super();
      System.out.println("Welcome to the machine");  // prints 1st
  }

  public static SimpleStateMachine getInstance() {
      return instance;
  }

  public void doUsefulThings() {
      System.out.println("Doing useful things");  // prints 3rd
  }
}

Вот некоторый код для клиента этого Singleton:

public class MachineCaller {

    static SimpleStateMachine machine = SimpleStateMachine.getInstance();

    public static void main(String... args) {
        System.out.println("Start at the very beginning");  // prints 2nd
        machine.doUsefulThings();
    }
}

Обратите внимание, что экземпляр SimpleStateMachine не являетсяне построен до первого доступа к вашему классу.Поскольку в клиенте MachineCaller он объявлен как static, это считается «первым доступом» и создает экземпляр.Помните об этом, если вы определенно хотите, чтобы ваш конечный автомат выполнял некоторые из этих задач инициализации во время запуска приложения.

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

public class SimpleStateMachine {

    static {
        System.out.println("First time tasks #1");
        System.out.println("First time tasks #2");
    }

    public SimpleStateMachine() {
        super();
        System.out.println("Welcome to the machine");
    }

    public void doUsefulThings() {
        System.out.println("Doing useful things");
    }
}

Пока мы занимаемся этим, так как вы упомянули, что это конечный автомат ... книга Head First Design Patterns хорошо,Легко понятная трактовка State Pattern .Я рекомендую прочитать, если вы еще этого не сделали.

1 голос
/ 19 июля 2011

Вы можете использовать уровень пакета вместо публичного.Таким образом, он может быть вызван только вашим приложением.

0 голосов
/ 19 июля 2011

Я видел, как многие Java-программисты делают что-то вроде этого:

public static void main(String args[]) {
      new MyClass();
}

Так что в основном они создают только один объект класса.Если есть метод, который должен запускаться только один раз, я думаю, что этот подход может достичь этого.Ваш метод будет вызываться из конструктора.Но так как я не знаю, как работает ваше приложение, каковы ограничения, так что это всего лишь мысль.

0 голосов
/ 19 июля 2011

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

Это сделало бы метод или класс видимым для класса и других в пакете, но обеспечило бы вам определенный уровень конфиденциальности.Возможно, вы захотите взглянуть на Какая польза от защиты на уровне пакетов в Java? .

0 голосов
/ 19 июля 2011

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

Возможно, вы могли бы оставить метод открытым, но заставить его ничего не делать после первого вызова?

0 голосов
/ 19 июля 2011

Хмм ... Вы хотите приватный метод, но хотите получить к нему доступ снаружи?

Попробуйте сделать это с помощью отражения.http://download.oracle.com/javase/tutorial/reflect/index.html

0 голосов
/ 19 июля 2011

Альтернативное решение: вы можете сделать его private и создать метод invokeHiddenMethod(String methodName, Object ... args), используя отражение.

...