คุณสมบัติควรมีผลข้างเคียง


19

คุณสมบัติใน C # ควรมีผลข้างเคียงนอกเหนือจากการแจ้งการเปลี่ยนแปลงสถานะหรือไม่?

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


3
อ่าให้ฉันค้นหาคำถาม SO ที่เกี่ยวข้อง 1 วินาทีstackoverflow.com/questions/2451910/... stackoverflow.com/questions/2784934/... stackoverflow.com/questions/582680/... stackoverflow.com/questions/694711/...
งาน

1
ท่ามกลางการค้นพบของ @ Job เหตุใดฉันจึงควรหลีกเลี่ยงการใช้คุณสมบัติใน C # ความเห็นของอาคา Jeffrey Richter นั้นเกี่ยวข้องกับคำถามนี้มาก
วง

@rwong เกี่ยวข้องใช่ แต่ไม่รู้สึกอย่างสมบูรณ์ - ไม่ต้องอ่าน (เพื่อให้ตระหนักถึงปัญหาที่เขาเน้น) อย่างน้อยในเรื่องนี้ฉันอยู่ในค่าย Skeet
Apoorv Khurasia

แม้ว่าสิ่งนี้เกี่ยวข้องกับตัวสร้าง แต่ก็มีความเกี่ยวข้องเช่นกัน: programmers.stackexchange.com/a/164255/1996
Jim G.

คำตอบ:


40

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

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

โดยทั่วไปนั่นหมายความว่าผู้ให้บริการสถานที่พักไม่ควรมีผลข้างเคียง

อย่างไรก็ตามขอให้ระมัดระวังเกี่ยวกับสิ่งที่เราหมายถึงโดย "ผลข้างเคียง"

ผลข้างเคียงที่เป็นเทคนิคใด ๆการปรับเปลี่ยนของรัฐ นั่นอาจเป็นสถานะที่สาธารณชนเข้าถึงได้หรือ ... อาจเป็นสถานะส่วนตัวโดยสิ้นเชิง

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

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

ดังนั้นผมจึงจะคลายข้อ จำกัด บิตต่อไปนี้: ทรัพย์สินอ่านไม่ควรจะต้องมองเห็นผลข้างเคียงหรือผลข้างเคียงที่เปลี่ยนความหมายของพวกเขา

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

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


2
+1 - คำตอบที่สมบูรณ์รวมถึงกรณีที่ซับซ้อนกว่าซึ่งเปลี่ยน "จะ" เป็น "ควร ... ยกเว้นเมื่อ .... "
fast_now

อีกตัวอย่างของผลข้างเคียงที่ยอมรับได้ในตัวรับ: ฟังก์ชันการบันทึก
Loren Pechtel

5

ฉันจะตอบคำถามของคุณด้วยคำถาม: จะเกิดอะไรขึ้นเมื่อคุณแก้ไขคุณสมบัติความกว้างของแบบฟอร์ม

เพิ่งออกจากหัวฉันจะ:

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

(ข้อจำกัดความรับผิดชอบ: ฉันเป็นนักพัฒนา Delphi ไม่ใช่นักพัฒนา. NET นี่อาจไม่ถูกต้อง 100% สำหรับ C # แต่ฉันคิดว่ามันใกล้เคียงกันมาก

"ผลข้างเคียง" ทั้งหมดเหล่านี้เกิดขึ้นเมื่อคุณเปลี่ยนคุณสมบัติความกว้างในแบบฟอร์ม คนใดคนหนึ่งดูเหมือนว่าไม่เหมาะสมหรือไม่ถูกต้องอย่างใด?


ตราบใดที่มันไม่ได้เข้าสู่วงวนไม่สิ้นสุดที่เรียกตัวมันเอง เพื่อหลีกเลี่ยงปัญหานี้ "การเปลี่ยนแปลง" แต่ละรายการจะถูกแมปกับเหตุการณ์อย่างน้อยสามเหตุการณ์: เหตุการณ์หนึ่งถูกยิงก่อนการเปลี่ยนแปลงหนึ่งเหตุการณ์ถูกไล่ออกระหว่างการเปลี่ยนแปลงและอีกเหตุการณ์หนึ่งถูกไล่ออกหลังจากเสร็จสิ้น
วง

5

ดูกฎการออกแบบของ Microsoftโดยเฉพาะหนึ่งในนั้น:

CA1024: ใช้คุณสมบัติตามความเหมาะสม

... วิธีการคือผู้สมัครที่ดีที่จะกลายเป็นสถานที่ให้บริการหากมีเงื่อนไขใด ๆ ต่อไปนี้:

  • ไม่รับข้อโต้แย้งและส่งคืนข้อมูลสถานะของวัตถุ
  • ยอมรับอาร์กิวเมนต์เดี่ยวเพื่อตั้งค่าบางส่วนของสถานะของวัตถุ

คุณสมบัติควรประพฤติเหมือนเป็นฟิลด์ หากวิธีการไม่สามารถทำได้ก็ไม่ควรเปลี่ยนเป็นคุณสมบัติ วิธีการนั้นดีกว่าคุณสมบัติในสถานการณ์ต่อไปนี้:

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

2

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

แก้ไข : โอ้อีกอย่างหนึ่ง - ยิงเหตุการณ์ที่พูดว่า "PropertyXYZ เปลี่ยนแล้ว" (เช่นINotifyPropertyChanged) - ใช้ได้กับตัวเซ็ต


2

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


2

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

  1. เราต้องการให้คลาสทดสอบได้ง่าย
  2. เราต้องการชั้นเรียนเพื่อสนับสนุนการทำงานพร้อมกัน
  3. เราต้องการให้ชั้นเรียนนั้นง่ายต่อการให้เหตุผลสำหรับบุคคลที่สาม

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

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

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

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

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