การซ้อนด้วยอินเตอร์เฟส Java

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

เพิ่มเติมเกี่ยวกับอินเตอร์เฟส Java

สำหรับข้อมูลเบื้องต้นเกี่ยวกับอินเทอร์เฟซ Java รวมถึงความแตกต่างระหว่างคลาสและอินเทอร์เฟซโปรดดูบทช่วยสอนJava 101ของฉันการทำงานกับอินเทอร์เฟซใน Java

การซ้อนอินเทอร์เฟซในคลาส

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

 class EnclosingClass { interface EnclosedInterface1 { } static interface EnclosedInterface2 { } } 

EnclosedInterface1และEnclosedInterface2มีการเชื่อมต่อสมาชิกแบบคงที่ ไม่มีคลาสใดเทียบเท่ากับคลาสโลคัลเนื่องจากไม่สามารถประกาศอินเทอร์เฟซในบล็อกได้ อย่างไรก็ตามสามารถใช้อินเทอร์เฟซในบริบทคลาสที่ไม่ระบุชื่อได้

โดยทั่วไปอินเทอร์เฟซที่ซ้อนกันจะไม่สามารถเข้าถึงได้จากนอกเหนือจากคลาสที่ปิดล้อมไว้ มิฉะนั้นคุณสามารถประกาศให้เป็นอินเทอร์เฟซระดับบนสุดได้ แต่สามารถเข้าถึงได้จากภายในชั้นเรียนที่ปิดล้อมดังที่แสดงไว้ที่นี่:

 class EnclosingClass { interface EnclosedInterface1 { } static interface EnclosedInterface2 { } static class EnclosedClass1 implements EnclosedInterface1, EnclosedInterface2 { } class EnclosedClass2 implements EnclosedInterface1, EnclosedInterface2 { } void m() { class EnclosedClass3 implements EnclosedInterface1, EnclosedInterface2 { } new EnclosedInterface1() { }; } } 

โปรดสังเกตว่าคลาสสมาชิกแบบคงที่คลาสสมาชิกที่EnclosedClass1ไม่คงที่EnclosedClass2และคลาสโลคัลจะEnclosedClass3ใช้อินเทอร์เฟซที่ซ้อนกันทั้งสองแบบ อย่างไรก็ตามสามารถใช้อินเทอร์เฟซเดียวเท่านั้นในบริบทคลาสที่ไม่ระบุชื่อ (ดูคลาสแบบคงที่และคลาสภายในใน Java สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคลาสที่ไม่ระบุชื่อ)

คลาสที่มีอินเทอร์เฟซซ้อนกันใน java.net

ไลบรารีคลาสมาตรฐานของ Java ประกอบด้วยคลาสที่มีอินเตอร์เฟสซ้อนกัน ตัวอย่างเช่นInetAddress(ในjava.netแพ็คเกจ) ซึ่งแสดงถึงที่อยู่ Internet Protocol ประกาศAddressesอินเทอร์เฟซส่วนตัวที่ใช้งานโดยคลาสสมาชิกส่วนตัวCachedAddressesและNameServiceAddressesแบบคงที่ นอกจากนี้ยังประกาศNameServiceอินเทอร์เฟซส่วนตัวที่ใช้งานโดยคลาสสมาชิกส่วนตัวPlatformNameServiceและHostsFileNameServiceแบบคงที่

การซ้อนอินเทอร์เฟซในอินเทอร์เฟซ

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

 interface EnclosingInterface { interface EnclosedInterface1 // implicitly static and public { } static interface EnclosedInterface2 // explicitly static and implicitly public { } } 

คุณเข้าถึงอินเทอร์เฟซที่แนบมาโดยนำหน้าชื่อด้วยชื่อของอินเทอร์เฟซและตัวดำเนินการเข้าถึงสมาชิก ยกตัวอย่างเช่นการระบุในการเข้าถึงEnclosingInterface.EnclosedInterface1EnclosedInterface1

อินเทอร์เฟซที่ซ้อนกันใน Java Collections Framework

Java Collections Framework ให้ข้อมูลเชิงลึกเกี่ยวกับประโยชน์ของการซ้อนอินเทอร์เฟซหนึ่งในอีกอินเตอร์เฟส พิจารณาjava.util.Mapอินเทอร์เฟซซึ่งอธิบายแผนที่ (ชุดของคู่คีย์ - ค่า) Mapอินเตอร์เฟซบทคัดย่อสิ่งที่มันหมายถึงการเป็นแผนที่ ชั้นเรียนเช่นHashMapและjava.util.TreeMapการใช้งานMapอธิบายการใช้งานแผนที่ประเภทต่างๆ

Mapประกาศว่าEntryเป็นหนึ่งในสมาชิก Entryเป็นอินเทอร์เฟซแบบซ้อนที่อธิบายคู่คีย์ - ค่า Entryอินเตอร์เฟซที่มีการประกาศในMapเพราะความสัมพันธ์ที่ใกล้ชิดระหว่างสอง interfaces - แต่ละรายการต้องเป็นแผนที่ Entryถูกนำไปใช้โดยjava.util.AbstractMapคลาสของคลาสSimpleEntryและSimpleImmutableEntryสมาชิกแบบคงที่ โดยทั่วไปคุณจะไม่สนใจคลาสสมาชิกแบบคงที่เหล่านี้และโต้ตอบกับMap.Entryแทน

การซ้อนคลาสในอินเทอร์เฟซ

คุณลักษณะภาษาแปลกหน้าอย่างหนึ่งของ Java คือความสามารถในการซ้อนคลาสภายในอินเทอร์เฟซ เช่นเดียวกับอินเทอร์เฟซที่ซ้อนกันคลาสที่ซ้อนกันเป็นแบบสาธารณะโดยปริยายและคงที่ นี่คือตัวอย่าง:

 interface EnclosingInterface { class EnclosedClass { } } 

แม้จะมีความแปลกประหลาด แต่ความสามารถในการซ้อนคลาสภายในอินเทอร์เฟซอาจมีประโยชน์โดยเฉพาะอย่างยิ่งเมื่อมีความสัมพันธ์ที่แน่นหนาระหว่างอินเทอร์เฟซที่ปิดล้อมและคลาสที่ปิดอยู่ การบันทึกความสัมพันธ์นี้ช่วยเพิ่มความสามารถในการอ่านของซอร์สโค้ด ในกรณีที่คลาสและอินเทอร์เฟซมีชื่อเดียวกันการซ้อนกันยังสามารถช่วยคุณหลีกเลี่ยงความขัดแย้งของชื่อระหว่างทั้งสอง

ตัวอย่าง: แอดเดรสอินเตอร์เฟซที่อยู่ล้อมรอบคลาสที่อยู่

สมมติว่าคุณต้องการสร้างโมเดลของเอนทิตีที่สามารถระบุแอดเดรสได้เช่นจดหมายโปสการ์ดและพัสดุ แต่ละเอนทิตีจะได้รับการอธิบายตามคลาสของตัวเอง แต่พวกเขาทั้งหมดมีความเหมือนกันในการระบุถึงปลายทางบางแห่ง แต่ละคลาสอาจได้รับการออกแบบให้มีช่องที่อยู่ซ้ำกันหรือคุณอาจสรุปรายละเอียดเหล่านี้ลงในคลาสซูเปอร์คลาสทั่วไป หรือคุณสามารถใช้ประโยชน์จากAddressableอินเทอร์เฟซของ Listing 1

รายการ 1. Addressable.java

 public interface Addressable { public class Address { private String boxNumber; private String street; private String city; public Address(String boxNumber, String street, String city) { this.boxNumber = boxNumber; this.street = street; this.city = city; } public String getBoxNumber() { return boxNumber; } public String getStreet() { return street; } public String getCity() { return city; } public String toString() { return boxNumber + " - " + street + " - " + city; } } public Address getAddress(); } 

Addressableอินเตอร์เฟซอธิบายนิติบุคคลแอดเดรสว่ามีที่อยู่ ที่อยู่นี้อธิบายโดยAddressคลาสที่ซ้อนกัน วิธีการจะดำเนินการอะไรก็ตามที่การดำเนินการระดับgetAddress()Addressable

2 รายการของขวัญรหัสที่มากับคลาสที่ใช้LetterAddressable

รายการที่ 2. Letter.java

 public class Letter implements Addressable { private Addressable.Address address; public Letter(String boxNumber, String street, String city) { address = new Addressable.Address(boxNumber, street, city); } public Address getAddress() { return address; } } 

Letterเก็บเดียวฟิลด์ประเภทaddress Addressable.Addressคลาสที่ซ้อนกันนี้ถูกสร้างอินสแตนซ์โดยคอนLetterสตรัคเตอร์ของ getAddress()วิธีการดำเนินการส่งคืนวัตถุนี้

ลองพิจารณาว่าจะเกิดอะไรขึ้นเมื่อเราเพิ่มPostcardและParcelเรียนในAddressablesแอปพลิเคชัน 3 รายการของขวัญรหัสที่มาไปยังAddressablesแอพลิเคชันซึ่งแสดงให้เห็นถึงPostcard, ParcelและLetterประเภท

รายการ 3. Addressables.java

 public class Addressables { public static void main(String[] args) { Addressable[] addressables = { new Letter("100", "Main Street", "Town A"), new Postcard("200", "Waterfront Drive", "Town B"), new Parcel("300", "10th Ave", "Town C") }; for (int i = 0; i < addressables.length; i++) System.out.println(addressables[i].getAddress()); } }

main()วิธีแรกสร้างอาร์เรย์ของAddressableวัตถุ จากนั้นจะวนซ้ำบนวัตถุเหล่านี้โดยเรียกใช้getAddress()ในแต่ละวัตถุ เมธอดAddressable.Addressของอ็อบเจ็กต์ที่ส่งคืนtoString()ถูกเรียกใช้โดยSystem.out.println()เพื่อส่งคืนการแสดงสตริงของอ็อบเจ็กต์และการแทนค่านี้จะถูกส่งออกในภายหลัง

รวบรวมรายชื่อ 2 และ 3 พร้อมด้วยPostcard.javaและParcel.javaดังต่อไปนี้:

 javac *.java 

เรียกใช้แอปพลิเคชันดังนี้:

 java Addressables 

คุณควรสังเกตผลลัพธ์ต่อไปนี้:

 100 - Main Street - Town A 200 - Waterfront Drive - Town B 300 - 10th Ave - Town C 

อินเทอร์เฟซที่ซ้อนกันด้วยวิธีการแบบคงที่ (อินเตอร์เฟสวิธีการแบบคงที่)

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

 interface I { static void m() { class C { } } } 

สรุป

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

เรื่องนี้ "Nesting with Java interface" เผยแพร่ครั้งแรกโดย JavaWorld