Коли в Java потрібно використовувати методи приватного примірника в інтерфейсах?


9

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

Кей С. Хорстманн, Core Java Volume I - Основи

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

  1. private
  2. private static

Використання private staticметодів зрозуміло, але коли нам слід використовувати privateметоди? Ми тут не маємо справу з прикладами, оскільки це інтерфейс, тож чому створювати privateметоди дозволено? Хіба нам не потрібні лише private staticметоди?


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

2
Спробуйте викликати privateметод екземпляра інтерфейсу в класі, який реалізує інтерфейс.
Авра

1
Такий приватний метод може викликати інші методи з інтерфейсу, тому вони не еквівалентні або замінені private staticметодами.
Марк Ротвевель

Відповіді:


2

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

public interface InterfaceWithMethods {
    public default void doSomething() {
        doSomethingCommon();
    }

    public default void doSomethingElse() {
        doSomethingCommon();
    }

    public void actuallyDoSomething();

    private void doSomethingCommon() {
        System.out.println("Do something first.");
        actuallyDoSomething();
    }
}

Чому це актуально? Ви також можете реалізувати кожен метод як "загальнодоступний стандарт". Питання полягає в тому, чому / з яким наміром ви обрали б реалізацію x або y над z - не як.
Флоріан Саліхович

2
@FlorianSalihovic ви вибрали б нестатичне над статичним, коли вам потрібно викликати інший метод із цього приватного методу. Чи не тому?
jingx

Ви ставите неправильне запитання. Наочність методів вибирається для звуження або розширення можливостей взаємодії об'єктів один з одним. Важливо, оскільки розробники спілкуються з намірами про те, як їх повинен / повинен / може бути використаний код. Ви можете реалізувати все в статичних методах або взагалі не використовувати статичного методу. Питання важливе, оскільки нам потрібно думати про наслідки доступу інших об'єктів / класів до функціональності, який взагалі повинен бути недоступним.
Флоріан Саліхович

2
@FlorianSalihovic Але, як я дізнався з коментарів людей, ОП не запитував про видимість або коли використовувати статичний проти нестатичний, натомість вони запитували, чому нестатичні приватні методи навіть дозволені на інтерфейсах, коли приватних статичних, здавалося б, достатньо. У моїй відповіді був випадок використання, коли працював би лише нестатичний метод.
jingx

3

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

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

package com.company;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Main {

  public static void main(final String[] args) {
    var messages =
        List.of(
            MessageQueue.newSubject("Message 1"),
            MessageQueue.newTopic("Message 2"),
            MessageQueue.newTopic("Message 3"));
    final MessageQueueAdapter1 queue1 = () -> messages;
    inspectQueue(queue1);
    final MessageQueueAdapter2 queue2 = () -> messages;
    inspectQueue(queue2);
  }

  private static void inspectQueue(final MessageQueue queue) {
    final List<Message> messagesWithSubject = queue.getMessagesWithSubject();
    assert messagesWithSubject.size() == 1 : "expected one message with 'Subject'";
    final List<Message> messagesWithTopic = queue.getMessagesWithTopic();
    assert messagesWithTopic.size() == 2 : "expected two message with 'Topic'";
    assert !queue.getMessages().isEmpty() && 3 == queue.getMessages().size()
        : "expected three messages in total";
  }

  @FunctionalInterface
  interface Message {
    private static boolean isPrefixedBy(final String message, final String prefix) {
      return message != null && !message.isEmpty() && message.startsWith(prefix);
    }

    default boolean hasSubject() {
      return isPrefixedBy(this.getMessage(), MessageQueue.PREFIX_SUBJECT);
    }

    default boolean hasTopic() {
      return isPrefixedBy(this.getMessage(), MessageQueue.PREFIX_TOPIC);
    }

    String getMessage();
  }

  interface MessageQueue {
    String PREFIX_SUBJECT = "Subject: ";

    String PREFIX_TOPIC = "Topic: ";

    private static Message newMessage(final String message) {
      return () -> message;
    }

    static Message newSubject(final String message) {
      return newMessage(PREFIX_SUBJECT + message);
    }

    static Message newTopic(final String message) {
      return newMessage(PREFIX_TOPIC + message);
    }

    List<Message> getMessages();

    List<Message> getMessagesWithSubject();

    List<Message> getMessagesWithTopic();
  }

  @FunctionalInterface
  interface MessageQueueAdapter1 extends MessageQueue {
    private static List<Message> filterBy(
        final List<Message> messages, final Predicate<Message> predicate) {
      return messages.stream().filter(predicate).collect(Collectors.toList());
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithSubject() {
      return filterBy(this.getMessages(), Message::hasSubject);
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithTopic() {
      return filterBy(this.getMessages(), Message::hasTopic);
    }
  }

  @FunctionalInterface
  interface MessageQueueAdapter2 extends MessageQueue {
    private List<Message> filterBy(final Predicate<Message> predicate) {
      return this.getMessages().stream().filter(predicate).collect(Collectors.toList());
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithSubject() {
      return filterBy(Message::hasSubject);
    }

    /** {@inheritDoc} */
    @Override
    default List<Message> getMessagesWithTopic() {
      return filterBy(Message::hasTopic);
    }
  }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.