ข้อมูลซ่อนตัวอยู่มากกว่าการประชุมหรือไม่?


20

ใน Java, C # และภาษาที่มีการตรวจสอบอย่างมากและมีการพิมพ์แบบคงที่เราใช้ในการเขียนโค้ดดังนี้:

public void m1() { ... }
protected void m2() { ... }
private void m2() { ... }
void m2() { ... }

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

_m(self): pass

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

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

เมื่อคำนึงถึงสิ่งนี้คำถามของฉันคือ:

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

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


10
ขออภัย Eric Lippert เป็นวันหยุด :)
Benjol

คำถามของคุณค่อนข้างยากที่จะเข้าใจ คุณเพียงแค่ถามว่ามีใครสามารถเข้าถึงสมาชิกส่วนตัวจากภายนอกหรือไม่?
Morgan Herlocker

1
คำถามที่เกี่ยวข้อง: programmers.stackexchange.com/questions/92380/…
281377

@ รหัส: ฉันสามารถบอกได้ว่าฉันไม่ได้แสดงความชัดเจนเพียงพอจากคำตอบบางส่วน คุณบอกได้ไหมว่าอะไรทำให้ยากที่จะเข้าใจเป็นพิเศษ ฉันจะพยายามอธิบาย
blubb

2
"มันเป็นเรื่องไร้สาระที่จะให้ข้อมูลในเวลารวบรวมและจากนั้นตรวจสอบได้เฉพาะตอนรันไทม์" - จริงเหรอ? ดีกว่าบอกให้ Microsoft ทราบเพราะนั่นเป็นสิ่งที่สำคัญของกรอบงาน. NET ปัจจุบันขึ้นอยู่กับ: การเลือกเข้า - ออกหรือไม่เข้าร่วมการพิมพ์แบบสแตติก ฉันไม่คิดว่านี่เป็นสิ่งที่คุณหมายถึงจริงๆ คำถามพูดซ้ำ ๆ เกี่ยวกับการตรวจสอบ "คงที่" กับ "ตรวจสอบ" แบบไดนามิก "แต่สิ่งเหล่านี้เป็นลักษณะของระบบประเภท สิ่งที่เป็นจริงที่เป็นปัญหาที่นี่เป็นที่รวบรวมเวลากับเวลาทำงานที่มีผลผูกพัน
Aaronaught

คำตอบ:


4

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

ฉันทำงานกับหลามและในระหว่างการเดินทางการเรียนรู้ของฉันฉันได้ยินว่าในหลามการประชุมอยู่ที่นั่นเพราะผู้คนที่ทำงานกับมันควรรู้ว่ามันมีความหมายอย่างไรและจะนำไปใช้อย่างไร ที่กล่าวว่าใน_m(self): passขีดล่างจะเตือนฉันไม่ให้ยุ่งกับฟิลด์นั้น แต่ทุกคนจะทำตามแบบแผนนั้นหรือไม่? ฉันทำงานกับ javascript และต้องบอกว่าไม่ทำงาน บางครั้งฉันต้องตรวจสอบปัญหาและเหตุผลก็คือบุคคลนั้นกำลังทำสิ่งที่เขาไม่ควรทำ ...

อ่านการสนทนานี้เกี่ยวกับงูใหญ่นำขีดล่าง

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

จากสิ่งที่ฉันพูดใช่

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

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

แก้ไข ใช่สะท้อนสามารถตรวจสอบความคิดเห็น

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


3
การสะท้อนกลับสามารถข้ามการป้องกันการเข้าถึงได้ สำหรับ Java และ C # ทั้งคู่สามารถเข้าถึงข้อมูลส่วนตัวได้
Mark H

ขอบคุณ! คำตอบที่นี่: stackoverflow.com/questions/1565734/ …อธิบาย!
wleao

1
วัฒนธรรมจาวาสคริปต์นั้นแตกต่างจากวัฒนธรรมงูใหญ่มาก Python มี pep-08 และนักพัฒนา python เกือบทั้งหมดจะปฏิบัติตามอนุสัญญาเหล่านี้ การละเมิด PEP-08 มักถูกพิจารณาว่าเป็นจุดบกพร่อง ดังนั้นฉันคิดว่าประสบการณ์ javascript / php / perl / ruby ​​แปลน้อยมากในประสบการณ์ python ในด้านนี้: _private ทำงานได้ดีมากใน python
Mike Korobov

1
ในภาษาการเขียนโปรแกรม (แต่ไม่ทั้งหมด) การซ่อนข้อมูลสามารถใช้เพื่อป้องกันรหัสที่เป็นศัตรูได้ การซ่อนข้อมูลไม่สามารถใช้เพื่อป้องกันผู้ใช้ที่เป็นศัตรู
Brian

2
@ ไมค์หากมีการละเมิด PEP-08 บ่อยครั้ง "ถือว่าเป็นข้อผิดพลาด" และไม่มีงูเหลือม dev ที่จะฝันไม่ทำตามอนุสัญญาคุณอาจบังคับใช้ภาษาเหล่านั้นด้วย! ทำไมคนไม่ทำงานเมื่อภาษาสามารถทำได้โดยอัตโนมัติ
Andres F.

27

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

กล่าวอีกนัยหนึ่งไม่อนุญาตให้คุณใช้งานเมื่อมันยังทำงานอยู่ทำให้คุณไม่สามารถใช้งานได้โดยไม่ตั้งใจเมื่อมันไม่ทำงานอีกต่อไป

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

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

ดังนั้นสรุปสั้น ๆ :

  • พับลิก: ใช้อย่างปลอดภัยกับอินสแตนซ์ของคลาสจุดประสงค์ของคลาสจะไม่เปลี่ยนแปลง
  • ได้รับการป้องกัน: เพื่อใช้เมื่อขยาย (สืบทอดมาจาก) คลาส - อาจเปลี่ยนแปลงหากการนำไปปฏิบัตินั้นมีการเปลี่ยนแปลงอย่างมาก
  • ส่วนตัว: อย่าแตะต้อง! อาจเปลี่ยนแปลงได้ตามความประสงค์เพื่อให้การใช้งานอินเทอร์เฟซที่คาดหวังดีขึ้น

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

3
@Simon Stelling - ไม่ฉันกำลังบอกว่าผู้ดำเนินการดั้งเดิมของชั้นเรียนที่ทำให้บางสิ่งบางอย่างเป็นส่วนตัวกำลังบอกคุณว่า "อย่าใช้สิ่งนี้พฤติกรรมใด ๆ ที่นี่อาจเปลี่ยนแปลงได้ในอนาคต" ตัวอย่างเช่นตัวแปรสมาชิกส่วนตัวของคลาสที่มีระยะห่างระหว่างจุดสองจุดในภายหลังอาจมีระยะห่างระหว่างจุดสองจุดกำลังสองด้วยเหตุผลด้านประสิทธิภาพ อะไรก็ตามที่จะต้องพึ่งพาพฤติกรรมเก่า ๆ ก็จะพังอย่างเงียบ ๆ
Joris Timmermans

1
@MadKeithV: แล้วคำหลักระดับภาษาพูดว่า "อย่าแตะเพราะ ... " แตกต่างจากการประชุมที่มีความหมายเหมือนกันอย่างไร เฉพาะคอมไพเลอร์บังคับใช้ แต่จากนั้นเรากลับไปที่การอภิปรายแบบคงที่และแบบไดนามิก

7
@Simon Stelling (และ Delnan) - สำหรับฉันมันเหมือนกับถามว่า "ตัว จำกัด เครื่องยนต์แตกต่างจากเครื่องหมาย จำกัด ความเร็วอย่างไร
Joris Timmermans

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

11

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


2
ฉันเห็นด้วยทั้งหมด แต่นี่ไม่ได้ตอบคำถามของฉัน ไม่ว่าฉันจะใช้_memberหรือprivate memberในชั้นเรียนของฉันนั้นมีความสำคัญน้อยมากตราบใดที่โปรแกรมเมอร์คนอื่นเข้าใจว่าเขาควรดูpublicหรือเป็นสมาชิกที่ไม่ใช่คำนำหน้าเท่านั้น
blubb

6
ใช่ แต่เอกสารสาธารณะของชั้นเรียนที่เขียนด้วยภาษาแบบไดนามิกไม่ได้ส่งชิ้นส่วนส่วนตัวทั้ง 36 ชิ้นมาที่คุณ (อย่างน้อยก็ไม่ใช่ตามค่าเริ่มต้น)

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

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

4

ผมขอแนะนำว่าสำหรับพื้นหลังคุณเริ่มต้นด้วยการอ่านเกี่ยวกับค่าคงที่ระดับ

ค่าคงที่คือการทำให้เรื่องสั้นสั้นเป็นข้อสันนิษฐานเกี่ยวกับสถานะของคลาสซึ่งควรจะเป็นจริงตลอดช่วงชีวิตของคลาส

ลองใช้ตัวอย่าง C # ที่ง่ายจริงๆ:

public class EmailAlert
{
    private readonly List<string> addresses = new List<string>();

    public void AddRecipient(string address)
    {
        if (!string.IsNullOrEmpty(address))
            addresses.Add(address);
    }

    public void Send(string message)
    {
        foreach (string address in addresses)
            SendTo(address, message);
    }

    // Details of SendTo not shown
}

เกิดอะไรขึ้นที่นี่?

  • สมาชิกaddressesจะเริ่มต้นในการก่อสร้างชั้นเรียน
  • เป็นส่วนตัวไม่มีอะไรจากภายนอกสามารถสัมผัสได้
  • เราได้สร้างมันขึ้นมาreadonlyดังนั้นไม่มีอะไรจากภายในสามารถสัมผัสได้หลังจากการก่อสร้าง (นี่ไม่ถูกต้อง / จำเป็นเสมอไป แต่มันมีประโยชน์ที่นี่)
  • ดังนั้นSendวิธีการที่สามารถทำให้สมมติฐานที่ว่าไม่เคยไปได้addresses nullไม่จำเป็นต้องทำการตรวจสอบนั้นเพราะไม่มีวิธีที่สามารถเปลี่ยนค่าได้

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

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

สำหรับคำถามอื่น ๆ เหล่านี้:

มันสามารถใช้เพื่อป้องกันสถานะลับของชั้นเรียนจากการถูกโจมตีหรือไม่?

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

การสะท้อนกลับสามารถแทนที่กลไกนี้ได้หรือไม่?

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

อะไรจะทำให้คุ้มค่าสำหรับคอมไพเลอร์ในการบังคับใช้การซ่อนข้อมูล?

คอมไพเลอร์แล้วไม่บังคับมัน ดังนั้นรันไทม์ใน. NET, Java และสภาพแวดล้อมอื่น ๆ - opcode ที่ใช้เรียกเมธอดจะไม่สำเร็จถ้าเมธอดนั้นเป็นแบบส่วนตัว วิธีเดียวในการ จำกัด นั้นต้องการรหัสที่เชื่อถือได้ / สูงและรหัสที่ยกระดับสามารถเขียนได้โดยตรงไปยังหน่วยความจำของโปรแกรม สามารถบังคับใช้ได้มากเท่าที่สามารถบังคับใช้ได้โดยไม่ต้องใช้ระบบปฏิบัติการที่กำหนดเอง


1
@Simon: เราจำเป็นต้องชี้แจง "ไม่รู้" ที่นี่ คำนำหน้าวิธีการที่_ระบุสัญญา แต่ไม่บังคับใช้ นั่นอาจทำให้ยากที่จะเพิกเฉยต่อสัญญา แต่ก็ไม่ได้ทำให้ยากที่จะทำลายสัญญาโดยเฉพาะอย่างยิ่งเมื่อเปรียบเทียบกับวิธีที่น่าเบื่อและมักจะ จำกัด เช่น Reflection การประชุมกล่าวว่า "คุณไม่ควรทำอย่างนี้" ตัวดัดแปลงการเข้าถึงกล่าวว่า "คุณไม่สามารถทำลายได้ " ฉันไม่ได้พยายามที่จะบอกว่าวิธีการหนึ่งดีกว่าวิธีอื่น - พวกเขาทั้งคู่นั้นดีขึ้นอยู่กับปรัชญาของคุณ แต่พวกเขาก็แตกต่างกันมาก
Aaronaught

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

3

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


3

การซ่อนข้อมูลวิวัฒนาการมาจากปรัชญาการออกแบบจากบนลงล่าง Python ถูกเรียกว่าภาษาจากล่างขึ้นบน

การซ่อนข้อมูลถูกบังคับใช้อย่างดีในระดับชั้นเรียนใน Java, C ++ และ C # ดังนั้นจึงไม่ใช่การประชุมในระดับนี้ มันง่ายมากที่จะทำให้คลาสเป็น "กล่องดำ" พร้อมส่วนต่อประสานสาธารณะและรายละเอียดที่ซ่อนอยู่ (ส่วนตัว)

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

แม้จะใช้ Java, C ++ หรือ C # ในบางจุดการซ่อนข้อมูลก็กลายเป็นเรื่องปกติ ไม่มีการควบคุมการเข้าถึงในระดับสูงสุดของนามธรรมที่เกี่ยวข้องกับสถาปัตยกรรมซอฟต์แวร์ที่ซับซ้อนมากขึ้น ตัวอย่างเช่นใน Java คุณสามารถค้นหาการใช้".internal" ชื่อแพ็คเกจ นี่เป็นรูปแบบการตั้งชื่ออย่างเดียวเพราะไม่ใช่เรื่องง่ายที่ข้อมูลประเภทนี้จะถูกบังคับใช้ผ่านการเข้าถึงแพคเกจเพียงอย่างเดียว

ภาษาหนึ่งที่พยายาม จำกัด การเข้าถึงอย่างเป็นทางการคือภาษาไอเฟล บทความนี้ชี้ให้เห็นถึงจุดอ่อนที่ซ่อนข้อมูลอื่น ๆ ของภาษาเช่น Java

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

เราต้องการให้โครงสร้างของระบบกำหนดโดยผู้ออกแบบอย่างชัดเจนก่อนที่จะเริ่มการเขียนโปรแกรมแทนที่จะตั้งใจใช้ข้อมูลของโปรแกรมเมอร์


1
+1 สำหรับเครื่องหมายคำพูด "การใช้ข้อมูลของโปรแกรมเมอร์" นั่นเป็นสิ่งที่แน่นอน (แม้ว่าคุณจะมีเครื่องหมายจุลภาคพิเศษในตอนท้าย)
jmoreno

2

Ruby และ PHP มีมันและบังคับใช้ตอนรันไทม์

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

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

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


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

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

1
@Simon: ทำไมต้องยุ่งกับอินเทอร์เฟซกับสิ่งที่คุณไม่ต้องการให้คนอื่นใช้ ฉันเกลียดที่ C ++ ต้องการให้สมาชิกทุกคนนำเสนอในการกำหนดชั้นเรียนในไฟล์ส่วนหัว (ฉันเข้าใจว่าทำไม) อินเทอร์เฟซสำหรับคนอื่นและไม่ควรทิ้งขยะในสิ่งที่ไม่สามารถใช้ได้
phkahler

1
@phkahler: pydocลบออก_prefixedMembersจากอินเทอร์เฟซ อินเทอร์เฟซที่ยุ่งเหยิงไม่มีส่วนเกี่ยวข้องกับการเลือกคำสำคัญที่คอมไพเลอร์ตรวจสอบ
blubb

2

การปรับเปลี่ยน Acces สามารถทำสิ่งที่การประชุมไม่สามารถทำได้แน่นอน

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

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

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

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


2

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

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

ถ้าฉันมีห้องสมุด

class C {
  public void foo() { ... }

  private void fooHelper() { /* lots of complex code */ }
}

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

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


อะไรจะทำให้คุ้มค่าสำหรับคอมไพเลอร์ในการบังคับใช้การซ่อนข้อมูล?

สังเกตด้านบนใน Java privateไม่ได้บังคับใช้โดยคอมไพเลอร์ แต่โดย Java ตรวจสอบ bytecode


การสะท้อนกลับสามารถแทนที่กลไกนี้ได้หรือไม่? อะไรจะทำให้คุ้มค่าสำหรับคอมไพเลอร์ในการบังคับใช้การซ่อนข้อมูล?

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

 public class C {
   private int i = 42;

   public class B {
     public void incr() { ++i; }
   }
 }

ตั้งแต่คลาสB(ชื่อจริง ๆC$B) ใช้iคอมไพเลอร์สร้างวิธีBการเข้าถึงสังเคราะห์ที่ช่วยให้การเข้าถึงC.iในทางที่จะผ่าน bytecode verifier น่าเสียดายเนื่องจากClassLoaderอนุญาตให้คุณสร้างคลาสจาก a byte[]จึงเป็นเรื่องง่ายที่จะได้รับสิทธิ์ส่วนตัวที่Cได้สัมผัสกับคลาสภายในโดยการสร้างคลาสใหม่ในCแพ็คเกจของซึ่งเป็นไปได้หากCไม่ได้ปิดผนึกขวด

การprivateบังคับใช้ที่เหมาะสมต้องการการประสานงานระหว่าง classloaders, ตัวตรวจสอบ bytecode และนโยบายความปลอดภัยที่สามารถป้องกันการเข้าถึงแบบไตร่ตรอง


มันสามารถใช้เพื่อป้องกันสถานะลับของชั้นเรียนจากการถูกโจมตีหรือไม่?

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

ภาษาที่มีความสามารถในวัตถุเช่นJoe-Eใช้การซ่อนข้อมูลและวิธีการอื่นเพื่อทำให้การย่อยสลายอย่างปลอดภัยเป็นไปได้:

Joe-E เป็นส่วนย่อยของภาษาการเขียนโปรแกรม Java ที่ออกแบบมาเพื่อสนับสนุนการเขียนโปรแกรมที่ปลอดภัยตามระเบียบวินัยความสามารถของวัตถุ Joe-E มีวัตถุประสงค์เพื่ออำนวยความสะดวกในการสร้างระบบความปลอดภัยเช่นเดียวกับการอำนวยความสะดวกในการตรวจสอบความปลอดภัยของระบบที่สร้างขึ้นใน Joe-E

กระดาษที่เชื่อมโยงจากหน้านั้นเป็นตัวอย่างของการprivateบังคับใช้ที่ทำให้เกิดการสลายตัวที่ปลอดภัย

ให้การห่อหุ้มที่ปลอดภัย

รูปที่ 1. เครื่องมือช่วยการบันทึกข้อมูลแบบผนวกเท่านั้น

public final class Log {
  private final StringBuilder content;
  public Log() {
    content = new StringBuilder();
  }
  public void write(String s) {
    content.append(s);
  }
}

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


1

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


1

โดยการป้องกันส่วนหนึ่งของภาษาคุณจะได้รับสิ่ง: การรับรองที่สมเหตุสมผล

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

ตอนนี้มีวิธีที่จะได้รับการป้องกันวากยสัมพันธ์? แน่นอน; ภาษาส่วนใหญ่มีพวกเขา ใน C ++ คุณสามารถส่งคลาสไปยังประเภทอื่น ๆ และกระตุ้นที่บิต ใน Java และ C # คุณสามารถสะท้อนตนเองได้ และอื่น ๆ

แต่การทำเช่นนี้เป็นเรื่องยาก เห็นได้ชัดว่าคุณกำลังทำสิ่งที่คุณไม่ควรทำ คุณไม่สามารถทำได้โดยไม่ตั้งใจ (นอกเหนือจาก wild write ใน C ++) คุณต้องคิดด้วยความเต็มใจว่า "ฉันจะไปแตะบางสิ่งที่ฉันบอกไม่ให้คอมไพเลอร์" คุณเต็มใจที่จะต้องทำบางสิ่งบางอย่างที่ไม่สมควร

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

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

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

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

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

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