ทำไมถึงมีช่องส่วนตัวไม่ได้รับการป้องกันเพียงพอ


265

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

หนึ่งในสิ่งแรกที่ฉันทำเมื่อฉันคลาสย่อยคลาสคือการเปลี่ยนprivateวิธีการprotectedมากมาย แต่ซ่อนรายละเอียดจากโลกภายนอกเป็นสำคัญดังนั้นเราจึงจำเป็นและไม่เพียงprotectedpublic

คำถามของฉันคือ: คุณรู้เกี่ยวกับกรณีการใช้งานที่สำคัญprivateแทนที่จะprotectedเป็นเครื่องมือที่ดีหรือสองตัวเลือก " protected& public" เพียงพอสำหรับภาษา OOP หรือไม่?



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

18
คลาสที่ได้รับมาเป็นส่วนหนึ่งของโลกภายนอก
CodesInChaos

20
อย่าลืมว่าการป้องกันไม่ได้หมายความว่าการเข้าถึงจะถูกล็อคไปยังลำดับชั้นการสืบทอด ใน Java จะให้สิทธิ์การเข้าถึงระดับแพ็คเกจด้วย
berry120

8
อาจารย์ของฉันเคยบอกว่า "มีหลายสิ่งที่ฉันจะไม่บอกลูก ๆ ของฉัน
SáT

คำตอบ:


225

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

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

ในทางปฏิบัติprotectedสมาชิกเป็นหลัก "API สาธารณะสำหรับคลาสย่อย" และต้องมีความเสถียรและเข้ากันได้ย้อนหลังได้มากเท่ากับpublicสมาชิก หากเราไม่มีความสามารถในการสร้างprivateสมาชิกจริงแล้วไม่มีอะไรในการใช้งานจะปลอดภัยที่จะเปลี่ยนแปลงเพราะคุณจะไม่สามารถแยกแยะความเป็นไปได้ที่รหัสลูกค้า (ไม่ประสงค์ร้าย) ได้รับการจัดการขึ้นอยู่กับ มัน.

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


11
ฉันจะขว้างคุณมากกว่า +1 ถ้าทำได้เพราะนี่เป็นครั้งแรกprivateที่ฉันเข้าท่า มุมมอง lib จำเป็นต้องใช้บ่อยขึ้นมิฉะนั้นใครก็ตามที่ชื่นชอบ "การควบคุมแบบสัมบูรณ์" (c-like) "การควบคุมแบบสัมบูรณ์ความรับผิดชอบแบบสัมบูรณ์" ความคิดการเข้ารหัสอาจตั้งค่าสถานะเป็น "ปกป้องฉันจากตัวเอง" โปรดทราบว่าฉันยังคงเคยใช้มาprivateก่อนหน้านี้ฉันแค่รู้สึกว่ามีเอกสารที่ดีอยู่เสมอและการตั้งชื่อแบบที่ต้องการ_fooเพื่อบ่งบอกว่าคุณไม่ควรจะยุ่งกับมันเท่ากันถ้าไม่ดีกว่า ความสามารถในการพูดอย่างไม่แน่นอนว่า "ไม่มีอะไรจะทำให้แตก" เป็นคุณสมบัติที่ถูกต้องตามกฎหมายprivateเท่านั้น
abluejelly

เดิมทีฉันไม่สนใจกรณีของรหัสของไลบรารีสาธารณะและกรอบงานและคิดว่ามากหรือน้อยในแง่ของ "รหัสลูกค้า" เท่านั้น การเพิ่มประสิทธิภาพการใช้งานภายในเป็นตัวอย่างที่ดีสำหรับคำถามของฉันแม้ว่าฉันจะถามตัวเองว่าสิ่งนี้เกิดขึ้นจริงหรือไม่ (โดยเฉพาะอย่างยิ่งเมื่อหลาย ๆ คนแนะนำคลาสไม่ควรมีความยาวเกิน 1,000 บรรทัด) โดยทั่วไปแล้วฉันชอบวิธีการของรูบี้ซึ่งเป็นคำแนะนำส่วนตัว: "นี่คือมังกรดำเนินการด้วยความระมัดระวัง"
Adam Libuša

9
@ AdamLibušaแม้ว่านี่จะเป็นข้อตกลงที่ใหญ่กว่ามากหากรหัสของคุณเป็นแบบสาธารณะ แต่ก็ยังคงมีผลอยู่แม้ว่าคุณจะเป็นผู้เขียนลูกค้าของคลาสทั้งหมดก็ตาม ปัญหาเพียงเปลี่ยนจาก refactors บางอย่างเป็นไปไม่ได้เพื่อ refactors บางอย่างที่น่าเบื่อและข้อผิดพลาดได้ง่าย การหาค่าเหมาะที่สุดจริง ๆ แล้วเป็นเหตุผลที่พบน้อยที่สุดสำหรับ refactors เหล่านี้ในประสบการณ์ของฉัน (แม้ว่าฉันจะทำจาวาสคริปต์เป็นหลัก), โดยปกติแล้วมันเป็นเหมือนข้อผิดพลาดที่พบข้อบกพร่องในการใช้งานขั้นพื้นฐาน การแก้ไขที่แข็งแกร่งอย่างแท้จริง
Ixrec

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

1
ฉันจะขว้างคุณมากกว่า +1 ถ้าฉันทำได้ => นั่นคือสิ่งที่เราเรียกว่าโปรดปราน @abluejelly
Thomas Ayoub

256

ใน OOP ไม่ช้าก็เร็วคุณจะสร้างคลาสย่อยของคลาส

นี่เป็นสิ่งที่ผิด ไม่ใช่ว่าทุกคลาสจะมีคลาสย่อยและบางภาษา OOP ที่พิมพ์แบบสแตติกจะมีคุณสมบัติในการป้องกันเช่นfinal(Java และ C ++) หรือsealed(C #)

เป็นการดีที่จะเข้าใจและสามารถปรับใช้งานได้อย่างสมบูรณ์

ไม่มันไม่ใช่. เป็นการดีที่คลาสจะสามารถกำหนดส่วนต่อประสานสาธารณะได้อย่างชัดเจนและรักษาค่าคงที่แม้ว่าจะสืบทอดมาจากคลาสก็ตาม

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

หรือจะใส่ไว้ในเงื่อนไขของ Scott Meyers: ส่วนส่วนตัวของคลาสได้รับผลกระทบจากจำนวน จำกัด ของรหัส: โค้ดของคลาสเอง

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

ส่วนที่ได้รับความคุ้มครองอาจได้รับผลกระทบจากคลาสย่อยที่มีอยู่ทั้งหมดและคลาสย่อยทั้งหมดที่ยังไม่ได้ถูกเขียนซึ่งเป็นรหัสจำนวนอนันต์

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


34
+1 สำหรับสถานการณ์เชิงทฤษฎีของ "รับผลกระทบจากจำนวนอนันต์ของรหัส"
Broken_Window

13
บางทีก็น่าสังเกตว่าผู้ออกแบบ C # ตัดสินใจห้ามมิให้ใช้วิธีการที่สืบทอดมาเว้นแต่จะมีการระบุไว้ชัดเจนว่าเป็นvirtualเพราะเหตุผลที่อธิบายไว้ในคำตอบนี้
Will Vousden

11
หรือใส่เพียง: protectedสำหรับวิธีการไม่ได้สำหรับข้อมูลสมาชิก
Matthieu M.

7
ฉันหามันไม่พบในตอนนี้ แต่ฉันจำได้ว่าอ่านคำตอบที่เป็นลายลักษณ์อักษรอย่างดีจาก @EricLippert เกี่ยวกับสาเหตุที่ MS เป็นsealedส่วนใหญ่ของไลบรารี. net และ IIRC ว่าทำไมเขาถึงชอบที่จะล็อคส่วนที่เหลือไว้ ช่วงเวลาที่คุณอนุญาตให้ผู้สืบทอดบุคคลที่สามเริ่มสัมผัสค่าภายในที่คุณต้องการเพิ่มจำนวนมากของการตรวจสอบความถูกต้อง / การตรวจสอบสติกับทุกวิธีเพราะคุณไม่สามารถเชื่อถือค่าคงที่การออกแบบใด ๆ เกี่ยวกับสถานะภายในวัตถุ
Dan Neely

4
@ ThorbjørnRavnAndersen "ในขณะที่การพัฒนา แต่ไม่ได้รับการปล่อยตัวเมื่อ" - ชั้นเรียนบนโลกควรจะรู้ได้อย่างไร? คุณต้องการรวบรวมรุ่นทดสอบที่แตกต่างจากรุ่นที่วางจำหน่ายจริงหรือไม่เมื่อคุณไม่สามารถทดสอบรุ่นที่วางจำหน่ายได้ การทดสอบไม่จำเป็นต้องเข้าถึงข้อมูลส่วนตัว
เซบาสเตียนเรดล

33

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

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


2
+1 สำหรับ "ขี่โค้ชและม้าผ่าน" อะไรก็ได้ มันเป็นวลีที่ยอดเยี่ยมที่ฉันหวังว่าจะได้ยินมากขึ้น
Nic Hartley

2
หากใครบางคนต้องการคลาสย่อยของคุณบางทีเขาควรจะเข้าถึงระบบป้องกันของคุณ? และหากคุณไม่ต้องการให้ใครบางคนเปลี่ยนมาตรการป้องกันเพื่อให้บรรลุเป้าหมายบางอย่างคุณอาจไม่แชร์รหัสหรือไม่ มันใช้งานได้เช่นนี้ใน Ruby - private เป็นคำแนะนำไม่มากก็น้อย
Adam Libuša

3
@ AdamLibuša "อย่าเปิดเผยรหัส" หรือไม่ ทันทีที่คุณเผยแพร่ DLL ใด ๆ คุณจะแบ่งปันรหัส - โครงสร้างและวิธีการทั้งหมดและทุกอย่างจะมีให้คนทั้งโลกได้เห็นโดยเฉพาะอย่างยิ่งกับภาษาที่สนับสนุนการสะท้อนตามค่าเริ่มต้น ทุกคนสามารถทำสิ่งที่พวกเขาต้องการด้วย "รหัสของคุณ" - privateเป็นเพียงวิธีการพูดว่า "อย่าแตะต้องสิ่งเหล่านี้" และบังคับใช้ภายในสัญญาคอมไพเลอร์ ในระบบเช่น. NET สิ่งนี้มีผลกระทบด้านความปลอดภัยที่สำคัญด้วย - คุณสามารถสัมผัสกับสิทธิส่วนบุคคลของผู้อื่นได้เมื่อคุณมีความไว้วางใจอย่างเต็มที่
Luaan

2
@ AdamLibušaฉันคิดว่าความสับสนของคุณส่วนใหญ่เกิดจาก OOP ที่แตกต่างกันวิธีการใช้ภาษาที่แตกต่างกัน รากของ OOP (ตามที่กำหนดไว้เดิม) คือการส่งข้อความ - ซึ่งหมายความว่าทุกอย่างเป็นส่วนตัวยกเว้นสำหรับข้อความที่คุณตอบกลับ ในภาษา OOPish ส่วนใหญ่สิ่งนี้จะถูกเปิดเผยเป็น "ทำให้ข้อมูลของคุณเป็นส่วนตัว" - วิธีที่จะทำให้ส่วนต่อประสานสาธารณะมีขนาดเล็กที่สุดเท่าที่จะทำได้ วิธีเดียวที่ผู้ใช้ (ไม่ว่าจะเป็นคลาสย่อยหรือคลาสอื่น) มีการจัดการชั้นเรียนของคุณผ่านส่วนต่อประสานสาธารณะที่คุณกำหนดไว้ - คล้ายกับวิธีที่คุณใช้พวงมาลัยและคันเหยียบในการขับรถ :)
Luaan

3
@Luaan +1 เมื่อมันโอเคที่จะสัมผัสกับสิทธิของผู้อื่น!
Nigel Touch

12

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

  1. วิธีการที่เกี่ยวข้องกับพวกเขาก่อนและหลังเงื่อนไข (สัญญา)
  2. วัตถุที่เกี่ยวข้องกับพวกเขาไม่เปลี่ยนแปลง

การใช้เหตุผลแบบแยกส่วนเกี่ยวกับวัตถุดำเนินการดังต่อไปนี้ (อย่างน้อยก็ประมาณแรก)

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

ลองนึกภาพว่าเราตรวจสอบการobject Aใช้วิธีการด้านบน และตอนนี้ต้องการตรวจสอบmethod gของobject Bที่เรียกของmethod f object Aเหตุผล Modular ช่วยให้เราสามารถที่จะให้เหตุผลเกี่ยวกับการได้โดยไม่ต้องพิจารณาการดำเนินงานของmethod g method fโดยที่เราสามารถสร้างค่าคงที่object Aและเงื่อนไขก่อนกำหนดmethod fที่ไซต์การโทรในmethod g,เราสามารถใช้เงื่อนไขการโพสต์method fเป็นบทสรุปของพฤติกรรมของการเรียกเมธอด ยิ่งไปกว่านั้นเราจะได้รู้ว่าหลังจากการโทรกลับคืนค่าAคงเดิม

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

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

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

เขตข้อมูลที่มีการป้องกัน

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

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

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


8

privateตัวแปรในคลาสนั้นดีกว่าprotectedด้วยเหตุผลเดียวกันกับที่breakข้อความในswitchบล็อกนั้นดีกว่าgoto labelข้อความ ซึ่งเป็นที่โปรแกรมเมอร์ของมนุษย์มีข้อผิดพลาดได้ง่าย

protectedตัวแปรให้ยืมตัวไปใช้ในทางที่ผิดโดยไม่เจตนา (ความผิดพลาดของโปรแกรมเมอร์) เช่นเดียวกับgotoคำสั่งที่ให้ยืมตัวเองเพื่อสร้างรหัสสปาเก็ตตี้

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

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

คลาสพื้นฐานไม่มีความรู้เกี่ยวกับคลาสที่ได้รับมาอย่างแน่นอน ตราบใดที่คลาสเบสเป็นห่วงprotectedไม่ได้ให้ความคุ้มครองแก่คุณมากกว่าpublicเพราะไม่มีอะไรจะหยุดคลาสที่ได้รับจากการสร้างpublicgetter / setter ซึ่งทำหน้าที่เหมือนแบ็คดอร์

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

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

ในที่สุดภาษาระดับสูงมีอยู่เพื่อลดข้อผิดพลาดของมนุษย์ มีแนวทางการเขียนโปรแกรมที่ดี (เช่นหลักการ SOLID ) เพื่อลดข้อผิดพลาดของมนุษย์

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


เพื่อ downvoter - อะไรที่สามารถเปลี่ยนแปลง / ปรับปรุงเกี่ยวกับคำตอบนี้?
Ben Cottrell

ฉันไม่ได้ลงคะแนน แต่เปรียบเทียบระดับการเข้าถึงกับตัวแบ่ง / ข้ามไป?
imel96

@ imel96 ไม่เปรียบเทียบสาเหตุที่หลีกเลี่ยงไม่ได้และถูกทำให้ท้อแท้โดย "วิธีปฏิบัติที่ดีที่สุด" (โดยเฉพาะอย่างยิ่งสำหรับการเขียนรหัสใหม่ ) เช่นโปรแกรมเมอร์ที่มีความสามารถจะหลีกเลี่ยงpublicรายละเอียดการใช้งานเพราะมันยืมตัวเองไปยังโค้ดที่ไม่มีความสามารถ โปรแกรมเมอร์ที่มีความสามารถจะหลีกเลี่ยงgotoเพราะมันยืมตัวเองเป็นรหัสที่ไม่มีความสามารถ อย่างไรก็ตามโลกแห่งความเป็นจริงนั้นบางครั้งคุณก็หลงทางในเรื่องของรหัสดั้งเดิมและไม่มีทางเลือกนอกจากการใช้gotoและด้วยเหตุผลเดียวกันนี้บางครั้งคุณก็ไม่มีทางเลือกนอกจากใช้รายละเอียดการนำไปปฏิบัติ
Ben Cottrell

ความรุนแรงนั้นแตกต่างกันในเรื่องของขนาดมันหาที่เปรียบมิได้ ฉันจะอยู่ด้วยรหัสที่มีเพียงpublicคุณสมบัติ / อินเตอร์เฟซ gotoแต่ไม่ได้มีรหัสที่ใช้เท่านั้น
imel96

2
@ imel96 คุณเคยทำงานในรหัสที่ใช้gotoหรือเป็นเพราะคุณได้อ่านบทความเช่นนี้หรือไม่? ฉันเข้าใจว่าทำไม gotoความชั่วร้ายเพราะฉันใช้เวลา 2 ปีทำงานในรหัสโบราณที่ใช้มัน และฉันใช้เวลาทำงานกับโค้ดนานขึ้นซึ่ง "คลาส" มีรายละเอียดการใช้งานรั่วไหลไปทุกหนทุกแห่งpublicและตัวfriendระบุใช้เป็นแฮ็กเร็ว / ง่าย / สกปรก ฉันไม่ยอมรับข้อโต้แย้งที่ว่า "การเปิดเผยรายละเอียดการปฏิบัติต่อสาธารณะ" ไม่สามารถทำให้ปาเก็ตตี้ยุ่งเหยิงระหว่างกันในระดับความรุนแรงเท่ากันgotoเพราะมันสามารถทำได้จริง ๆ
Ben Cottrell

4

คลาสที่สืบทอดได้มีสองสัญญา - หนึ่งที่มีผู้ถือการอ้างอิงวัตถุและคลาสที่ได้รับ สมาชิกสาธารณะจะผูกพันตามสัญญากับผู้ถืออ้างอิงและสมาชิกที่ได้รับความคุ้มครองจะผูกพันตามสัญญากับคลาสที่ได้รับ

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

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


4

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

หากข้อสันนิษฐานนั้นถูกปฏิเสธมีเพียงสองกรณีที่ต้องพิจารณา

  1. ผู้เขียนชั้นเรียนดั้งเดิมมีความคิดที่ชัดเจนว่าทำไมมันถึงขยายออกไป (เช่นเป็น BaseFoo และจะมีการใช้งาน Foo ที่เป็นรูปธรรมจำนวนมากตามถนน)

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

  1. ผู้เขียนระดับเด็กกำลังพยายามแฮ็กพฤติกรรมบางอย่างในชั้นผู้ปกครอง

กรณีนี้น่าจะหายาก (คุณอาจแย้งว่ามันไม่ถูกกฎหมาย) และไม่ต้องการเพียงแค่ปรับเปลี่ยนคลาสต้นฉบับในฐานรหัสดั้งเดิม มันอาจเป็นอาการของการออกแบบที่ไม่ดี ในกรณีเหล่านี้ฉันต้องการคนที่แฮ็คในพฤติกรรมเพียงใช้แฮ็กอื่น ๆ เช่นเพื่อน (C / C ++) และsetAccessible(true)(Java)

ฉันคิดว่ามันปลอดภัยที่จะปฏิเสธสมมติฐานนั้น

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


2

ระดับการเข้าถึงทั้งสามมีกรณีการใช้งานของพวกเขา OOP จะไม่สมบูรณ์ขาดใด ๆ ของพวกเขา คุณมักจะทำ

  • ทำให้ตัวแปรทั้งหมด / ข้อมูลสมาชิกส่วนตัว คุณไม่ต้องการให้ใครบางคนจากภายนอกไปยุ่งกับข้อมูลภายในของคุณ นอกจากนี้วิธีการที่มีฟังก์ชั่นการใช้งานเพิ่มเติม (คิดว่าการคำนวณขึ้นอยู่กับตัวแปรสมาชิกหลายตัว) กับส่วนต่อสาธารณะหรือส่วนต่อประสานที่มีการป้องกันของคุณ- นี่เป็นเพียงการใช้ภายในเท่านั้นและคุณอาจต้องการเปลี่ยน / ปรับปรุงในอนาคต
  • ทำให้อินเตอร์เฟซทั่วไปของชั้นเรียนของคุณสาธารณะ นั่นคือสิ่งที่ผู้ใช้ในชั้นเรียนดั้งเดิมของคุณควรทำงานด้วยและวิธีที่คุณคิดว่าคลาสที่ได้รับควรมีลักษณะเช่นกัน เพื่อให้การห่อหุ้มที่เหมาะสมเหล่านี้มักจะเป็นวิธีการเท่านั้น (และคลาสตัวช่วย / structs, enums, typedefs สิ่งที่ผู้ใช้ต้องการทำงานกับวิธีการของคุณ) ไม่ใช่ตัวแปร
  • ประกาศวิธีการป้องกันที่สามารถใช้งานได้สำหรับผู้ที่ต้องการขยาย / เชี่ยวชาญการทำงานของชั้นเรียนของคุณ แต่ไม่ควรเป็นส่วนหนึ่งของส่วนต่อประสานสาธารณะ - อันที่จริงคุณมักจะเพิ่มสมาชิกส่วนตัวให้ได้รับการป้องกันเมื่อจำเป็น หากมีข้อสงสัยคุณจะไม่ทำจนกว่าคุณจะรู้
    1. ชั้นเรียนของคุณสามารถ / อาจ / จะเป็นคลาสย่อย
    2. และมีความคิดที่ชัดเจนว่ากรณีการใช้งานของคลาสย่อยอาจเป็นอย่างไร

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


1

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

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


1

คำตอบที่ดีมากมายที่นี่ แต่ฉันจะโยนสองเซ็นต์ของฉันต่อไป :-)

ส่วนตัวดีสำหรับเหตุผลเดียวกับที่ข้อมูลทั่วโลกไม่ดี

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

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


1

ฉันคิดว่ามันคุ้มค่าที่จะพูดถึงความคิดเห็นที่ไม่เห็นด้วย

ในทางทฤษฎีมันเป็นเรื่องดีที่ได้ควบคุมระดับการเข้าถึงด้วยเหตุผลทั้งหมดที่กล่าวถึงในคำตอบอื่น ๆ

ในทางปฏิบัติบ่อยครั้งเมื่อตรวจสอบโค้ดฉันเห็นคน (ผู้ที่ต้องการใช้ส่วนตัว) เปลี่ยนระดับการเข้าถึงจากส่วนตัว -> ได้รับการป้องกันและไม่บ่อยเกินไปจากการป้องกัน -> สาธารณะ เกือบตลอดเวลาการเปลี่ยนคุณสมบัติคลาสเกี่ยวข้องกับการปรับเปลี่ยน setters / getters สิ่งเหล่านี้เสียเวลาของฉันมาก (การตรวจสอบรหัส) และของพวกเขา (การเปลี่ยนรหัส)

นอกจากนี้ยังทำให้ฉันรำคาญด้วยนั่นหมายความว่าคลาสของพวกเขาจะไม่ปิดเพื่อการดัดแปลง

นั่นคือด้วยรหัสภายในที่คุณสามารถเปลี่ยนได้เสมอหากคุณต้องการเช่นกัน สถานการณ์แย่ลงเมื่อใช้รหัสบุคคลที่สามเมื่อไม่สามารถเปลี่ยนรหัสได้ง่าย

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

Imo คล้ายกับการพิมพ์แบบไดนามิก / แบบคงที่ ในทางทฤษฎีการพิมพ์แบบสแตติกนั้นดีมาก ในทางปฏิบัติมันเพียง แต่ป้องกันไม่ให้เหมือน 2% ของข้อผิดพลาดประสิทธิผลไม่มีเหตุผลแบบไดนามิกพิมพ์ดีด ... การใช้งานส่วนตัวอาจป้องกันข้อผิดพลาดได้น้อยกว่านั้น

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


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

0

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

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

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


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

@sam โดยทั่วไปควรเขียนโค้ดโดยมีข้อสันนิษฐานว่าใครก็ตามที่แก้ไขมันในครั้งต่อไปจะไม่จำเป็นต้องรู้ว่า codebase ทั้งหมดนั้นอยู่ข้างใน นั่นอาจเป็นผู้เขียนต้นฉบับในบางครั้ง (เวลาผ่านไปการอดนอน ... ) การโกงอาจเป็นนักเรียนที่ได้รับรหัสโครงกระดูกเพื่อเนื้อออกและเปลี่ยนตรรกะที่พวกเขาไม่ควรสัมผัส
Phil Lello

0

โดยทั่วไปเมธอด / ตัวแปรส่วนตัวจะถูกซ่อนจากคลาสย่อย นั่นอาจเป็นสิ่งที่ดี

วิธีการส่วนตัวสามารถตั้งสมมติฐานเกี่ยวกับพารามิเตอร์และออกจากการตรวจสอบสติไปที่ผู้โทร

วิธีการป้องกันควรมีสติตรวจสอบอินพุต


-1

"ส่วนตัว" หมายถึง: ไม่ได้มีเจตนาที่จะเปลี่ยนแปลงหรือเข้าถึงได้โดยทุกคนยกเว้นชั้นเรียนเอง ไม่ได้ตั้งใจจะเปลี่ยนแปลงหรือเข้าถึงโดยคลาสย่อย subclasses? คลาสย่อยอะไร คุณไม่ควรจะทำคลาสย่อยนี้!

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

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


-1

หนึ่งในสิ่งแรกที่ฉันทำเมื่อฉันคลาสย่อยคลาสคือการเปลี่ยนวิธีการส่วนตัวเพื่อป้องกัน

เหตุผลบางประการเกี่ยวprivateกับกับprotected วิธีการ :

privateวิธีการป้องกันการใช้รหัสซ้ำ คลาสย่อยไม่สามารถใช้รหัสในวิธีส่วนตัวและอาจต้องใช้อีกครั้ง - หรือนำวิธีการนั้นมาใช้ใหม่ซึ่งเดิมขึ้นอยู่กับวิธีการส่วนตัว & c

ในทางกลับกันวิธีการใด ๆ ที่ไม่ privateสามารถมองเห็นได้ว่าเป็น API ที่จัดทำโดยชั้นเรียนถึง "โลกภายนอก" ในแง่ที่ว่า subclasses ของบุคคลที่สามได้รับการพิจารณาว่าเป็น "โลกภายนอก" ด้วยเช่นกัน แล้ว.

นั่นเป็นสิ่งที่ไม่ดีเหรอ? - ฉันไม่คิดอย่างนั้น

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

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

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

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

ต้องการความสามารถในการขยายและการรับมรดก privateอย่าทำให้วิธีการของคุณ

ไม่ต้องการให้พฤติกรรมบางอย่างในชั้นเรียนของคุณเปลี่ยนไปหรือไม่? finalทำให้วิธีการของคุณ

จริง ๆ แล้วไม่สามารถเรียกวิธีการของคุณนอกบริบทที่กำหนดชัดเจน ทำให้วิธีการของคุณprivateและ / หรือคิดเกี่ยวกับวิธีที่คุณสามารถทำให้บริบทที่กำหนดไว้อย่างดีที่จำเป็นสำหรับการใช้ซ้ำผ่านprotectedวิธีการ wrapper อื่น

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

สำหรับสาขาที่privateไม่เลวจริงๆ ตราบใดที่เขตข้อมูลสามารถ "ใช้" อย่างสมเหตุสมผลด้วยวิธีการที่เหมาะสม ( ไม่ใช่ getXX()หรือsetXX()!)


2
-1 สิ่งนี้ไม่ได้ตอบคำถามเดิมprivateเทียบกับprotectedให้คำแนะนำที่ผิดพลาด ("ใช้privateเท่าที่จำเป็น"?) และขัดกับฉันทามติทั่วไปในการออกแบบ OO การใช้privateไม่เกี่ยวข้องกับการซ่อนโค้ดเลอะเทอะ
Andres F.

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

1
@HannoBinder ฉันยอมรับว่ามีชั้นเรียนมากมายที่ประสบจากความแข็งแกร่งอย่างไรก็ตามความยืดหยุ่นและการนำรหัสกลับมาใช้มีความสำคัญน้อยกว่าการห่อหุ้มและการบำรุงรักษาในระยะยาว พิจารณากรณีของคุณที่สมาชิกทุกคนในชั้นเรียนมีการป้องกันและชั้นเรียนที่ได้มาสามารถยุ่งเกี่ยวกับรายละเอียดการดำเนินการใด ๆ ที่พวกเขาต้องการ; คุณทำการทดสอบหน่วยในชั้นเรียนอย่างน่าเชื่อถือได้อย่างไรโดยรู้ว่าอะไรในส่วนใด ๆ ของรหัสที่ไม่ได้เขียนอาจทำให้รหัสนั้นล้มเหลวได้ตลอดเวลา รหัสที่สามารถ "แฮ็ก" ได้จำนวนเท่าไรก่อนที่มันจะเสื่อมสภาพกลายเป็นโคลนก้อนใหญ่?
Ben Cottrell

2
โอ้คุณพูดว่า "สมาชิก" สิ่งที่ฉันพูดหมายถึงวิธีการเท่านั้น ตัวแปรสมาชิก (ฟิลด์) เป็นเรื่องราวที่แตกต่างที่ความเป็นส่วนตัวมีความชอบธรรมมากกว่า
JimmyB

2
ศัพท์เฉพาะในการอภิปรายมีอยู่ทั่วทุกแห่งเพราะมันไม่เฉพาะเจาะจงกับภาษาใดภาษาหนึ่ง "สมาชิก" ใน C ++ สามารถเป็นข้อมูลฟังก์ชันประเภทหรือเทมเพลต
JDługosz

-1

คุณรู้เกี่ยวกับกรณีการใช้งานที่สำคัญที่เป็นส่วนตัวแทนที่จะได้รับการป้องกันเป็นเครื่องมือที่ดีหรือสองตัวเลือก "ที่ได้รับการป้องกันและสาธารณะ" เพียงพอสำหรับภาษา OOP หรือไม่?

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

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

ตัวอย่าง:

public abstract Class MercedesBenz() extends Car {
  //Might be useful for subclasses to know about their customers
  protected Customer customer; 

  /* Each specific model has its own horn. 
     Therefore: protected, so that each subclass might implement it as they wish
  */
  protected abstract void honk();

  /* Taken from the car class. */
  @Override
  public void getTechSupport(){
     showMercedesBenzHQContactDetails(customer);
     automaticallyNotifyLocalDealer(customer);
  }

  /* 
     This isn't specific for any subclass.
     It is also not useful to call this from inside a subclass,
     because local dealers only want to be notified when a 
     customer wants tech support. 
   */
  private void automaticallyNotifyLocalDealer(){
    ...
  }
}

2
เมื่อคุณมีบางสิ่งบางอย่างที่จะไม่เป็นประโยชน์สำหรับคลาสย่อยใด ๆ ที่จะโทรหาหรือลบล้าง - และนี่คือสิ่งที่คุณในความคิดของฉันไม่เคยรู้ล่วงหน้า
Adam Libuša

ฉันอาจต้องกดปุ่มรีเซ็ตบน CMOS ของฉันด้วย แต่ข้อสันนิษฐานเริ่มต้นคือฉันไม่ต้องการมันมากและดังนั้นมันจึงถูกใส่เข้าไปในแชสซี เช่นเดียวกับวิธีการต่างๆ คุณทำให้มันได้รับการปกป้องหากคลาสย่อยจำเป็นต้องปรับใช้ / เรียกมันอีกครั้ง (ดู: honking) คุณทำให้เป็นสาธารณะหากบุคคลอื่น ๆ จำเป็นต้องโทรหา
Arnab Datta

-2

มันยากสำหรับฉันที่จะเข้าใจเรื่องนี้ดังนั้นฉันจึงต้องการแบ่งปันประสบการณ์ของฉัน:

  • เขตข้อมูลที่มีการป้องกันคืออะไร มันไม่มีอะไรมากไปกว่าสนามที่ไม่สามารถเข้าถึงได้นอกชั้นเรียนคือสาธารณะ$classInstance->fieldเช่นนี้ และเคล็ดลับที่ว่า "นี่คือมัน" เด็กในชั้นเรียนของคุณจะสามารถเข้าถึงได้อย่างเต็มที่เพราะเป็นส่วนภายในที่ถูกต้อง
  • อะไรคือสิ่งที่ส่วนตัวฟิลด์? มันเป็น " ความเป็นส่วนตัวที่แท้จริง " สำหรับชั้นเรียนของคุณและการใช้ชั้นเรียนของคุณเอง "ให้พ้นมือเด็ก" เหมือนขวดยา คุณจะมีการรับประกันว่ามันเป็น unoverridable โดยระดับของสัญญาซื้อขายล่วงหน้าวิธีการของคุณ - เมื่อเรียก - จะมีแน่นอนสิ่งที่คุณได้ประกาศ

UPDATE: ตัวอย่างจริงจากงานจริงที่ฉันแก้ไข นี่คือ: คุณมีโทเค็นเช่น USB หรือ LPT (นั่นคือกรณีของฉัน) และคุณมีมิดเดิลแวร์ โทเค็นจะขอรหัสผ่านจากคุณเปิดขึ้นถ้ามันถูกต้องและคุณสามารถส่งส่วนที่เข้ารหัสและจำนวนของคีย์เพื่อถอดรหัส ปุ่มถูกเก็บไว้ในโทเค็นคุณไม่สามารถอ่านได้ใช้มันเท่านั้น และมีกุญแจชั่วคราวสำหรับเซสชันที่เซ็นชื่อด้วยคีย์ในโทเค็น แต่เก็บไว้ในมิดเดิลแวร์เอง รหัสชั่วคราวไม่ควรรั่วไปข้างนอกเพื่ออยู่ในระดับไดรเวอร์ และฉันใช้ฟิลด์ส่วนตัวเพื่อจัดเก็บคีย์ชั่วคราวนี้และข้อมูลที่เกี่ยวข้องกับการเชื่อมต่อฮาร์ดแวร์ ดังนั้นอนุพันธ์จึงไม่สามารถใช้งานไม่ได้เป็นเพียงส่วนต่อประสานสาธารณะ แต่ยังมีบางส่วนที่ได้รับการป้องกันรูทีนย่อย "มีประโยชน์" ที่ฉันทำไว้สำหรับงาน แต่ไม่สามารถเปิดกล่องรับข้อมูลด้วยปุ่มและการโต้ตอบ HW มีเหตุผล?


ขอโทษนะเพื่อน! เพิ่งสับสนพวกเขา - อัปเดตคำตอบของฉัน =) ขอบคุณ! ฉันรีบร้อนและพิมพ์ผิด =)
Alexey Vesnin

2
ฉันคิดว่า OP ตระหนักดีถึงความแตกต่างระหว่างระดับการป้องกันสองระดับ แต่สนใจว่าทำไมจึงควรใช้อีกระดับหนึ่ง
Sam

@ Sam โปรดอ่านคำตอบของฉันให้ลึกซึ้งยิ่งขึ้น มันเป็นสนามที่แตกต่างกันโดยสิ้นเชิง ! เพียงสิ่งที่พวกเขามีเหมือนกันคือว่าพวกเขาทั้งสองไม่สามารถอ้างอิงสาธารณะ
Alexey Vesnin

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

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