การสร้างใหม่เป็นข้อยกเว้นที่ทำให้สิ่งที่เป็นนามธรรมรั่วไหลหรือไม่?


12

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

// in the interface

/**
 * @return This method returns a doohickey to use when you need to foo
 * @throws DoohickeyDisasterException
 */
public function getThatDoohickey();

// in the implementation

public function getThatDoohickey() {

    try {
        $SomethingInTheClass->doSomethingThatThrowsAnException();
    } catch (Exception $Exc) {
        throw new DoohickeyDisasterException('Message about doohickey failure');
    }

    // other code may return the doohickey

}

ฉันใช้วิธีนี้เพื่อป้องกันไม่ให้สิ่งที่เป็นนามธรรมรั่วไหล

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

เพียงชี้แจงคำถามของฉันจะเกี่ยวข้องกับการเปลี่ยนเป็นบรรทัดของรหัสต่อไปนี้

throw new DoohickeyDisasterException($Exc->getMessage(), null, $Exc);

ข้อยกเว้นควรจะเกี่ยวกับสาเหตุที่ไม่เกี่ยวกับการที่พวกเขาโยน หากรหัสของคุณสามารถมีแล้วมันควรจะโยนfile_not_found file_not_found_exceptionข้อยกเว้นไม่ควรระบุเฉพาะไลบรารี
Mooing Duck

คำตอบ:


11

คำถามของฉันคือ: จะผ่านข้อยกเว้นภายในที่โยนเป็นข้อยกเว้นก่อนหน้านี้จะรั่วนามธรรม? หากไม่เป็นเช่นนั้นจะเหมาะที่จะใช้ข้อความข้อยกเว้นก่อนหน้านี้ซ้ำอีกครั้งหรือไม่

คำตอบคือ: "มันขึ้นอยู่กับ"

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

หากข้อยกเว้นของคุณมีการติดตามลงไปยังสาเหตุที่แท้จริงในรหัสที่เรียกว่าอาจรั่วไหลข้อมูลภายนอกสิ่งที่เป็นนามธรรม - แต่โดยทั่วไปฉันคิดว่าเป็นที่ยอมรับได้เนื่องจากข้อยกเว้นนั้นถูกจัดการโดยผู้โทร (และไม่มีใครสนใจ มาจาก) หรือแสดงต่อผู้ใช้ (และคุณต้องการทราบสาเหตุที่แท้จริงสำหรับการดีบัก)

อย่างไรก็ตามบ่อยครั้งที่การอนุญาตให้มีการยกเว้นเป็นตัวเลือกที่เหมาะสมในการนำไปใช้และไม่ใช่ปัญหาของสิ่งที่เป็นนามธรรม แค่ถามว่า "ฉันจะโยนรหัสนี้ไปหรือเปล่าถ้ารหัสที่ฉันโทรไม่ได้"


8

พูดอย่างเคร่งครัดหากข้อยกเว้น 'ภายใน' เปิดเผยอะไรเกี่ยวกับผลงานภายในของการนำไปใช้งานคุณกำลังรั่ว ดังนั้นในทางเทคนิคคุณควรจับทุกอย่างและโยนประเภทยกเว้นของคุณเอง

แต่.

ค่อนข้างเป็นข้อโต้แย้งที่สำคัญไม่กี่สามารถทำผิดนี้ สะดุดตาที่สุด:

  • ยกเว้นเป็นสิ่งที่ยอดเยี่ยม ; พวกเขาละเมิดกฎของ 'การดำเนินงานปกติ' ในหลาย ๆ ทางอยู่แล้วดังนั้นพวกเขาอาจละเมิด encapsulation และนามธรรมระดับอินเทอร์เฟซเช่นกัน
  • ประโยชน์ของการมีการติดตามสแต็คที่มีความหมายและข้อมูลข้อผิดพลาด ณ จุดนั้นมักจะมีค่ามากกว่าความถูกต้องของ OOP ตราบใดที่คุณไม่รั่วไหลของข้อมูลภายในโปรแกรมผ่านสิ่งกีดขวาง UI (ซึ่งเป็นการเปิดเผยข้อมูล)
  • การห่อทุกข้อยกเว้นภายในในประเภทยกเว้นด้านนอกที่เหมาะสมสามารถนำไปสู่รหัสสำเร็จรูปที่ไม่มีประโยชน์ซึ่งเอาชนะวัตถุประสงค์ทั้งหมดของข้อยกเว้น (กล่าวคือใช้การจัดการข้อผิดพลาดโดยไม่สร้างมลพิษให้กับการจัดการรหัสปกติด้วยการจัดการข้อผิดพลาดสำเร็จรูป)

ที่กล่าวว่าการจับและห่อข้อยกเว้นมักจะสมเหตุสมผลถ้าเพียงเพิ่มข้อมูลเพิ่มเติมลงในบันทึกของคุณหรือเพื่อป้องกันการรั่วไหลของข้อมูลภายในไปยังผู้ใช้ปลายทาง การจัดการข้อผิดพลาดยังคงเป็นรูปแบบศิลปะและยากที่จะต้มจนเป็นกฎทั่วไปไม่กี่ข้อ ข้อยกเว้นบางอย่างควรได้รับการเดือดร้อนคนอื่นไม่ควรและการตัดสินใจก็ขึ้นอยู่กับบริบท หากคุณกำลังเข้ารหัส UI คุณไม่ต้องการให้อะไรผ่านไปยังผู้ใช้ที่ไม่มีการกรอง แต่ถ้าคุณกำลังเข้ารหัสไลบรารีที่ใช้โปรโตคอลเครือข่ายบางอย่างการทำ bubbling ข้อยกเว้นบางอย่างอาจเป็นสิ่งที่ถูกต้องที่จะทำ ; แปลNetworkDownExceptionไปFoobarNetworkDownExceptionเป็น cruft เพียงความหมาย)


6

ก่อนอื่นสิ่งที่คุณทำที่นี่ไม่ได้สร้างข้อยกเว้นขึ้นมาใหม่ Rethrowing คือการโยนข้อยกเว้นแบบเดียวกันอย่างแท้จริง:

try {
    $SomethingInTheClass->doSomethingThatThrowsAnException();
} catch (Exception $Exc) {
    throw $Exc;
}

เห็นได้ชัดว่านี่ไม่มีจุดหมาย Rethrowing สำหรับสถานการณ์ที่คุณต้องการปล่อยทรัพยากรบางอย่างหรือบันทึกข้อยกเว้นหรือสิ่งอื่นที่คุณอาจต้องการทำโดยไม่หยุดข้อยกเว้นจากการทำให้สแตกขึ้น

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

แต่นี่ไม่เกี่ยวกับ abstractions ที่รั่วนั่นเป็นอีกปัญหาหนึ่ง

เพื่อตอบคำถามว่าข้อยกเว้นที่ถูก rethrown (หรือข้อยกเว้นที่ไม่ได้ตรวจสอบ) สามารถเป็นนามธรรมได้หรือไม่ฉันขอบอกว่าขึ้นอยู่กับรหัสโทรศัพท์ของคุณ หากรหัสนั้นต้องการความรู้เกี่ยวกับเฟรมเวิร์กที่เป็นนามธรรมนั่นเป็นสิ่งที่เป็นนามธรรมรั่วไหลเพราะถ้าคุณแทนที่เฟรมเวิร์กนั้นด้วยอันอื่นคุณต้องเปลี่ยนรหัสนอกนามธรรมของคุณ

ตัวอย่างเช่นถ้า DoohickeyDisasterException เป็นคลาสจากเฟรมเวิร์กและรหัสการโทรของคุณมีลักษณะเช่นนี้แสดงว่าคุณมีสิ่งที่เป็นนามธรรม

try {
    $wrapper->getThatDoohickey();
} catch (DoohickeyDisasterException $Exc) {
    echo "The Doohickey is all wrong!";
    echo $Exc->getMessage();
    gotoAHappyPlaceAndSingHappySongs();
}

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

หากในอีกทางหนึ่ง DoohickeyDisasterException เป็นหนึ่งในการสร้างของคุณเองแล้วคุณจะไม่รั่วซึม abstractions คุณควรกังวลตัวเองมากขึ้นกับจุดแรกของฉัน


2

กฎที่ฉันพยายามไปคือ: ห่อถ้าคุณทำให้มัน ในทำนองเดียวกันหากมีข้อผิดพลาดที่จะสร้างขึ้นเนื่องจากข้อยกเว้นรันไทม์มันควรจะเป็นประเภทของ DoHickeyException หรือ MyApplicationException

สิ่งที่บอกเป็นนัยว่าหากสาเหตุของข้อผิดพลาดนั้นเป็นสิ่งที่อยู่นอกรหัสของคุณและคุณไม่ได้คาดหวังว่ามันจะล้มเหลว เช่นเดียวกันหากเป็นปัญหากับรหัสของคุณให้ตัดคำยกเว้นที่กำหนดเอง (อาจ)

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.