ฉันไม่คิดว่าจะมีคำตอบที่ไม่เชื่อเรื่องภาษาเพราะสิ่งนี้ถือเป็น“ คุณสมบัติ” เป็นคำถามเฉพาะภาษาและสิ่งที่ผู้เรียก“ ทรัพย์สิน” คาดว่าเป็นคำถามเฉพาะภาษาเช่นกัน ฉันคิดว่าวิธีที่มีประโยชน์มากที่สุดในการคิดเกี่ยวกับเรื่องนี้คือการคิดเกี่ยวกับสิ่งที่ดูเหมือนว่าจากมุมมองของผู้โทร
ใน C # คุณสมบัติมีความโดดเด่นในสิ่งที่พวกเขาเป็น (ตามอัตภาพ) ตัวพิมพ์ใหญ่ (เช่นวิธีการ) แต่ขาดวงเล็บ (เช่นตัวแปรอินสแตนซ์สาธารณะ) หากคุณเห็นรหัสต่อไปนี้เอกสารที่หายไปคุณคาดหวังอะไร
var reciprocalHeading = myHeading.Reciprocal;
ในฐานะที่เป็น C # สามเณร แต่ผู้ที่อ่านแนวทางการใช้งานคุณสมบัติของ Microsoft ฉันคาดว่าReciprocal
จะมีสิ่งอื่น ๆ :
- เป็นสมาชิกข้อมูลเชิงตรรกะของ
Heading
ชั้นเรียน
- มีราคาถูกที่จะโทรหาไม่จำเป็นต้องให้ฉันแคชค่า
- ขาดผลข้างเคียงที่สังเกตได้
- สร้างผลลัพธ์เดียวกันหากเรียกสองครั้งติดต่อกัน
- (อาจ) เสนอ
ReciprocalChanged
กิจกรรม
จากสมมติฐานเหล่านี้ (3) และ (4) อาจถูกต้อง (สมมติว่าHeading
เป็นประเภทค่าที่ไม่เปลี่ยนรูปเช่นเดียวกับคำตอบของ Ewan ), (1) เป็นที่ถกเถียงกัน (2) ไม่เป็นที่รู้จัก แต่ยังถกเถียงกันและ (5) ใช้ความหมาย (แม้ว่าสิ่งใดก็ตามที่มีหัวเรื่องควรจะมีHeadingChanged
เหตุการณ์) สิ่งนี้ชี้ให้เห็นว่าใน C # API“ ไม่ได้รับหรือคำนวณส่วนกลับ” ไม่ควรนำมาใช้เป็นคุณสมบัติ แต่โดยเฉพาะอย่างยิ่งหากการคำนวณของราคาถูกและHeading
ไม่เปลี่ยนรูปมันเป็นกรณีของเขตแดน
(โปรดทราบว่าไม่มีข้อกังวลใด ๆ ที่เกี่ยวข้องกับว่าการเรียกคุณสมบัติสร้างอินสแตนซ์ใหม่ไม่ใช่แม้แต่ (2) การสร้างวัตถุใน CLR ทั้งในตัวของมันเองนั้นค่อนข้างถูก)
ใน Java คุณสมบัติเป็นระเบียบวิธีการตั้งชื่อ ถ้าฉันเห็น
Heading reciprocalHeading = myHeading.getReciprocal();
ความคาดหวังของฉันคล้ายกับที่กล่าวมาข้างต้น (หากกำหนดไว้ชัดเจนน้อยกว่า): ฉันคาดว่าการโทรนั้นจะถูก idempotent และไม่มีผลข้างเคียง อย่างไรก็ตามนอกกรอบ JavaBeans แนวคิดของ“ คุณสมบัติ” นั้นไม่ใช่สิ่งที่มีความหมายใน Java และโดยเฉพาะอย่างยิ่งเมื่อพิจารณาคุณสมบัติที่ไม่เปลี่ยนรูปแบบซึ่งไม่สอดคล้องกันตอนนี้setReciprocal()
การgetXXX()
ประชุมค่อนข้างล้าสมัย จากจาวาที่มีประสิทธิภาพรุ่นที่สอง (อายุมากกว่าแปดปีแล้ว):
เมธอดที่ส่งคืนboolean
ฟังก์ชันที่ไม่ใช่ฟังก์ชันหรือคุณลักษณะของวัตถุที่พวกมันถูกเรียกมักจะถูกตั้งชื่อด้วยวลีนามคำนามหรือวลีกริยาที่ขึ้นต้นด้วยกริยาget
… มีแกนนำเสียงร้องที่อ้างว่ามีเพียงรูปแบบที่สาม (เริ่มต้นด้วยget
) เป็นที่ยอมรับ แต่มีพื้นฐานเล็กน้อยสำหรับการเรียกร้องนี้ โดยทั่วไปสองรูปแบบแรกจะนำไปสู่รหัสที่อ่านง่ายขึ้น (หน้า 239)
ใน API ร่วมสมัยที่คล่องแคล่วมากขึ้นฉันคาดว่าจะเห็น
Heading reciprocalHeading = myHeading.reciprocal();
- ซึ่งจะแนะนำอีกครั้งว่าการโทรนั้นราคาถูก idempotent และไม่มีผลข้างเคียง แต่จะไม่พูดอะไรเกี่ยวกับการคำนวณใหม่หรือการสร้างวัตถุใหม่ นี่เป็นเรื่องปกติ ใน API ที่ดีฉันไม่ควรสนใจ
ใน Ruby ไม่มีสิ่งใดเป็นสมบัติ มี "คุณสมบัติ" แต่ถ้าฉันเห็น
reciprocalHeading = my_heading.reciprocal
ฉันไม่มีทางรู้ได้ทันทีว่าฉันกำลังเข้าถึงตัวแปรอินสแตนซ์@reciprocal
ผ่านทางattr_reader
การเข้าถึงอย่างง่ายหรือว่าฉันกำลังเรียกวิธีการที่ทำการคำนวณราคาแพง ความจริงที่ว่าชื่อเมธอดนั้นเป็นคำนามง่าย ๆ แต่แทนที่จะบอกว่าcalcReciprocal
แนะนำอีกครั้งว่าการโทรนั้นอย่างน้อยราคาถูกและอาจไม่มีผลข้างเคียง
ในสกาล่าการตั้งชื่อแบบแผนก็คือวิธีการที่มีผลข้างเคียงต้องใช้วงเล็บและวิธีการที่พวกมันทำไม่ได้ แต่
val reciprocal = heading.reciprocal
อาจเป็นใด ๆ ของ:
// immutable public value initialized at creation time
val reciprocal: Heading = …
// immutable public value initialized on first use
lazy val reciprocal: Heading = …
// public method, probably recalculating on each invocation
def reciprocal: Heading = …
// as above, with parentheses that, by convention, the caller
// should only omit if they know the method has no side effects
def reciprocal(): Heading = …
(หมายเหตุที่สกาล่าช่วยให้สิ่งต่างๆที่ยังคงท้อแท้โดยคู่มือสไตล์นี้เป็นหนึ่งในความรำคาญที่สำคัญของฉันกับ Scala)
การขาดวงเล็บบอกฉันว่าการโทรไม่มีผลข้างเคียง ชื่ออีกครั้งแสดงให้เห็นว่าการโทรควรจะค่อนข้างถูก นอกเหนือจากนั้นฉันไม่สนใจว่ามันจะทำให้ฉันได้รับคุณค่า
กล่าวโดยย่อ:รู้จักภาษาที่คุณใช้และรู้ว่าผู้เขียนคนอื่นจะคาดหวังอะไรจาก API ของคุณ ทุกอย่างอื่นคือรายละเอียดการใช้งาน
Heading
ชนิดที่ไม่เปลี่ยนรูปแบบและการreciprocal
กลับมาใหม่Heading
คือการปฏิบัติที่ดี "Pit of Success" (ด้วยข้อแม้ที่ทั้งสองสายreciprocal
ควรกลับ "สิ่งเดียวกัน" คือพวกเขาควรจะผ่านการทดสอบความเท่าเทียมกัน)