วิธีตั้งชื่อเมธอดที่ทั้งสองทำงานและส่งคืนบูลีนเป็นสถานะได้อย่างไร?


33

หากมีวิธีการ

bool DoStuff() {
    try {
        // doing stuff...
        return true;
    }
    catch (SomeSpecificException ex) {
        return false;
    }
}

มันควรจะถูกเรียกว่าค่อนข้างIsStuffDone()?

ผู้ใช้ทั้งสองชื่ออาจตีความผิด: หากชื่อเป็นDoStuff()สาเหตุว่าทำไมจึงส่งคืนบูลีน หากชื่อIsStuffDone()ไม่ชัดเจนว่าวิธีการทำงานหรือตรวจสอบผลของมันเท่านั้น

มีแบบแผนสำหรับกรณีนี้หรือไม่? หรือวิธีการอื่นเป็นวิธีนี้ถือว่ามีข้อบกพร่อง? ยกตัวอย่างเช่นในภาษาที่มีพารามิเตอร์ที่ส่งออกเช่น C # voidตัวแปรสถานะบูลีนอาจจะส่งผ่านไปยังวิธีการที่เป็นหนึ่งและประเภทผลตอบแทนของวิธีการที่จะเป็น

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


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

7
ส่วนใหญ่ฉันจะเรียกมันว่า "เสีย" เนื่องจากคืนค่าการbooleanแทนที่หรือตัดผ่านข้อยกเว้นมักจะผิดเสมอ
maaartinus

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

2
อืมม ... BadlyDesignedMethodInSeriousNeedOfRefactoring? และเพื่อตอบคำถามของคุณเกี่ยวกับข้อยกเว้น - ฉันจะให้ผู้โทรจัดการหรือจับพวกเขาแล้วโยนข้อยกเว้นที่กำหนดเองซึ่งหมายความว่า "วิธีนี้ไม่มีงาน" แบ่งปันและเพลิดเพลิน
Bob Jarvis - Reinstate Monica

5
สำหรับทุกคนที่พูดว่า: เพียงแค่โยน (หรือให้ผ่าน) ข้อยกเว้นคุณกำลังทำข้อสันนิษฐานที่ไม่มีมูลความจริงเกี่ยวกับวิธีการใช้รหัสนี้ สถานการณ์หนึ่งที่เป็นไปได้คือมีปัญหาที่ต้องแก้ไขด้วยวิธีการแก้ปัญหาต่าง ๆ ที่แก้ปัญหา subclasses ที่ใหญ่กว่าของปัญหาด้วยต้นทุนที่เพิ่มขึ้น if (FirstMethodSucceeds(problem) or SecondMethodSucceeds(problem) or ...) Hurray(); else UniversalSolve(problem);มันจะทำให้ความรู้สึกที่จะเขียนสิ่งที่ต้องการ การทำเช่นเดียวกันกับข้อยกเว้น (กำหนดเอง) จะซับซ้อนกว่าอย่างไร้ประโยชน์
Marc van Leeuwen

คำตอบ:


68

ใน. NET คุณมักจะมีคู่ของวิธีที่หนึ่งในนั้นอาจจะมีข้อยกเว้น ( DoStuff) และอื่น ๆ กลับสถานะบูลีนและในการดำเนินการที่ประสบความสำเร็จผลลัพธ์ที่แท้จริงผ่านพารามิเตอร์ออก ( TryDoStuff)

(Microsoft เรียกสิ่งนี้ว่า"รูปแบบการลองแยกวิเคราะห์"เนื่องจากอาจเป็นตัวอย่างที่เด่นชัดที่สุดสำหรับTryParseวิธีนี้คือวิธีการต่างๆในรูปแบบดั้งเดิม)

หากTryคำนำหน้าเป็นเรื่องแปลกในภาษาของคุณคุณอาจไม่ควรใช้มัน


3
+1 นี่คือวิธีที่ฉันได้เห็นสิ่งต่าง ๆ ที่ทำในที่อื่น if (TryDoStuff()) print("Did stuff"); else print("Could not do stuff");เป็นสำนวนที่ค่อนข้างมาตรฐานและใช้งานง่ายในความคิดของฉัน
Karl Nicoll

12
ควรสังเกตว่าTryDoStuffวิธีการนั้นถือว่าล้มเหลวหมดจดและไม่มีผลข้างเคียงเมื่อพวกเขากลับมาเป็นเท็จ
Trillian

FYI นอกจากนี้ยังมีRemoveวิธีการเช่นในกรอบ NET ที่จะลบองค์ประกอบจากโครงสร้างข้อมูล (เช่นDictionary) boolและส่งกลับ ผู้บริโภคของ API สามารถตัดสินใจที่จะบริโภคหรือเพิกเฉยได้ อย่างไรก็ตามข้อผิดพลาดจะถูกรายงานเป็นข้อยกเว้น
โอเมอิกอิกบัล

18

เกิดอะไรขึ้นถ้าคุณเพียงโยนข้อยกเว้นรหัสการโทร

วิธีนี้คุณจะมอบหมายการจัดการข้อยกเว้นให้กับผู้ที่เคยใช้รหัสของคุณ ถ้าในอนาคตคุณต้องการทำสิ่งต่อไปนี้:

  • หากไม่มีข้อยกเว้นให้ดำเนินการ A
  • ถ้า (ตัวอย่าง) a FileNotFoundExceptionถูกโยนให้ดำเนินการ B
  • หากมีข้อผิดพลาดอื่นใดให้ดำเนินการ C

ถ้าคุณโยนกลับข้อยกเว้นของการเปลี่ยนแปลงข้างต้นจะเพียงแค่นำมาซึ่งการเพิ่มพิเศษcatchบล็อก หากคุณปล่อยให้เป็นเช่นนี้คุณจะต้องเปลี่ยนวิธีการและสถานที่ที่วิธีการที่เรียกว่าซึ่งขึ้นอยู่กับความซับซ้อนของโครงการสามารถอยู่ในหลายสถานที่


1
จะเกิดอะไรขึ้นถ้าข้อยกเว้นนั้นเป็นประเภทที่ไม่สามารถมอบหมายได้และควรจัดการภายใน
Limbo Exile

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

6
มันอาจจะแบกมูลค่าในใจว่าการขว้างปายกเว้นควรจะเป็นสำหรับกรณีพิเศษ หากเป็นเรื่องปกติหรือปกติสำหรับDoStuffการล้มเหลวการโยนข้อยกเว้นสำหรับกรณีความล้มเหลวจะคล้ายกับการควบคุมการไหลของโปรแกรมโดยมีข้อยกเว้นที่ไม่ดี ข้อยกเว้นยังมีค่าประสิทธิภาพโดยธรรมชาติ หากDoStuffความล้มเหลวเป็นกรณีที่ผิดปกติเนื่องจากข้อผิดพลาดดังนั้นข้อยกเว้นเป็นวิธีที่แน่นอนตามที่ @npinti แนะนำ
Karl Nicoll

1
@KarlNicoll ไม่ว่าจะเป็น "พิเศษ" สิ่งที่เป็นอัตนัยอย่างสมบูรณ์ เกณฑ์หลักควรเป็นว่าคุณต้องการให้โปรแกรมหยุดทำงานหรือไม่หากไม่มีใครทำอะไรเกี่ยวกับข้อผิดพลาดหรือไม่และคุณต้องการให้มีข้อผิดพลาดเกิดขึ้นในประเภทของฟังก์ชันหรือไม่ นอกจากนี้ไม่ใช่ความจริงที่ว่าข้อยกเว้นมีราคาแพง ขึ้นอยู่กับภาษาและวิธีการโยน ข้อยกเว้นนั้นมีราคาถูกใน Python และถ้าคุณดึงข้อมูลการติดตามสแต็กออกมาพวกมันก็จะถูกใน Java เช่นกัน แม้ว่าจะมีค่าใช้จ่ายด้านประสิทธิภาพ แต่เป็นการเพิ่มประสิทธิภาพก่อนวัยอันควรที่จะต้องกังวลจนกว่าคุณจะทำประวัติ
Doval

1
@Doval - ฉันยอมรับว่ามันเป็นอัตนัยซึ่งเป็นเหตุผลที่ OP ไม่ควรลดคำตอบของ npinti ทั้งหมดเพราะมันอาจเป็นแนวทางที่ดีที่สุด ประเด็นของฉันคือการโยนข้อยกเว้นไม่ใช่เส้นทางที่ดีที่สุดเสมอไป มีหลายกรณีที่ความล้มเหลวไม่ได้แสดงให้เห็นถึงการขว้างข้อยกเว้นและอาจทำให้แอปพลิเคชันหยุดทำงาน ตัวอย่างเช่นถ้าDoStuff()วิธีของ OP ล้างขึ้นหลังจากโค้ดภายในส่งข้อยกเว้นและโพสต์เงื่อนไขของวิธีการยังคงถูกต้องรหัสส่งคืนอาจเป็นตัวเลือกที่ดีกว่าเนื่องจากข้อผิดพลาดได้รับการจัดการ
Karl Nicoll

7

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

PHP

// this method update and return the number affected rows 
// called update instead of updateAndGetAffectedCount
$affected = $query->update(/* values */);

C-Sharp

// Remove item from the List
// returns true if item is successfully removed; otherwise, false.
public bool Remove( T item )

6

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

ที่กล่าวว่าหากคุณเพิ่มรายการที่ไม่ได้รับอนุญาตจากคอลเลกชันเช่นค่า null การเพิ่มจะส่งNullPointerExceptionกลับแทนที่จะส่งกลับเท็จ

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


1

อาจล้มเหลวด้วยเหตุผลที่แตกต่างกันยกเว้นเงื่อนไขปกติดังนั้นจะใช้สิ่งนี้:

boolean doStuff() - returns true when successful

สิ่งสำคัญคือการจัดทำเอกสารความหมายของบูลีน


1

ฉันมักจะมีวิธีการคืนOperationResult(หรือOperationResult<T>) และตั้งค่าIsSuccessคุณสมบัติในOperationResultอย่างเหมาะสม หากวิธีการ 'ปกติ' เป็นโมฆะแล้วกลับมาOperationResultถ้าวิธีการ 'ปกติ' ส่งกลับวัตถุแล้วกลับมาOperationResult<T>และตั้งค่าItemคุณสมบัติที่OperationResultเหมาะสม ฉันยังแนะนำให้มีวิธีการในการOperationResultเช่นและ.Failed(string reason) กลายเป็นประเภทที่คุ้นเคยในระบบของคุณอย่างรวดเร็วและนักพัฒนารู้จักวิธีจัดการกับมัน.Succeeded(T item)OperationResult


0

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

ตัวอย่างเช่นในภาษา Objective-C และชื่อวิธีการ iOS / Mac OS X SDK มักจะไปตามบรรทัดของ:

- (returndatatype) viewDidLoad {
- (returndatatype) isVisible {
- (returndatatype) appendMessage:datatype variablename with:datatype variablename {

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

ใน PHP mysql_connect () จะคืนค่าเท็จหากการเชื่อมต่อล้มเหลว มันไม่ได้บอกว่ามันจะทำ แต่มันทำและเอกสารนั้นบอกว่าทำมันดังนั้นจึงไม่สามารถตีความโปรแกรมเมอร์ได้อย่างผิด ๆ


อ่า แต่ viewDidLoad เป็นมากกว่าการแจ้งเตือนการโทรกลับ ผู้ใช้ไม่เรียกมันว่าจะโหลดมุมมอง แต่จะเรียกว่าหลังจากโหลดมุมมองแล้ว ในทำนองเดียวกัน: isVisible ไม่ได้ตั้งค่าการมองเห็น แต่เพียงแค่คืนค่าปัจจุบัน มันไม่ได้ทำอะไรเลย
lilbyrdie

0

ฉันอยากจะแนะนำให้ใช้คำนำหน้า 'ลอง' นี่เป็นรูปแบบที่รู้จักกันดีสำหรับสถานการณ์ที่วิธีการนั้นอาจสำเร็จหรือไม่ รูปแบบการตั้งชื่อนี้ถูกใช้โดย Microsoft ใน. NET Framework (ตัวอย่างเช่น TryParseInt)

แต่นี่อาจไม่เกี่ยวกับการตั้งชื่อ มันเกี่ยวกับวิธีที่คุณออกแบบพารามิเตอร์อินพุต / เอาต์พุตของวิธีการ

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

ใน C # ฉันต้องการใช้พารามิเตอร์ out ใช้ out ฉันกำลังทำเครื่องหมายพารามิเตอร์เป็นพารามิเตอร์ด้านข้าง พิเศษที่ C # 6 จะสนับสนุนการประกาศตัวแปรแบบอินไลน์

DoStuff(out var isStuffDone); // The out parameter name clearly states its purpose.
DoStuff(out var _); // I use _ for naming parameters that I am ignoring.

0

ฉันจะเลือกชื่อตามบทบาทหลักของวิธีการ ความจริงแล้วเมธอดนั้นส่งคืนค่าบูลีนนั้นไม่ได้บังคับใช้คำนำหน้า 'Is' มามีโค้ด Java บางตัวที่ใช้คำนำหน้า 'Is' ค่อนข้างมาก java.io.File.delete()ลองดูที่ ก็จะส่งกลับแต่มันไม่ได้เรียกว่าboolean isFileDeleted()เหตุผลคือบทบาทหลักของ metod คือการลบไฟล์ บางคนเรียกวิธีนี้โดยมีเจตนาที่จะลบไฟล์

บูลีนมีเพียงเพื่อแจ้งผลการทำงานกลับคืนมา ในทางกลับกันเรามาดูjava.util.Map.isEmpty()กัน เห็นได้ชัดว่าคุณเรียกวิธีการดังกล่าวเพื่อดูว่าคอลเลกชันว่างเปล่า คุณไม่ต้องการให้มีสิ่งใดทำ คุณเพียงแค่ต้องการทราบว่าสถานะปัจจุบันคืออะไร

DoStuff()ดังนั้นส่วนตัวผมจะติดกับ definitelly

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

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