Java에서 인터페이스에서 프라이빗 인스턴스 메소드를 언제 사용해야합니까?


9

Java 9부터 인터페이스의 메소드는 개인용이 될 수 있습니다. 개인용 메소드는 정적 또는 인스턴스 메소드 일 수 있습니다. 전용 메소드는 인터페이스 자체의 메소드에서만 사용할 수 있기 때문에 인터페이스의 다른 메소드에 대한 헬퍼 메소드로 제한됩니다.

Cay S. Horstmann, 핵심 Java 볼륨 I-기본 사항

우리는 개인 기능에 공통 기능을 넣고 공개적으로 액세스 할 수 없도록했습니다. 그러나 여기에는 두 가지 종류의 전용 메소드가 있습니다.

  1. private
  2. private static

private static메소드 사용 은 이해할 만하지 만 언제 private메소드 를 사용해야 합니까? 여기서는 인터페이스이므로 인스턴스를 다루지 않습니다. 왜 private메소드 작성 이 허용됩니까? private static방법 만 필요하지 않습니까?


인터페이스에는 다른 인스턴스 메소드가 호출하지만 공개 소비 용이 아닌 메소드가 포함될 수 있습니다.
Dave Newton

2
인터페이스 private를 구현하는 클래스에서 인터페이스의 인스턴스 메소드를 호출하십시오 .
Abra

1
이러한 전용 메소드는 인터페이스에서 다른 메소드를 호출 할 수 있으므로 private static메소드 와 동일하거나 대체 할 수 없습니다 .
Mark Rotteveel

기본 방법
모리스 페리

답변:


2

실제로 OP의 질문에 대답하려는 또 다른 시도입니다. 개인 메소드의 인터페이스에서 다른 비 정적 메소드를 호출해야하는 경우 개인 메소드는 정적 일 수 없습니다. 예를 들어, 아래의 private 메소드가 정적이면 컴파일 오류가 발생합니다.

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();
    }
}

왜 관련이 있습니까? 모든 메소드를 "공개 기본값"으로 구현할 수도 있습니다. 질문은 왜 / 어떤 의도로 z 대신 x 또는 y 구현을 선택하겠습니까-방법이 아닙니다.
Florian Salihovic

2
@FlorianSalihovic이 개인 메소드에서 다른 메소드를 호출해야 할 때 정적이 아닌 정적을 선택합니다. 그게 아닌가?
jingx

당신은 잘못된 질문을하고 있습니다. 방법의 가시성은 물체가 서로 상호 작용하는 방법에 대한 가능성을 좁히거나 넓히기 위해 선택됩니다. 의사 소통을하는 개발자가 코드를 어떻게 사용하고 사용해야하는지에 대해 의도하는 것이 중요합니다. 정적 메소드로 모든 것을 구현하거나 정적 메소드를 전혀 사용할 수 없습니다. 문제는 다른 객체 / 클래스가 기능에 액세스 할 때 발생하는 결과에 대해 생각할 필요가 있기 때문에 중요합니다.
Florian Salihovic

2
@FlorianSalihovic 그러나 사람들의 의견에서 알았 듯이 OP는 가시성 또는 정적 대 비 정적 사용 방법에 대해 묻지 않고 대신 비공개 정적이 충분할 때 인터페이스에서 정적이 아닌 개인 메소드가 허용되는 이유를 묻고있었습니다. 내 대답은 비 정적 방법 만 작동하는 유스 케이스를 제공했습니다.
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);
    }
  }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.