อินเทอร์เฟซ Java ขยายคำถาม

ฉันต้องใช้เซิร์ฟเวอร์ RMI ซึ่งจะเป็นส่วนหน้าสำหรับบริการ RMI อื่นอีกสองบริการ ดังนั้นฉันจึงตัดสินใจว่าสิ่งที่ต้องทำคือมีอินเทอร์เฟซสำหรับสิ่งนี้ ใช้งานอินเทอร์เฟซสำหรับอีกสองบริการ

public interface FrontEndServer extends Remote, BookServer, StudentServer
{
    // Block empty so far
}

อย่างไรก็ตามมีวิธีบน StudentServer

/**
 * Allows a student to borrow a book
 * 
 * @param studentID of the student who wishes to borrow a book
 * @param bookID of the book the student wishes to borrow
 * @throws RemoteException
 * @throws StudentNotFoundException when a student is not found in the system
 */
void addBookToStudent(int studentID, int bookID) throws RemoteException, StudentNotFoundException;

ฉันต้องการให้ FrontEndServer โยน BookNotFoundException ด้วย เนื่องจากบริการนี้จะตรวจสอบว่ามีหนังสืออยู่จริงหรือไม่ ก่อนที่จะพยายามเพิ่มรายละเอียด

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


person Malachi    schedule 05.03.2009    source แหล่งที่มา


คำตอบ (6)


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

ลองคิดดู:

interface A {
  void foo();
}

interface B extends A {
  void foo() throws IOException;
}

A a = new B() { ... }
a.foo();

อาจจะโยน IOException แต่คุณไม่มีทางรู้ นั่นเป็นเหตุผลที่คุณไม่สามารถทำมันได้

แน่นอนว่าสิ่งนี้เป็นที่ยอมรับอย่างสมบูรณ์:

interface A {
  void foo() throws IOException;
}

interface B extends A {
  void foo();
}

A a = new B() { ... }
try {
    a.foo();
} catch (IOException e) {
    // must catch even though B.foo() won't throw one
}

BookNotFoundException ของคุณสามารถขยาย RuntimeException หรือ RemoteException ได้ ไม่แน่ใจว่านั่นเป็นแนวทางที่ดี

person cletus    schedule 05.03.2009
comment
ขอบคุณ - ดูเหมือนว่าฉันจะใช้วิธีการต่างๆ ใน ​​FrontEndServer - ฉันคิดว่ามันก็สมเหตุสมผลดี - person Malachi; 06.03.2009
comment
แม้ว่าถ้าคุณต้องการกำหนด book ของคุณ not found ข้อยกเว้น เป็นประเภทของ RuntimeException คุณสามารถโยนมันได้โดยไม่ต้องประกาศ แต่นั่นเป็นสิ่งที่ชั่วร้าย - person Guss; 06.03.2009

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

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

ในส่วนของการออกแบบนั้น วิธี addBookToStudent จะได้ประโยชน์จากการสามารถขว้าง BookNotFoundException ได้ อินเทอร์เฟซมีความเปราะบางในแง่ที่ว่าการเปลี่ยนแปลงในทางใดทางหนึ่งจะทำให้โค้ดเสียหายจำนวนมาก คุณต้องระมัดระวังในการออกแบบเริ่มแรก ตัวอย่างเช่น BookNotFoundException น่าจะเป็นค่าเฉพาะเจาะจง ไม่มีข้อยกเว้นหลายประการที่จะป้องกันไม่ให้ "เพิ่ม" หนังสือให้กับนักเรียนใช่หรือไม่ (ฉันเดาว่านักเรียนกำลังตรวจสอบหนังสือจากห้องสมุดที่ให้ยืม) ตัวอย่างเช่น: CheckOutLimitExceededException, UnpaidFinePendingException, AdultLiteraturePermissionException เป็นต้น

คิดอย่างรอบคอบเกี่ยวกับประเภทของข้อยกเว้นที่เลือกซึ่งอาจเหมาะสมกับระดับนามธรรมเมื่อออกแบบอินเทอร์เฟซ เนื่องจากจะเปลี่ยนแปลงได้ยากในภายหลัง

person erickson    schedule 05.03.2009

แนวคิดบางประการสำหรับคุณ:

  1. ประกาศวิธีการ addBookToStudent ในอินเทอร์เฟซเพื่อส่ง BookNotFoundException แม้ว่า StudentServer อาจจะไม่ทิ้งข้อยกเว้นจริงๆ แต่นั่นไม่ได้หมายความว่าคุณจะไม่สามารถใส่ไว้ในอินเทอร์เฟซได้

  2. คุณสามารถสร้างข้อยกเว้นใหม่ - ObjectNotFoundException และมี BookNotFoundException และ StudentNotFoundException สืบทอดจากที่นั่น จากนั้นประกาศ addBookToStudent ให้ส่ง ObjectNotFoundException

  3. สิ่งที่ฉันอาจจะทำใน "ชีวิตจริง" - ให้ StudentServer พูดคุยกับ BookServer เพื่อตรวจสอบความถูกต้องของรหัสหนังสือและโยนข้อยกเว้นเอง แทนที่จะทำการตรวจสอบนั้นใน FrontEndServer โดยเฉพาะอย่างยิ่งถ้า StudentServer จะถูกนำมาใช้โดยตรงจากสิ่งอื่นใดนอกเหนือจาก FrontEndServer

person Eric Petroelje    schedule 05.03.2009

ฉันขอแนะนำให้คุณพยายามแยก API ที่เปิดเผยของคุณออกจาก API ที่ใช้ในการปรับใช้ฟังก์ชันของคุณ ฉันเดาว่าจุดประสงค์ของส่วนหน้าของบริการ RMI คือเพื่อให้การแยกและความเสถียรจากแอปพลิเคชันการโทร

โดยที่ฉันอยากจะแนะนำให้คุณ:

  • เขียน API ที่คุณต้องการเปิดเผย
  • เขียนการใช้งานที่เชื่อมโยงระหว่าง API ของคุณและบริการแบ็คเอนด์
person Kam    schedule 05.03.2009

เป็นไปได้ในทางทฤษฎีถ้า BookNotFoundException ขยาย RemoteExcepiton

อย่างไรก็ตาม ฉันคิดว่าคุณไม่สามารถควบคุมอินเทอร์เฟซ StudentServer ได้ ดูเหมือนว่าจุดประสงค์ของอินเทอร์เฟซนั้นคือการไม่โยน BookNotFoundException แม้ว่าฉันจะเข้าใจว่าทำไมคุณถึงต้องการ แต่อินเทอร์เฟซดูเหมือนจะไม่สนับสนุนสิ่งนั้น

person Rob Di Marco    schedule 05.03.2009

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

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

หากคุณลองคิดดู คุณจะเห็นว่านี่เป็นตรรกะ FrontEndServer ของคุณสามารถใช้เป็น BookServer ได้โดยใช้โค้ดบางส่วน รหัสในระหว่างการคอมไพล์คาดว่าจะมีข้อยกเว้นที่กำหนดไว้ใน BookServer จากนั้นในระหว่างรันไทม์ จู่ๆ BookServer ก็ไม่ได้กำหนดไว้ในอินเทอร์เฟซ BookServer ก็มีข้อยกเว้นเกิดขึ้น หากโค้ดนั้นรู้เพียงว่า BookException เป็นสิ่งที่ไม่คาดคิด จะไม่มีคำสั่ง catch หรือ Throws ที่จะจัดการกับมัน

person DefLog    schedule 05.03.2009