คุณควรใช้ตัวแปรสมาชิกที่มีการป้องกันหรือไม่? ข้อดีคืออะไรและปัญหานี้ทำให้เกิดอะไรได้บ้าง?
คุณควรใช้ตัวแปรสมาชิกที่มีการป้องกันหรือไม่? ข้อดีคืออะไรและปัญหานี้ทำให้เกิดอะไรได้บ้าง?
คำตอบ:
คุณควรใช้ตัวแปรสมาชิกที่มีการป้องกันหรือไม่?
ขึ้นอยู่กับว่าคุณจู้จี้จุกจิกแค่ไหนในการซ่อนสถานะ
หากนักพัฒนาเข้ามาและแบ่งคลาสย่อยของคุณพวกเขาอาจทำให้มันยุ่งเพราะพวกเขาไม่เข้าใจมันทั้งหมด สำหรับสมาชิกส่วนตัวนอกเหนือจากอินเทอร์เฟซสาธารณะพวกเขาไม่สามารถเห็นรายละเอียดการใช้งานที่เฉพาะเจาะจงว่าสิ่งต่างๆกำลังดำเนินการอย่างไรซึ่งทำให้คุณมีความยืดหยุ่นในการเปลี่ยนแปลงในภายหลัง
โดยทั่วไปหากมีบางสิ่งที่ไม่ได้จงใจคิดว่าเป็นสาธารณะฉันจะทำให้เป็นแบบส่วนตัว
หากสถานการณ์เกิดขึ้นที่ฉันต้องการเข้าถึงตัวแปรส่วนตัวหรือวิธีการจากคลาสที่ได้รับมาฉันจะเปลี่ยนจากไพรเวตเป็นแบบป้องกัน
สิ่งนี้แทบจะไม่เคยเกิดขึ้นเลย - ฉันไม่ใช่แฟนพันธุ์แท้เลยเพราะมันไม่ใช่วิธีที่ดีอย่างยิ่งในการจำลองสถานการณ์ส่วนใหญ่ ไม่ว่าจะในอัตราใดก็ตามไม่ต้องกังวล
ฉันว่านี่เป็นวิธีที่ดี (และอาจเป็นวิธีที่ดีที่สุดในการดำเนินการนี้) สำหรับนักพัฒนาซอฟต์แวร์ส่วนใหญ่
ข้อเท็จจริงง่ายๆของเรื่องนี้คือหากนักพัฒนารายอื่นเข้ามาในอีกหนึ่งปีต่อมาและตัดสินใจว่าพวกเขาต้องการเข้าถึงตัวแปรสมาชิกส่วนตัวของคุณพวกเขาก็จะแก้ไขโค้ดเปลี่ยนเป็นแบบป้องกันและดำเนินธุรกิจต่อไป
ข้อยกเว้นที่แท้จริงเพียงประการเดียวคือหากคุณอยู่ในธุรกิจการจัดส่ง binary dll ในรูปแบบ black-box ไปยังบุคคลที่สาม สิ่งนี้ประกอบด้วย Microsoft ผู้จำหน่าย 'Custom DataGrid Control' เหล่านั้นและอาจมีแอพขนาดใหญ่อื่น ๆ อีกสองสามตัวที่มาพร้อมกับไลบรารีความสามารถในการขยาย ถ้าคุณไม่อยู่ในหมวดหมู่นั้นก็ไม่คุ้มที่จะเสียเวลา / ความพยายามมากังวลกับเรื่องแบบนี้
ความรู้สึกทั่วไปในปัจจุบันคือทำให้เกิดการมีเพศสัมพันธ์ที่ไม่เหมาะสมระหว่างชั้นเรียนที่ได้รับและฐานของพวกเขา
พวกเขาไม่มีข้อได้เปรียบเป็นพิเศษเหนือวิธีการ / คุณสมบัติที่ได้รับการป้องกัน (ในบางครั้งพวกเขาอาจมีข้อได้เปรียบด้านประสิทธิภาพเล็กน้อย) และยังถูกนำมาใช้มากขึ้นในยุคที่การสืบทอดอย่างลึกซึ้งเป็นไปในรูปแบบที่ไม่ได้อยู่ในขณะนี้
no particular advantage over protected methods/properties
จะเป็นno particular advantage over *private* methods/properties
?
super
โครงสร้างเพื่อเรียกตัวสร้างหลัก จากนั้นจะดูแลการเริ่มต้นตัวแปรสถานะส่วนตัวในคลาสแม่
ปัญหาสำคัญสำหรับผมคือว่าเมื่อคุณทำให้ตัวแปรที่มีการป้องกันแล้วคุณไม่สามารถอนุญาตให้มีวิธีการใด ๆ ในชั้นเรียนของคุณที่จะพึ่งพาค่าของมันที่อยู่ในช่วงได้เนื่องจากคลาสย่อยสามารถทำให้มันอยู่นอกช่วงได้เสมอ
ตัวอย่างเช่นถ้าฉันมีคลาสที่กำหนดความกว้างและความสูงของออบเจ็กต์ที่แสดงผลได้และฉันทำให้ตัวแปรเหล่านั้นได้รับการป้องกันฉันก็ไม่สามารถตั้งสมมติฐานใด ๆ เกิน (เช่น) อัตราส่วนภาพได้
วิกฤตฉันไม่สามารถตั้งสมมติฐานเหล่านั้นได้ทุกเมื่อนับจากช่วงเวลาที่โค้ดถูกปล่อยออกมาเป็นไลบรารีเนื่องจากแม้ว่าฉันจะอัปเดตตัวตั้งค่าเพื่อรักษาอัตราส่วน แต่ฉันไม่สามารถรับประกันได้ว่าตัวแปรจะถูกตั้งค่าผ่าน setters หรือเข้าถึงผ่านทาง getters ในรหัสที่มีอยู่
คลาสย่อยของคลาสของฉันไม่สามารถเลือกที่จะรับประกันได้เนื่องจากไม่สามารถบังคับใช้ค่าตัวแปรได้แม้ว่านั่นจะเป็นจุดรวมของคลาสย่อยก็ตามก็ตาม
ตัวอย่างเช่น:
ด้วยการ จำกัด ตัวแปรให้เป็นส่วนตัวฉันจึงสามารถบังคับใช้พฤติกรรมที่ฉันต้องการผ่าน setters หรือ getters
โดยทั่วไปฉันจะเก็บตัวแปรสมาชิกที่ได้รับการป้องกันของคุณไว้ในกรณีที่หายากซึ่งคุณสามารถควบคุมโค้ดที่ใช้งานได้ทั้งหมดเช่นกัน หากคุณกำลังสร้าง API สาธารณะฉันจะบอกว่าอย่าเลย ด้านล่างนี้เราจะอ้างถึงตัวแปรสมาชิกว่าเป็น "คุณสมบัติ" ของวัตถุ
นี่คือสิ่งที่ superclass ของคุณไม่สามารถทำได้หลังจากสร้างตัวแปรสมาชิกที่ได้รับการป้องกันแทนที่จะเป็น private-with-accessors:
เกียจคร้านสร้างมูลค่าทันทีเมื่อกำลังอ่านคุณสมบัติ หากคุณเพิ่มเมธอด getter ที่ได้รับการป้องกันคุณสามารถสร้างมูลค่าและส่งคืนได้อย่างเกียจคร้าน
ทราบเมื่อมีการแก้ไขหรือลบคุณสมบัติ สิ่งนี้สามารถแนะนำจุดบกพร่องเมื่อซูเปอร์คลาสตั้งสมมติฐานเกี่ยวกับสถานะของตัวแปรนั้น การสร้างเมธอด setter ที่มีการป้องกันสำหรับตัวแปรจะช่วยให้สามารถควบคุมได้
ตั้งค่าเบรกพอยต์หรือเพิ่มเอาต์พุตการดีบักเมื่อมีการอ่านหรือเขียนตัวแปร
เปลี่ยนชื่อตัวแปรสมาชิกโดยไม่ต้องค้นหารหัสทั้งหมดที่อาจใช้
โดยทั่วไปฉันคิดว่าเป็นกรณีที่หายากที่ฉันแนะนำให้สร้างตัวแปรสมาชิกที่ได้รับการป้องกัน คุณควรใช้เวลาไม่กี่นาทีในการเปิดเผยคุณสมบัติผ่าน getters / setters มากกว่าชั่วโมงต่อมาในการติดตามข้อบกพร่องในโค้ดอื่น ๆ ที่แก้ไขตัวแปรที่ได้รับการป้องกัน ไม่เพียงแค่นั้น แต่คุณยังได้รับการประกันจากการเพิ่มฟังก์ชันในอนาคต (เช่นการโหลดแบบขี้เกียจ) โดยไม่ทำลายโค้ดที่อ้างอิง ทำช้ากว่าทำตอนนี้ยาก
ในระดับการออกแบบอาจเหมาะสมที่จะใช้คุณสมบัติที่มีการป้องกัน แต่สำหรับการนำไปใช้งานฉันไม่เห็นข้อได้เปรียบในการแมปสิ่งนี้กับตัวแปรสมาชิกที่ได้รับการป้องกันแทนที่จะเป็นวิธีการเข้าถึง / ตัวเปลี่ยน
ตัวแปรสมาชิกที่ได้รับการป้องกันมีข้อเสียอย่างมีนัยสำคัญเนื่องจากอนุญาตให้รหัสไคลเอ็นต์ (คลาสย่อย) เข้าถึงสถานะภายในของคลาสคลาสพื้นฐานได้อย่างมีประสิทธิภาพ สิ่งนี้ป้องกันไม่ให้คลาสพื้นฐานคงค่าคงที่อย่างมีประสิทธิภาพ
ด้วยเหตุผลเดียวกันตัวแปรสมาชิกที่ได้รับการป้องกันยังทำให้การเขียนโค้ดแบบมัลติเธรดที่ปลอดภัยทำได้ยากขึ้นอย่างมากเว้นแต่ค่าคงที่ที่รับประกันหรือถูก จำกัด ไว้ที่เธรดเดียว
วิธีการของ Accessor / mutator ช่วยเพิ่มความเสถียรของ API และความยืดหยุ่นในการใช้งานภายใต้การบำรุงรักษา
นอกจากนี้หากคุณเป็นคนเจ้าระเบียบ OO วัตถุจะทำงานร่วมกัน / สื่อสารโดยการส่งข้อความไม่ใช่สถานะการอ่าน / การตั้งค่า
ในทางกลับกันพวกเขามีข้อดีน้อยมาก ฉันไม่จำเป็นต้องลบออกจากรหัสของคนอื่น แต่ฉันไม่ได้ใช้มันด้วยตัวเอง
โดยส่วนใหญ่แล้วการใช้แบบป้องกันจะเป็นอันตรายเนื่องจากคุณทำลายส่วนห่อหุ้มของชั้นเรียนของคุณซึ่งอาจถูกทำลายลงด้วยคลาสที่ได้รับการออกแบบมาไม่ดี
แต่ฉันมีตัวอย่างที่ดีอย่างหนึ่ง: สมมติว่าคุณสามารถใช้คอนเทนเนอร์ทั่วไปได้ มีการใช้งานภายในและตัวเข้าถึงภายใน แต่คุณต้องเสนอการเข้าถึงข้อมูลแบบสาธารณะอย่างน้อย 3 รายการ ได้แก่ map, hash_map, vector-like จากนั้นคุณมีสิ่งที่ต้องการ:
template <typename T, typename TContainer>
class Base
{
// etc.
protected
TContainer container ;
}
template <typename Key, typename T>
class DerivedMap : public Base<T, std::map<Key, T> > { /* etc. */ }
template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }
template <typename T>
class DerivedVector : public Base<T, std::vector<T> > { /* etc. */ }
ฉันใช้รหัสประเภทนี้น้อยกว่าหนึ่งเดือนที่ผ่านมา (ดังนั้นรหัสจึงมาจากหน่วยความจำ) หลังจากคิดบางอย่างฉันเชื่อว่าในขณะที่ Base container ทั่วไปควรเป็นคลาสนามธรรมแม้ว่ามันจะอยู่ได้ค่อนข้างดีเพราะการใช้ Base โดยตรงจะทำให้เจ็บปวด แต่ก็ควรห้าม
สรุปดังนั้นคุณได้ป้องกันข้อมูลที่ใช้โดยคลาสที่ได้รับ ถึงกระนั้นเราต้องคำนึงถึงข้อเท็จจริงที่ว่าคลาสฐานควรเป็นนามธรรม
protected
public
ฉันยินดีที่จะพิสูจน์ว่าผิด สิ่งที่คุณต้องทำคือเขียนชั้นเรียนโดยมีสมาชิกที่ได้รับการคุ้มครองและห้ามไม่ให้ฉันแก้ไขชั้นเรียน เห็นได้ชัดว่าคลาสจะต้องไม่สิ้นสุดเนื่องจากจุดรวมของการใช้การป้องกันคือการสืบทอด ไม่ว่าจะมีอะไรบางอย่างห่อหุ้มหรือไม่ก็ตาม ไม่มีสถานะระหว่างกัน
ในระยะสั้นใช่
ตัวแปรสมาชิกที่ได้รับการป้องกันอนุญาตให้เข้าถึงตัวแปรจากคลาสย่อยและคลาสใด ๆ ในแพ็กเกจเดียวกัน สิ่งนี้มีประโยชน์อย่างมากโดยเฉพาะข้อมูลแบบอ่านอย่างเดียว อย่างไรก็ตามฉันไม่เชื่อว่าสิ่งเหล่านี้จำเป็นเพราะการใช้ตัวแปรสมาชิกที่ได้รับการป้องกันใด ๆ สามารถจำลองแบบได้โดยใช้ตัวแปรสมาชิกส่วนตัวและตัวรับและตัวตั้งค่า
สำหรับเร็กคอร์ดภายใต้ Item 24 ของ "C ++ พิเศษ" ในเชิงอรรถข้อหนึ่งซัทเทอร์ไป "คุณจะไม่เขียนคลาสที่มีตัวแปรสาธารณะหรือสมาชิกที่ได้รับการป้องกันใช่ไหม (โดยไม่คำนึงถึงตัวอย่างที่ไม่ดีที่กำหนดโดยห้องสมุดบางแห่ง .)”
สำหรับข้อมูลโดยละเอียดเกี่ยวกับตัวปรับการเข้าถึง. Net ไปที่นี่
ไม่มีข้อดีหรือข้อเสียที่แท้จริงสำหรับตัวแปรสมาชิกที่ได้รับการป้องกันเป็นคำถามเกี่ยวกับสิ่งที่คุณต้องการในสถานการณ์เฉพาะของคุณ โดยทั่วไปเป็นที่ยอมรับในการประกาศตัวแปรสมาชิกเป็นส่วนตัวและเปิดใช้งานการเข้าถึงภายนอกผ่านคุณสมบัติ นอกจากนี้เครื่องมือบางอย่าง (เช่น O / R mappers บางตัว) คาดว่าข้อมูลออบเจ็กต์จะแสดงโดยคุณสมบัติและไม่รู้จักตัวแปรสาธารณะหรือสมาชิกที่ได้รับการป้องกัน แต่ถ้าคุณรู้ว่าคุณต้องการให้คลาสย่อยของคุณ (และเฉพาะคลาสย่อยของคุณ) เข้าถึงตัวแปรบางตัวก็ไม่มีเหตุผลที่จะไม่ประกาศว่าได้รับการป้องกัน