ใน Java เราควรใช้เมธอดอินสแตนซ์ส่วนตัวในอินเตอร์เฟสเมื่อใด


9

ในฐานะของ Java 9 วิธีการในอินเตอร์เฟสสามารถเป็นส่วนตัวได้ วิธีการส่วนตัวสามารถคงที่หรือวิธีการอินสแตนซ์ เนื่องจากไพรเวตเมธอดสามารถใช้ได้เฉพาะในเมธอดของอินเตอร์เฟสเองเท่านั้นการใช้งานจึง จำกัด เฉพาะวิธีการช่วยเหลือสำหรับเมธอดอื่นของอินเตอร์เฟส

Cay S. Horstmann, Core Java Volume I - ความรู้พื้นฐาน

ฉันเข้าใจว่าเราสามารถใส่ฟังก์ชั่นทั่วไปในวิธีการส่วนตัวและไม่ให้สาธารณชนเข้าถึงได้ แต่เรามีวิธีส่วนตัวสองแบบที่นี่:

  1. private
  2. private static

การใช้private staticวิธีการนั้นเป็นสิ่งที่เข้าใจได้ แต่เราควรใช้privateวิธีการเมื่อใด เราไม่ได้จัดการกับอินสแตนซ์ที่นี่เนื่องจากเป็นอินเทอร์เฟซดังนั้นทำไมจึงprivateอนุญาตให้สร้างวิธีได้ เราไม่ต้องการprivate staticวิธีการอย่างเดียวเหรอ?


อินเทอร์เฟซอาจรวมถึงวิธีการที่วิธีการอินสแตนซ์อื่นเรียก แต่ไม่ได้มีไว้สำหรับการบริโภคสาธารณะ
Dave Newton

2
ลองโทรหาprivateวิธีการอินสแตนซ์ของอินเทอร์เฟซในคลาสที่ใช้ส่วนต่อประสาน
Abra

1
วิธีการส่วนตัวดังกล่าวสามารถเรียกใช้วิธีอื่นจากอินเทอร์เฟซดังนั้นจึงไม่เทียบเท่าหรือเปลี่ยนได้โดยprivate staticวิธีการ
Mark Rotteveel

บางทีวิธีการเริ่มต้นอาจจะ
Maurice Perry

คำตอบ:


2

ตกลงความพยายามอีกครั้งในการตอบคำถามของ OP จริง ๆ เมื่อคุณต้องการเรียกวิธีอื่นที่ไม่คงที่บนอินเทอร์เฟซจากวิธีส่วนตัววิธีส่วนตัวไม่สามารถคงที่ได้ ตัวอย่างเช่นจะมีข้อผิดพลาดในการรวบรวมหากวิธีการส่วนตัวด้านล่างเป็นแบบคงที่:

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 มากกว่าไม่ใช่วิธี
Florian Salihovic

2
@ FlorianSalihovic คุณจะเลือกไม่คงที่มากกว่าคงที่เมื่อคุณต้องการที่จะเรียกวิธีการอื่นจากวิธีการส่วนตัวนี้ นั่นเป็นสาเหตุหรือไม่
jingx

คุณกำลังถามคำถามผิด การมองเห็นวิธีการนั้นถูกเลือกให้แคบลงหรือขยายความเป็นไปได้ในการที่วัตถุมีปฏิสัมพันธ์ซึ่งกันและกัน สิ่งสำคัญคือผู้พัฒนาต้องการสื่อสารเกี่ยวกับวิธีการใช้ / ต้อง / ใช้รหัสของตนอย่างไร คุณสามารถใช้ทุกอย่างในวิธีคงที่หรือไม่ใช้วิธีคงที่เลย คำถามนี้มีความสำคัญเนื่องจากเราต้องคำนึงถึงผลที่ตามมาจากการเข้าถึงการทำงานของวัตถุ / คลาสอื่น ๆ ซึ่งไม่ควรเข้าถึงได้ทั้งหมด
Florian Salihovic

2
@ FlorianSalihovic แต่เมื่อฉันได้เรียนรู้จากความคิดเห็นของผู้คน OP ไม่ได้ถามเกี่ยวกับทัศนวิสัยหรือเวลาที่จะใช้ static vs non-static แต่พวกเขาถามว่าทำไมเมธอดส่วนตัว non-static ถึงได้รับอนุญาตบนอินเตอร์เฟส คำตอบของฉันให้กรณีการใช้งานซึ่งวิธีการแบบไม่คงที่จะทำงานได้เท่านั้น
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.