คุณสร้างการโต้แย้งหรือการโต้แย้งจากวิธีส่วนตัวหรือไม่?


20

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

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

ฉันรู้สึกว่าข้อยกเว้นเหล่านี้โดยทั่วไปมีประโยชน์มากกว่าในบางสิ่งบางอย่างเช่น API ที่จะเปิดเผยต่อสาธารณะ

คำตอบ:


22

โดยปกติแล้วสำหรับวิธีการส่วนตัวคุณจะไม่โยนข้อยกเว้นเนื่องจากในขณะที่คุณเขียนมันนักพัฒนาควรจะรู้วิธีและวิธีที่เขาจะเรียกวิธีการจาก ดังนั้นตัวแปรที่ส่งผ่านเป็นพารามิเตอร์ไปยังเมธอดไพรเวตควรถูกตรวจสอบภายนอกเมธอดนั่นคือก่อนที่จะเรียกมัน การขว้าง "InvalidArgumentException" และข้อยกเว้นอื่น ๆ นั้นถือเป็นแนวปฏิบัติที่ดีสำหรับวิธีสาธารณะ (ไม่ว่าคุณจะเขียน "API" หรือไม่ก็ตาม)

สำหรับกรณีที่คุณต้องการ "InvalidArgumentException" มีค่าควรแก่การกล่าวถึงว่ามีAssertคลาสใน Spring API สำหรับ Java ตั้งแต่รุ่น 1.1.2 เป็นประโยชน์อย่างมากสำหรับฉันอย่างน้อยในการเขียนรหัสน้อยลงเพื่อทำการตรวจสอบ

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

นี่คือวิธีใช้การยืนยันใน:


1
Apache Commons ยังมีคลาส Validate ที่ทำหน้าที่คล้ายกับคลาส Assert ของ Spring
Rosa Richter

@cantido ใช่และฉันจะเพิ่มว่าชั้น Preconditions ใน Guava ของ Google ซึ่งทำงานในลักษณะเดียวกัน ขอบคุณสำหรับข้อมูล :-)
Jalayn

2

เหมือนทุกอย่างอื่นมันขึ้นอยู่กับ ....

หากวิธีการสาธารณะเป็น wrappers ง่ายที่เรียกว่าวิธีการส่วนตัว (ตามเส้นของวิธีการโอเวอร์โหลดส่วนตัว) ก็อาจทำให้เกิดข้อยกเว้นในวิธีการส่วนตัวแทนการตรวจสอบในแต่ละสาธารณะ

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


2

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

มีสามสิ่งที่โปรแกรมเมอร์ C ++ มักสนใจ:

  • มันจะมีค่าใช้จ่ายเป็นศูนย์ในการสร้างที่ปรับให้เหมาะสมหรือไม่? (นั่นคือมันสามารถ "รวบรวม" หรือไม่)
  • ฉันสามารถใช้มันเพื่อดักจับตัวดีบั๊กที่จุดที่ตรวจพบข้อผิดพลาดได้หรือไม่?
  • ฉันสามารถใช้มันเพื่อรายงานปัญหาจากฟังก์ชั่นที่ประกาศได้noexceptหรือไม่?

ในอดีตฉันได้เข้าหาปัญหาแรกโดยการเขียนโค้ดแบบนี้

int
factorial(const int n)
{
  if (CHECK_ARGS)
    {
      if (n < 0)
        throw std::invalid_argument {"n < 0"};
    }
  int fac = 1;
  for (int i = 2; i <= n; ++i)
    fac *= i;
  return fac;
}

ซึ่งCHECK_ARGSเป็น#defineวันที่จะคงที่เวลารวบรวมเพื่อเรียบเรียงสมบูรณ์อาจขจัดข้อโต้แย้งรหัสการตรวจสอบทั้งหมดในการเพิ่มประสิทธิภาพสร้าง (ฉันไม่ได้บอกว่าการรวบรวมเช็คเอาท์เป็นสิ่งที่ดีโดยทั่วไป แต่ฉันเชื่อว่าผู้ใช้ควรมีตัวเลือกในการรวบรวมพวกเขาออก)

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

เพิ่มมาตรฐานการเข้ารหัสเห็นด้วยกับเรื่องนี้:

ข้อผิดพลาดของโปรแกรมเมอร์คืออะไร

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

มีการพูดคุยที่น่าสนใจมากที่ John Lakos มอบให้ที่CppCon'14หัวข้อการเขียนโปรแกรมการป้องกัน Done Right ( ตอนที่ 1 , ตอนที่ 2 ) ในส่วนแรกของการพูดคุยของเขาเขากล่าวถึงทฤษฎีสัญญาและพฤติกรรมที่ไม่ได้กำหนด ในส่วนที่สองเขานำเสนอสิ่งที่ฉันพิจารณาข้อเสนอที่ดีมากสำหรับการตรวจสอบการโต้แย้งอย่างเป็นระบบ ในสาระสำคัญเขาเสนอมาโครการยืนยันที่อนุญาตให้ผู้ใช้เลือกงบประมาณ (ในแง่ของการใช้งาน CPU) เท่าใดเธอยินดีที่จะบริจาคให้กับห้องสมุดเพื่อตรวจสอบการโต้แย้งและห้องสมุดใช้ประโยชน์จากงบประมาณนั้นอย่างชาญฉลาด นอกจากนี้ผู้ใช้ยังสามารถติดตั้งฟังก์ชั่นการจัดการข้อผิดพลาดทั่วโลกที่จะถูกเรียกในกรณีที่ตรวจพบสัญญาที่เสียหาย

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


1

พิจารณาโครงสร้างต่อไปนี้:

  1. ตรรกะภายใน: ฟังก์ชั่นนี้สันนิษฐานว่าจะถูกเรียกด้วยพารามิเตอร์ที่ถูกต้องและใช้เพื่อยืนยันการตรวจสอบเงื่อนไขเบื้องต้น postconditions และ invariants เพื่อตรวจสอบตรรกะภายในของคุณ

  2. อินเตอร์เฟซผู้ใช้เสื้อคลุม: ฟังก์ชันนี้ตัดฟังก์ชั่นภายในและใช้ InvalidArgumentExceptions ในการจัดการค่าผิดและจะบอกให้ผู้ใช้สามารถแก้ไขปัจจัยการผลิตของเขา: Assert(x).hasLength(4);, Assume(y).isAlphanumeric();, Assert(z).isZipCode();, Assume(mailAdress).matchesRegex(regex_MailAdress);, Reject(x).ifEmpty();ฯลฯ

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

  4. wrapper อินเตอร์เฟสบรรทัดคำสั่ง: ฟังก์ชั่นนี้จะหุ้มฟังก์ชั่นภายในและถามอีกครั้งสำหรับอินพุตสุดท้าย

คุณควรใช้ทั้ง - การยืนยันและการยกเว้น - ในวิธีการต่าง ๆ สำหรับงานที่แตกต่างกัน คุณควรแยกตรรกะภายในจากการตรวจสอบพารามิเตอร์ เปรียบเทียบกับการแยกของรุ่นมุมมองตัวควบคุม


0

มีวิธีที่ดีกว่าในการหลีกเลี่ยงการตรวจสอบการอ้างอิงเป็นโมฆะ: ใช้สัญญารหัสหรือกรอบ AOP เพื่อทำการตรวจสอบสำหรับคุณ Google "c # code contract" หรือ "postsharp"


ฉันเดาว่าคำถามของฉันจะขยายไปถึงสัญญารหัสด้วย มีความจำเป็นในการตรวจสอบเงื่อนไขของวิธีการในวิธีส่วนตัว (เช่น. สำหรับการพิสูจน์อักษรในอนาคตหรือหยุดคุณจากการยิงตัวเองด้วยการเดินเท้า)?
Mr Moose
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.