มันเพียงพอสำหรับวิธีการที่จะโดดเด่นเพียงแค่ชื่ออาร์กิวเมนต์ (ไม่พิมพ์)?


36

มันเพียงพอสำหรับวิธีการที่จะโดดเด่นเพียงแค่ชื่ออาร์กิวเมนต์ (ไม่พิมพ์) หรือมันจะดีกว่าที่จะตั้งชื่ออย่างชัดเจนมากขึ้น?

ยกตัวอย่างเช่นVST Find<T>(int id)T FindById<T>(int id)

มีเหตุผลที่ดีที่จะตั้งชื่ออย่างชัดเจนยิ่งขึ้น (เช่นการเพิ่มById) และการเก็บชื่ออาร์กิวเมนต์เพียงอย่างเดียวหรือไม่

เหตุผลหนึ่งที่ฉันคิดได้ก็คือเมื่อลายเซ็นของวิธีการเหมือนกัน แต่มีความหมายแตกต่างกัน

FindByFirstName(string name) และ FindByLastName(string name)


4
ดังนั้นเมื่อคุณค้นหาเกินพิกัดเพื่อรวมT Find<T>(string name)หรือ(int size)คุณวางแผนที่จะแก้ไขปัญหาที่หลีกเลี่ยงไม่ได้อย่างไร
UKMonkey

3
@ สหราชอาณาจักรกุญแจปัญหาอะไรที่หลีกเลี่ยงไม่ได้?
Konrad

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

2
@UKMonkey คุณสามารถโพสต์คำตอบกับตัวอย่างรหัสบางอย่างถ้าคุณต้องการ
คอนราด

3
หมายเลขอาจจะเป็นสีขาวขุ่นวัตถุและไม่ได้เป็นเพียงID intในวิธีนั้นรับการตรวจสอบเวลาคอมไพล์ที่คุณไม่ได้ใช้ id สำหรับ int หรือ viceversa ในบางส่วนของรหัสของคุณ และด้วยสิ่งที่คุณสามารถมีfind(int value)และfind(ID id).
Bakuriu

คำตอบ:


68

แน่นอนว่ามีเหตุผลที่ดีในการตั้งชื่อให้ชัดเจนยิ่งขึ้น

มันไม่ได้เป็นส่วนใหญ่จะเป็นวิธีการที่ความหมายที่ควรจะเป็นตัวอธิบาย แต่วิธีการใช้งาน และในขณะที่findById(string id)และfind(string id)มีทั้งอธิบายตนเองมีความแตกต่างกันมากระหว่างและfindById("BOB") find("BOB")ในกรณีก่อนหน้านี้คุณรู้ว่าตัวอักษรแบบสุ่มในความเป็นจริงแล้วเป็นรหัส ในกรณีหลังคุณไม่แน่ใจ - อาจเป็นชื่อจริงหรืออย่างอื่นโดยสิ้นเชิง


9
ยกเว้นใน 99% ของกรณีอื่น ๆ ที่คุณมีตัวแปรหรือคุณสมบัติชื่อเป็นจุดอ้างอิง: VSfindById(id) find(id)คุณสามารถไปทางนี้
เกร็ก Burghardt

16
@GregBurghardt: ค่าเฉพาะไม่จำเป็นต้องตั้งชื่อในลักษณะเดียวกันสำหรับวิธีการและผู้เรียก ตัวอย่างเช่นพิจารณาการใช้ในวิธีการ:double Divide(int numerator, int denominator) double murdersPerCapita = Divide(murderCount, citizenCount)คุณไม่สามารถพึ่งพาสองวิธีโดยใช้ชื่อตัวแปรเดียวกันเนื่องจากมีหลายกรณีที่ไม่ใช่กรณี (หรือเมื่อเป็นกรณีมันตั้งชื่อไม่ดี)
Flater

1
@Flater: ได้รับรหัสในคำถาม (การค้นหาสิ่งต่าง ๆ จากการจัดเก็บแบบถาวร) ฉันคิดว่าคุณอาจจะเรียกวิธีการนี้ด้วย "killedCitizenId" หรือ "พลเมืองรหัส" ... ฉันไม่คิดว่าอาร์กิวเมนต์หรือชื่อตัวแปรเป็น ไม่ชัดเจนที่นี่ และฉันก็สามารถไปทางนี้ได้ จริงๆแล้วมันเป็นคำถามที่ให้ความเห็นอย่างมาก
เกร็ก Burghardt

4
@GregBurghardt: คุณไม่สามารถกลั่นกฎสากลจากตัวอย่างเดียว คำถามของ OP นั้นโดยทั่วไปไม่ใช่เฉพาะตัวอย่างที่ให้มา ใช่มีบางกรณีที่ใช้ชื่อเดียวกันนั้นสมเหตุสมผล แต่ก็มีบางกรณีที่ไม่ใช้ ดังนั้นคำตอบนี้ดีที่สุดที่จะตั้งเป้าหมายเพื่อความมั่นคงแม้ว่ามันจะไม่จำเป็นในชุดย่อยของกรณีการใช้งาน
Flater

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

36

ข้อดีของการ FindById ()

  1. อนาคตพิสูจน์อักษร : ถ้าคุณเริ่มต้นด้วยFind(int)และต่อมามีการเพิ่มวิธีการอื่น ๆ ( FindByName(string), FindByLegacyId(int), FindByCustomerId(int), FindByOrderId(int)ฯลฯ ) FindById(int)คนอย่างผมมักจะใช้ทุกเพศทุกวัยที่กำลังมองหา ไม่ใช่ปัญหาหากคุณสามารถและจะเปลี่ยนFind(int)เป็นFindById(int)เมื่อจำเป็น - การพิสูจน์ในอนาคตเกี่ยวกับสิ่งเหล่านี้ถ้า s

  2. ให้อ่านง่ายขึ้น Findเป็นอย่างดีดีถ้าโทรลักษณะชอบrecord = Find(customerId);แต่จะง่ายขึ้นเล็กน้อยสำหรับการอ่านถ้ามันFindByIdrecord = FindById(AFunction());

  3. ความมั่นคง คุณสามารถใช้FindByX(int)/ FindByY(int)รูปแบบได้อย่างสม่ำเสมอทุกที่ แต่Find(int X)/ Find(int Y)เป็นไปไม่ได้เพราะขัดกัน

ข้อดีของการค้นหา ()

  • จูบ. Findเรียบง่ายและตรงไปตรงมาและอยู่ข้างoperator[]หนึ่งในสองชื่อฟังก์ชันที่คาดหวังมากที่สุดในบริบทนี้ (บางทางเลือกที่ได้รับความนิยมเป็นget, lookupหรือfetchขึ้นอยู่กับบริบท)
  • ตามกฎของหัวแม่มือหากคุณมีชื่อฟังก์ชั่นซึ่งเป็นคำที่รู้จักกันดีซึ่งอธิบายถึงสิ่งที่ฟังก์ชันใช้อย่างถูกต้อง แม้ว่าจะมีชื่อหลายคำที่ยาวกว่าซึ่งดีกว่าเล็กน้อยในการอธิบายสิ่งที่ฟังก์ชั่นทำ ตัวอย่าง: ความยาว VS NumberOfElements มีการแลกเปลี่ยนกันและตำแหน่งที่จะลากเส้นนั้นเป็นเรื่องของการถกเถียง
  • เป็นเรื่องปกติที่จะหลีกเลี่ยงความซ้ำซ้อน ถ้าเราดูFindById(int id)เราสามารถลบความซ้ำซ้อนได้อย่างง่ายดายโดยเปลี่ยนเป็นFind(int id)แต่มีการแลกเปลี่ยน - เราสูญเสียความชัดเจน

หรือคุณจะได้รับประโยชน์จากทั้งคู่โดยใช้รหัสที่พิมพ์อย่างมาก:

CustomerRecord Find(Id<Customer> id) 
// Or, depending on local coding standards
CustomerRecord Find(CustomerId id) 

การติดตั้งใช้งานId<>: พิมพ์ค่า ID อย่างมากใน C #

ความคิดเห็นที่นี่รวมทั้งในลิงก์ด้านบนทำให้เกิดข้อกังวลหลายประการเกี่ยวกับการId<Customer>ที่ฉันต้องการจะกล่าวถึง:

  • ข้อกังวลที่ 1: เป็นการใช้ชื่อสามัญอย่างไม่เหมาะสม CustomerIdและOrderIDเป็นประเภทที่แตกต่างกัน ( customerId1 = customerId2;=> ดี, customerId1 = orderId1;=> ไม่ดี) แต่การใช้งานของพวกเขาเกือบจะเหมือนกันดังนั้นเราจึงสามารถนำไปใช้งานได้ด้วยการคัดลอกหรือวาง ในขณะที่มีค่าในการอภิปรายเกี่ยวกับการเปิดเผยหรือซ่อนทั่วไป metaprogramming เป็นสิ่งที่ generics มีไว้สำหรับ
  • ความกังวลที่ 2: มันไม่ได้หยุด mistakes./It's ง่ายวิธีการแก้ปัญหาในการค้นหาของปัญหาDoSomething(int customerId, int orderId, int productId)ปัญหาหลักที่ถูกลบออกโดยใช้ขอพิมพ์รหัสเป็นคำสั่งอาร์กิวเมนต์ไม่ถูกต้องในการเรียกไปยัง รหัสที่พิมพ์อย่างมากยังป้องกันปัญหาอื่น ๆ รวมถึง OP ที่ถามด้วย
  • ข้อกังวลที่ 3: มันเป็นการปิดบังรหัสจริงๆ เป็นการยากที่จะบอกว่ามี ID อยู่int aVariableหรือไม่ ง่ายที่จะบอกว่ามีการถือครองรหัสId<Customer> aVariableและเราสามารถบอกได้ว่าเป็นรหัสลูกค้า
  • ข้อกังวลที่ 4: รหัสเหล่านี้ไม่มีประเภทที่แข็งแกร่งเพียงแค่ห่อหุ้ม เป็นเพียงเสื้อคลุมรอบString byte[]การห่อหุ้มหรือการห่อหุ้มไม่ได้ขัดแย้งกับการพิมพ์ที่รัดกุม
  • ข้อกังวลที่ 5: มันผ่านการออกแบบมา ต่อไปนี้เป็นรุ่นที่น้อยที่สุด แต่ฉันขอแนะนำให้เพิ่มoperator==และoperator!=เช่นกันถ้าคุณไม่ต้องการพึ่งพาเฉพาะในEquals:

.

public struct Id<T>: {
    private readonly int _value ;
    public Id(int value) { _value = value; }
    public static explicit operator int(Id<T> id) { return id._value; }
}

10

วิธีคิดอีกอย่างคือการใช้ความปลอดภัยของภาษา

คุณสามารถใช้วิธีการเช่น:

Find(FirstName name);

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


4
ไม่แน่ใจว่าคำตอบของคุณสำหรับคำถาม OPs คืออะไร คุณแนะนำให้ใช้ชื่อเช่น "ค้นหา" โดยอาศัยประเภทของการโต้แย้งหรือไม่? หรือคุณแนะนำให้ใช้ชื่อดังกล่าวเฉพาะเมื่อมีประเภทที่ชัดเจนสำหรับการโต้แย้งและใช้ชื่อที่ชัดเจนยิ่งขึ้นเช่น "FindById" ที่อื่น? หรือคุณแนะนำให้แนะนำประเภทที่ชัดเจนเพื่อสร้างชื่อเช่น "Find" เป็นไปได้มากขึ้น?
Doc Brown

2
@DocBrown ฉันคิดว่าหลังและฉันชอบมัน จริงๆแล้วมันคล้ายกับคำตอบของปีเตอร์ iiuc เหตุผลที่ฉันเข้าใจมันเป็นสองเท่า: (1) มันชัดเจนจากประเภทอาร์กิวเมนต์สิ่งที่ฟังก์ชั่น; (2) คุณไม่สามารถทำผิดพลาดได้string name = "Smith"; findById(name);ซึ่งเป็นไปได้ถ้าคุณใช้ประเภททั่วไปที่ไม่ใช่คำอธิบาย
Peter - Reinstate Monica

5
ในขณะที่โดยทั่วไปฉันเป็นแฟนของความปลอดภัยประเภทเวลารวบรวมระวังประเภทเสื้อคลุม การแนะนำคลาสของ wrapper เพื่อความปลอดภัยของประเภทอาจทำให้ API ของคุณซับซ้อนหากทำเกินความจำเป็น เช่นปัญหา "ศิลปินที่รู้จักกันในชื่อ int" ทั้งหมดที่ winapi มี; ในระยะยาวฉันจะบอกว่าคนส่วนใหญ่เพียงแค่มองไปที่ไม่มีที่สิ้นสุดDWORD LPCSTRโคลน ฯลฯ และคิดว่า "มันเป็น int / string / ฯลฯ " มันถึงจุดที่คุณใช้เวลามากขึ้นในการเตรียมเครื่องมือของคุณมากกว่าที่คุณจะออกแบบรหัส .
jrh

1
@jrh True การทดสอบสารสีน้ำเงินของฉันสำหรับการแนะนำประเภท "เล็กน้อย" (ต่างกันในชื่อเท่านั้น) คือเมื่อฟังก์ชั่น / วิธีการทั่วไปไม่สมเหตุสมผลในกรณีที่เราใช้งานเช่นints มักจะถูกสรุปคูณและอื่น ๆ ซึ่งไม่มีความหมายสำหรับ ID; ดังนั้นผมจึงต้องการให้แตกต่างไปจากID intสิ่งนี้สามารถลดความซับซ้อนของ API โดยการ จำกัด สิ่งที่เราสามารถกำหนดค่าได้ (เช่นหากเรามีIDมันจะใช้ได้กับfindไม่ใช่เท่านั้นageหรือhighscore) ในทางกลับกันถ้าเราพบว่าตัวเองเปลี่ยนแปลงมากหรือเขียนฟังก์ชั่น / วิธีการเดียวกัน (เช่นfind) สำหรับหลายประเภทนั่นเป็นสัญญาณว่าความแตกต่างของเราดีเกินไป
Warbo

1

ฉันจะลงคะแนนเพื่อการประกาศอย่างชัดเจนเช่น FindByID .... ซอฟต์แวร์ควรได้รับการสร้างขึ้นเพื่อการเปลี่ยนแปลง ควรจะเปิดและปิด (SOLID) ดังนั้นคลาสจึงเปิดเพื่อเพิ่มวิธีการค้นหาที่คล้ายกันเช่นสมมติว่า FindByName .. เป็นต้น

แต่ FindByID ถูกปิดและการใช้งานนั้นถูกทดสอบหน่วย

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


0

ฉันประหลาดใจที่ไม่มีใครแนะนำให้ใช้คำกริยาดังต่อไปนี้:

User Find(Predicate<User> predicate)

ด้วยวิธีนี้ไม่เพียง แต่คุณจะลดพื้นผิวของ API ของคุณ แต่ยังให้การควบคุมแก่ผู้ใช้มากขึ้น

หากนั่นยังไม่เพียงพอคุณสามารถขยายความต้องการของคุณได้เสมอ


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