ทำไมสมาชิกส่วนตัวสามารถเข้าถึงได้ในวิธีการคงที่?


25

ต่อไปนี้เป็นรหัสหลอกฉันลองใน Java และ PHP และทั้งสองทำงาน:

class Test { 

    private int a = 5;

    public static function do_test(){
        var t = new Test();
        t.a = 1;
        print t.a // 1
    }

}

Test::do_test();

ทำไมคุณสามารถทำสิ่งนี้ในกระบวนทัศน์ OOP และการใช้งานของมันคืออะไร?


6
ทำไมถึงไม่เป็นเช่นนั้น? ใน Java ส่วนตัวสมาชิกไม่ได้ส่วนตัวถึงตัวอย่างเช่น แต่ส่วนตัวถึงแฟ้มแหล่งที่มา สิ่งแรกที่คุณควรคำนึงถึงคือequalsต้องตรวจสอบช่องส่วนตัวของอินสแตนซ์อื่น (โพสต์แสดงความคิดเห็นเป็นเช่นนี้เป็นระยะสั้นและไม่มีอะไรเกี่ยวกับ OOP-Ness ของวิธีการนี้)
Ordous

2
โปรดทราบว่าวิธีการคงที่ไม่มีthis, ดังนั้นวัตถุเฉพาะของคลาสของตัวเองที่พวกเขาสามารถรับได้เป็นสิ่งที่พวกเขาสร้างขึ้นเอง (หรือที่ผ่านมาเป็นพารามิเตอร์) ดังนั้นหากคุณพิจารณาว่านี่เป็นการละเมิดการห่อหุ้มหรือช่องโหว่ความปลอดภัยไม่ใช่ว่ามันเป็นช่องโหว่ที่ใหญ่มากและอาจไม่คุ้มค่าที่จะเสียบ
Kilian Foth

4
ไม่แน่ใจว่าทำไมสิ่งนี้ถึงได้ลงคะแนน คำถามอาจไม่สำคัญ (ish) แต่ OP พบปัญหาในการทดสอบพฤติกรรมในสองภาษาก่อนถาม นั่นเป็นความพยายามมากกว่าที่เรามักจะเห็นจากผู้มาใหม่
yannis

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

1
ในความเป็นจริงเมื่อฉันถาม colegues ของฉันทั้งหมดกล่าวว่าเป็นไปไม่ได้ นั่นเป็นเหตุผลที่ฉันไม่ได้คิดว่ามันสำคัญ
เบ็

คำตอบ:


17

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

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

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

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

interface ITest {
     public int getA();
}

class Test implements ITest { 

    private int a = 5;

    public int getA() { return a; } // implementation of method declared in interface

    public static void main(){
        ITest t = new Test();
        t.a = 1; // syntax error: Interface ITest has no "a"
        System.out.println(t.getA()); // calls Test.getA, visible because ITest declares it
    }

}

คุณนึกถึงสถานการณ์เมื่อรูปแบบข้อมูลคลาสส่วนตัวมีประโยชน์ได้หรือไม่? ฉันเองใช้คลาสภายในเฉพาะใน GUI เช่นการตั้งค่า (สวิง ฯลฯ ) หรือคลาสสแตติกภายในในแบบฝึกหัดการเข้ารหัสเนื่องจากฉันไม่ต้องการให้แบบฝึกหัดเพื่อขยายไฟล์ต้นฉบับหลาย ๆ ไฟล์
InformedA

1
การซ่อน internals ของคลาสจากอินสแตนซ์อื่นจะทำให้คลาสข้อดีหนึ่งข้อมีอินเทอร์เฟซโดยไม่ต้องแลกเปลี่ยนอะไรเลย วิธีที่ง่ายและยืดหยุ่นกว่าคือการใช้อินเทอร์เฟซ
Doval

3

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

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

ข้อดีของการไม่อนุญาตการเข้าถึงดังกล่าว (เช่นในกรณีใน Microsoft Common Object Model (COM)) คือการอนุญาตให้ใช้โค้ดภายนอกเพื่อรักษาคลาสเป็นอินเทอร์เฟซ ถ้าชั้นImmutableMatrixมีส่วนตัวหรือการคุ้มครองdouble[][]ข้อมูลสนับสนุนและถ้ารหัสภายในชั้นตรวจสอบอาร์เรย์การสนับสนุนจากกรณีอื่น ๆ แล้วมันจะเป็นไปไม่ได้ที่จะกำหนดระดับที่ไม่ใช่อาเรย์ได้รับการสนับสนุน (เช่นZeroMatrix, IdentityMatrix) ซึ่งรหัสนอกสามารถใช้เป็น เป็นImmutable2dMatrixคลาสที่ไม่ต้องรวมฟิลด์สำรอง หากไม่มีสิ่งใดภายในImmutable2dMatrixใช้สมาชิกส่วนตัวของอินสแตนซ์อื่นนอกเหนือthisจากนั้นก็เป็นไปได้ที่จะเปลี่ยนชื่อคลาสเป็นImmutableArrayBackedMatrixและกำหนดImmutableMatrixคลาสนามธรรมใหม่ซึ่งอาจมีคลาสที่ไม่ได้ImmutableArrayBackedMatrixรับการสนับสนุนอาเรย์ดังกล่าวข้างต้นเป็นชนิดย่อย

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


2

Java ไม่ได้เป็นภาษาเชิงวัตถุ แต่เป็นภาษาที่ใช้ในคลาส - คลาสจะเป็นตัวกำหนดการดำเนินการและการเข้าถึงพฤติกรรมแทนที่จะเป็นอินสแตนซ์

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

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

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

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