หากตัวแปรมีทะเยอทะยานและผู้ตั้งค่ามันควรเป็นสาธารณะหรือไม่?


23

ฉันมีคลาสที่มีตัวแปรที่เป็นส่วนตัวและคลาสนั้นมีทะเยอทะยานและ setter สำหรับตัวแปรนั้น ทำไมไม่ทำให้ตัวแปรนั้นเป็นแบบสาธารณะ

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

void my_class::set_variable(int x){
   /* Some operation like updating a log */
   this->variable = x;
}

10
Getters และ setters มีไว้สำหรับป้องกัน สักวันหนึ่งคุณอาจต้องการทำthis->variable = x + 5หรือเรียกใช้UpdateStatisticsฟังก์ชันในตัวตั้งค่าและในกรณีเหล่านั้นclassinstancea->variable = 5จะทำให้เกิดปัญหา
Coder

1
อีกตัวอย่างหนึ่งคือ: set_inch, set_centimeter, get_inch, get_centimeter, กับการกระทำบางอย่างเหมือนผี

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

7
@Coder: คุณสามารถเพิ่มทะเยอทะยานของคุณ / setter เมื่อความต้องการที่เกิดขึ้น? หรือนี่คือสิ่งที่คุณไม่สามารถทำได้อย่างง่ายดายใน C ++ (ประสบการณ์ของฉันส่วนใหญ่เป็น Delphi)?
Marjan Venema

คำถามนี้: programmers.stackexchange.com/questions/21802/…อาจเป็นที่สนใจ
Winston Ewert

คำตอบ:


21

คุณเคยได้ยินเกี่ยวกับทรัพย์สินหรือไม่?

สถานที่ให้บริการเป็นเขตข้อมูลที่มี accessors "ในตัว" (getters และ setters) ตัวอย่างเช่น Java ไม่มีคุณสมบัติ แต่แนะนำให้เขียนตัวรับและตัวตั้งค่าลงในฟิลด์ส่วนตัว C # มีคุณสมบัติ

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

แต่ตัวอย่างเช่นหากคุณมีเขตข้อมูลบูลีนที่เรียกว่าตาย คุณควรคิดให้รอบคอบก่อนประกาศ setDead และ isDead คุณควรเขียน accessors ที่มนุษย์สามารถอ่านได้เช่น kill () แทนที่จะเป็น setDead

อย่างไรก็ตามมีเฟรมเวิร์กมากมายที่คิดว่าคุณกำลังติดตามการตั้งชื่อ JavaBean (พูดถึง Java ที่นี่) ดังนั้นในกรณีเหล่านี้คุณควรประกาศ getters และ setters ทั้งหมดหลังจากการตั้งชื่อแบบ Convetion


2
ในที่สุด "มนุษย์ที่อ่านได้" ในที่สุดก็เป็นข้อโต้แย้งว่าฉันสามารถ "คร่ำครวญ" ข้อโต้แย้งอื่น ๆ ทั้งหมดที่ฉันมักจะได้ยินเป็นการเรียงลำดับของการพิสูจน์ในอนาคตที่ได้รับการแก้ไขได้อย่างง่ายดายเมื่อจำเป็น ...
Marjan Venema

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

2
คุณยกประเด็นที่น่าอัศจรรย์ kill ไม่ใช่ชุด / รับมันเป็นการกระทำ มันซ่อนการใช้งานอย่างสมบูรณ์ - เป็นวิธีที่คุณใช้รหัส OO ในทางกลับกันคุณสมบัติเช่นเดียวกับโง่เหมือน setters / getters - stupider ถึงแม้ว่าไวยากรณ์ที่ง่ายช่วยให้ผู้คนสามารถเพิ่มพวกเขาไปยังตัวแปรเมื่อพวกเขาไม่ต้องการ (OO-Furbar รอให้เกิดขึ้น) ใครจะคิดว่าใช้ kill () เมื่อพวกเขาสามารถเพิ่มแท็ก "คุณสมบัติ" ในการตั้งค่าสถานะที่ตายแล้ว
Bill K

1
คำถามถูกแท็กคำถาม C ++ C ++ ไม่รองรับคุณสมบัติดังนั้นทำไมคุณถึงต้องโพสต์สิ่งนี้
Thomas Eding

1
@ThomasEding: C ++ ค่อนข้างมีเอกลักษณ์ในการมีโอเปอเรเตอร์การมอบหมาย แม้ว่า C ++ จะไม่ใช้คำว่า "property" ในลักษณะเดียวกับภาษาอย่าง C # หรือ VB.NET แต่แนวคิดก็ยังคงอยู่ มีความเป็นไปได้ใน C ++ ที่จะใช้ตัวดำเนินการโอเวอร์โหลดเพื่อที่foo.bar = biz.baz+5จะเรียกใช้ฟังก์ชันbizเพื่อประเมินค่าbazจากนั้นเพิ่มค่าห้าค่าและเรียกใช้ฟังก์ชันfooเพื่อตั้งค่าbarผลลัพธ์ โอเวอร์โหลดดังกล่าวไม่ได้เรียกว่า "คุณสมบัติ" แต่สามารถตอบสนองวัตถุประสงค์เดียวกันได้
supercat

25

นี่ไม่ใช่ความเห็นยอดนิยม แต่ฉันไม่เห็นความแตกต่างมากนัก

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

ในทฤษฎีทฤษฎีสุนัขเซทเทอร์และทะเยอทะยานหรือทรัพย์สินเพิ่มสถานที่เพื่อดำเนินการบางอย่างเมื่อตัวแปรถูกตั้งค่า / รับและในทางทฤษฎีพวกเขาแยกรหัสของคุณออกจากการเปลี่ยนแปลง

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

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

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

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

โดยวิธีการที่ฉันไม่เคยสนับสนุนตัวแปรสาธารณะ - ฉันกำลังบอกว่า setters และ getters (และแม้กระทั่งคุณสมบัติ) อยู่ใกล้เกินไปที่จะเป็นตัวแปรสาธารณะแล้ว

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


สิ่งหนึ่งที่ดีนอกเหนือจากคำตอบอื่น ๆ ที่นี่เกี่ยวกับ getter setter คือ: ฉันสามารถเพิ่มการตรวจสอบ / การแปลงภายในมันเพราะตัวแปรส่วนตัวที่เกิดขึ้นจริงถือว่ามันคุ้มค่า
WinW

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

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

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

1
สถานะที่เปลี่ยนแปลงไม่ได้เป็นที่ยอมรับ แต่คุณควรขอให้วัตถุของคุณทำอะไรบางอย่างให้กับคุณไม่ทำอะไรกับวัตถุของคุณ - ดังนั้นเมื่อคุณเปลี่ยนสถานะของคุณเซ็ตเตอร์ไม่ใช่วิธีที่ดีในการลองเขียนวิธีธุรกิจด้วยตรรกะ ในมันแทน ตัวอย่างเช่น "move (Up5) มากกว่า setZLocation (getZLocation () + 5)"
Bill K

8

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

ตัวอย่างเช่นหากวัตถุ 3 ชิ้นเรียกร้องfoo.barให้รับค่าของแถบและคุณตัดสินใจที่จะเปลี่ยนชื่อของแถบไปไกลคุณมีปัญหาในมือของคุณ หากวัตถุที่เรียกว่าfoo.barคุณจะต้องเปลี่ยนชั้นเรียนทั้งหมดที่มีนี้ หากใช้ setter / getter คุณจะไม่มีอะไรเปลี่ยนแปลง ความเป็นไปได้อีกอย่างก็คือการเปลี่ยนประเภทของตัวแปรซึ่งในกรณีนี้เพียงแค่เพิ่มโค้ดการแปลงบางส่วนลงใน getter / setter และคุณก็สบายดี


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

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

@ marjan แน่นอนว่าคุณสามารถแนะนำ getter / setter ได้ทุกเมื่อในภายหลัง ปัญหาคือคุณต้องย้อนกลับและเปลี่ยนรหัสทั้งหมดที่ใช้เขตข้อมูลสาธารณะแทน getter / setter ฉันไม่แน่ใจว่าฉันเป็นคนที่สับสนหรือคุณเป็น 0.o
Pete

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

1
การดำเนินการ refactor นั้นฟรีทั้งสองทางดังนั้นฉันจึงไม่ซื้อมัน นอกจากนี้ยังเป็นรูปแบบที่แย่มากในการใช้ setter หรือทะเยอทะยานนอกเสียจากว่าคุณจะต้องการมันในที่สุดคุณจะได้คนที่ไม่เข้าใจแนวคิดเพียงแค่เพิ่ม setters และ getters ให้กับสมาชิกโดยอัตโนมัติแทนเมื่อจำเป็น ของความชั่วร้ายตลอด codebase ของคุณ
Bill K

5

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

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


ขอบคุณมาก! ฉันกำลังคิดกรณีเดียวกับที่คุณพูดถึง ถ้าผมต้องการตัวแปรที่จะมีเนื้อหาใน [0,1] ฉันควรตรวจสอบค่าที่เข้ามาในหมามัน :)
Oni

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

หากคุณใช้ C # ให้ใช้คุณสมบัติคุณสามารถใช้คุณสมบัติเพื่อตั้งค่าอินสแตนซ์ส่วนตัวหากจำเป็นขึ้นอยู่กับตรรกะบางอย่างในส่วนของตัวตั้งค่าคุณสมบัติ
developerdoug

2

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

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

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


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

1

ก่อนอื่นให้ชัดเจนในกระบวนทัศน์

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

getter / setter มีประโยชน์ที่ไหน?

getters / Setters มีประโยชน์ในโครงสร้างข้อมูลหรือไม่ เลขที่

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

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

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

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

getters / setters มีประโยชน์ใน Objects หรือไม่? เลขที่

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

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

The Edge Case

มีสองสถานการณ์คือประชาชนทะเยอทะยาน / สุนัขจิ้งจอกทำให้รู้สึก

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

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

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

interface Container<T>
{
    typedef ...T... TRef; //<somehow make TRef to be a reference or pointer to the memory location of T
    TRef item(int index); 
}

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

คุณสามารถปรับปรุง / แก้ไข getters / setter โดยใช้ copy-semantics เท่านั้นหรือใช้ proxy:

interface Proxy<T>
{
     operator T(); //<returns a copy
     ... operator ->(); //<permits a function call to be forwarded to an element
     Proxy<T> operator=(T); //< permits the specific element to be replaced/assigned by another T.
}

interface Container<T>
{
     Proxy<T> item(int index);
     T item(int index); //<When T is a copy of the original value.
     void item(int index, T new_value); //<where new_value is used to replace the old value
}

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

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

Getters ส่วนตัว / Setters

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

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

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

Getters / Setters ที่ได้รับความคุ้มครอง

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


0

จากประสบการณ์ C ++, setter / getter มีประโยชน์สำหรับ 2 สถานการณ์:

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

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

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