เราควรเปลี่ยนชื่อเมธอดที่โอเวอร์โหลดหรือไม่?


14

สมมติว่าอินเตอร์เฟสมีวิธีการเหล่านี้:

Car find(long id);

List<Car> find(String model);

จะเป็นการดีกว่าถ้าจะเปลี่ยนชื่อพวกเขาเช่นนี้?

Car findById(long id);

List findByModel(String model);

อันที่จริงนักพัฒนาซอฟต์แวร์ใด ๆ ที่ใช้ API นี้ไม่จำเป็นต้องดูที่อินเทอร์เฟซเพื่อรับทราบข้อโต้แย้งที่เป็นไปได้ของfind()วิธีการเริ่มต้น

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


4
วิธีใดวิธีหนึ่งเป็นที่ยอมรับตราบใดที่คุณมีความสอดคล้องกัน
ChrisF

มีความสัมพันธ์ระหว่างการบรรทุกเกินพิกัดและวิธีการเอาชนะ อย่างไรก็ตามบทความนี้สนับสนุนข้อเสนอแนะของคุณ - อาจเป็นที่สนใจ: roseindia.net/javatutorials/ ......
NoChance

คำตอบ:


23

นี่เป็นปัญหาที่ค่อนข้างน้อยเมื่อเทียบกับวิธีปฏิบัติในการอ่านที่ไม่ดีอื่น ๆ อีกมากมายที่คุณอาจไวต่อดังนั้นฉันจะบอกว่ามันเป็นเรื่องของรสนิยมที่คุณตั้งชื่อวิธีการของคุณเป็นส่วนใหญ่

ด้วยที่กล่าวว่าหากคุณจะทำอะไรเกี่ยวกับเรื่องนี้ฉันจะปฏิบัติตามการปฏิบัตินี้:

  • เกินพิกัดถ้า ...

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

  • ใช้ชื่ออื่นถ้า ...

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

    นอกจากนี้หากประเภทที่ส่งคืนแตกต่างกันฉันจะเปลี่ยนคำกริยาเพื่อระบุว่า:

    Car findById(long id);
    
    List findAllByModel(String model);
    

3
FWIW ผมจะคำว่าเล็ก ๆ น้อย ๆ มากขึ้นอย่างมาก: "วิธีการเชื่อฟังว่าสัญญาเดียวกัน ..." เช่นประเภทอาร์กิวเมนต์ / นับไม่สำคัญ - ความหมายของการเรียกฟังก์ชั่นที่มีความเหมือนกันโดยไม่คำนึงถึง หากอาร์กิวเมนต์ประเภท / การนับมีความสำคัญคุณก็ไม่ควรโหลดมากเกินไป
mcmcc

4

ฉันขอแนะนำให้ใช้ชื่ออื่นในทุกกรณี มันเป็นไปได้ว่าในช่วงเวลาบางอย่างในอนาคตคุณจะต้องการที่จะเพิ่มวิธีการอื่นบอกว่าในทางตรงกันข้ามกับList<Car> findByMake(String make) List<Car> findByModel(String model)ทันใดนั้นการเรียกทุกอย่างก็findไม่สมเหตุสมผล วิธีการของคุณมีโอกาสน้อยที่จะใช้อย่างไม่ถูกต้องโดยไม่ตั้งใจหากชื่อของพวกเขาให้ข้อมูลเพิ่มเติมว่าควรใช้อย่างไร


1
เพื่อความเป็นธรรมนี้จะไม่มากเท่าที่ปัญหาถ้าทำงานเป็นตัวแทนมากขึ้นอย่างชัดเจนโดยวัตถุ: และfind(Make val) find(Model val)จากนั้นวิธีการอำนวยความสะดวกเช่นfindByMake(String val)จะมีความชัดเจนมากขึ้นว่าพวกเขากำลังทำอะไรอยู่ Stringท้ายที่สุดแล้ว a ไม่ใช่ทั้งยี่ห้อหรือรุ่นดังนั้นวิธีการควรอธิบายว่ามันทำอะไรอยู่
Nicole

4

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

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

ดังนั้นการทำสิ่งนี้:

void MyMethod(int param1, int param2 = 10)
{
    ...
}

ช่วยคุณไม่ให้ทำสิ่งนี้:

void MyMethod(int param1)
{
    MyMethod(param1, Param2Default);
}

void MyMethod(int param1, int param2)
{
    ....
}

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

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

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

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


0

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

สมมติว่าฟังก์ชั่นการโทรได้รับการค้นหาเป็นพารามิเตอร์และดำเนินการประมวลผลอื่น ๆ บางอย่างก่อนและ / findหรือหลังการเรียกร้องให้

void tryToSellCars(String which) {
    /* grab an airhorn, inflatable tube guy... */
    List<Car> cars = find(which);
    /* expound virtues of each car in detail... */
}

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

void tryToSellCar(CarQuery which) {
    /* grab airhorn, inflate tube guy... */
    List<Car> cars = find(which)
    /* expound virtues of each car in detail... */
}

หากคุณใช้งานfindByIdและfindByQueryObjectแยกกันคุณจะต้องตามล่าทุกการโทรเพื่อทำการเปลี่ยนแปลง ในตัวอย่างฉันเปลี่ยนเพียงหนึ่งคำและฉันก็ทำเสร็จแล้ว


คำตอบนี้ถือว่าแน่นอนว่าคุณกำลังใช้ภาษาที่รองรับการโหลดมากเกินไปพร้อมกับข้อผิดพลาดในการคอมไพล์สำหรับพารามิเตอร์ที่ไม่ถูกต้อง หากคุณกำลังเขียน JavaScript หรือ Ruby หรือภาษาอื่น ๆ ที่ไม่สนับสนุนการโหลดมากเกินไปฉันจะใช้ verbose findByFooเพื่อตรวจจับการจับคู่ประเภทที่ไม่ตรงกันก่อนหน้านี้เสมอ
sqykly
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.