ขึ้นอยู่กับข้อกำหนดเฉพาะของคุณในบางกรณีกลไกบริการตัวโหลดของ Java อาจบรรลุสิ่งที่คุณต้องการ
ในระยะสั้นจะช่วยให้นักพัฒนาประกาศอย่างชัดเจนว่าคลาสย่อยคลาสอื่น ๆ บางคลาส (หรือใช้อินเตอร์เฟซบางส่วน) โดยการแสดงรายการในไฟล์ในMETA-INF/services
ไดเรกทอรีของไฟล์ JAR / WAR จากนั้นจะสามารถค้นพบได้โดยใช้java.util.ServiceLoader
คลาสซึ่งเมื่อได้รับClass
วัตถุจะสร้างอินสแตนซ์ของคลาสย่อยที่ประกาศทั้งหมดของคลาสนั้น (หรือหากเป็นClass
ตัวแทนของอินเตอร์เฟสคลาสทั้งหมดที่ใช้อินเตอร์เฟสนั้น)
ข้อได้เปรียบหลักของวิธีนี้คือไม่จำเป็นต้องสแกนคลาสพา ธ ทั้งหมดสำหรับคลาสย่อยด้วยตนเอง - ตรรกะการค้นพบทั้งหมดจะอยู่ภายในServiceLoader
คลาสและโหลดคลาสที่ประกาศอย่างชัดเจนในMETA-INF/services
ไดเรกทอรีเท่านั้น (ไม่ใช่ทุกคลาสบนคลาสพา ธ ) .
อย่างไรก็ตามมีข้อเสียบางประการ:
- มันจะไม่พบคลาสย่อยทั้งหมดเท่านั้นที่จะมีการประกาศอย่างชัดเจน ดังนั้นหากคุณต้องการค้นหาคลาสย่อยทั้งหมดวิธีนี้อาจไม่เพียงพอ
- มันต้องการนักพัฒนาเพื่อประกาศคลาสอย่างชัดเจนภายใต้
META-INF/services
ไดเรกทอรี นี่เป็นภาระเพิ่มเติมสำหรับนักพัฒนาและอาจเกิดข้อผิดพลาดได้ง่าย
ServiceLoader.iterator()
สร้างอินสแตนซ์ subclass, ไม่ได้เป็นของClass
วัตถุ ทำให้สองประเด็น:
- คุณไม่ได้รับการพูดใด ๆ เกี่ยวกับวิธีการสร้างคลาสย่อย - คอนสตรัคเตอร์ no-arg ถูกใช้เพื่อสร้างอินสแตนซ์
- ดังนั้นคลาสย่อยต้องมี Constructor เริ่มต้นหรือต้องอธิบายความชัดเจนของ Constructor ที่ไม่มีอาร์กิวเมนต์
เห็นได้ชัดว่า Java 9 จะกล่าวถึงข้อบกพร่องเหล่านี้ (โดยเฉพาะอย่างยิ่งเรื่องที่เกี่ยวข้องกับการสร้างอินสแตนซ์ของคลาสย่อย)
ตัวอย่าง
สมมติว่าคุณสนใจหาคลาสที่ใช้อินเทอร์เฟซcom.example.Example
:
package com.example;
public interface Example {
public String getStr();
}
คลาสcom.example.ExampleImpl
ใช้อินเตอร์เฟสนั้น:
package com.example;
public class ExampleImpl implements Example {
public String getStr() {
return "ExampleImpl's string.";
}
}
คุณจะประกาศชั้นเรียนExampleImpl
คือการดำเนินการExample
โดยการสร้างไฟล์ที่มีข้อความMETA-INF/services/com.example.Example
com.example.ExampleImpl
จากนั้นคุณสามารถขอรับอินสแตนซ์ของการติดตั้งแต่ละครั้งของExample
(รวมถึงอินสแตนซ์ของExampleImpl
) ดังนี้:
ServiceLoader<Example> loader = ServiceLoader.load(Example.class)
for (Example example : loader) {
System.out.println(example.getStr());
}
// Prints "ExampleImpl's string.", plus whatever is returned
// by other declared implementations of com.example.Example.