ทำไมชั้นเรียนควรเป็นอย่างอื่นนอกจาก“ นามธรรม” หรือ“ สุดท้าย / ปิดผนึก”


29

หลังจาก 10 ปีของการเขียนโปรแกรม java / c # ฉันพบว่าตัวเองกำลังสร้าง:

  • คลาสนามธรรม : สัญญาที่ไม่ได้มีไว้เพื่อสร้างอินสแตนซ์
  • ชั้นเรียนสุดท้าย / ปิดผนึก : การนำไปปฏิบัติไม่ได้หมายถึงการใช้เป็นคลาสพื้นฐานให้กับสิ่งอื่น

ฉันไม่สามารถนึกถึงสถานการณ์ใด ๆ ที่ "คลาส" ง่าย ๆ (เช่นไม่เป็นนามธรรมหรือสุดท้าย / ปิดผนึก) จะเป็น "การเขียนโปรแกรมที่ชาญฉลาด"

ทำไมชั้นเรียนควรเป็นอย่างอื่นนอกจาก "นามธรรม" หรือ "ขั้นสุดท้าย / ปิดผนึก"

แก้ไข

บทความที่ดีนี้อธิบายถึงความกังวลของฉันได้ดีกว่าที่ฉันสามารถทำได้


21
เพราะมันถูกเรียกว่าOpen/Closed principleไม่ใช่Closed Principle.
StuperUser

2
คุณเป็นคนประเภทใดที่เขียนอย่างมืออาชีพ มันอาจมีอิทธิพลต่อความคิดเห็นของคุณในเรื่องนี้ได้เป็นอย่างดี

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

4
@ SuperUser: นั่นไม่ใช่เหตุผลมันเป็นคำพูดซ้ำซาก สหกรณ์ไม่ได้ถามว่าคำพูดซ้ำซากคือเขาถามว่าทำไม หากไม่มีเหตุผลเบื้องหลังหลักการก็ไม่มีเหตุผลที่จะต้องใส่ใจกับมัน
Michael Shaw

1
ฉันสงสัยว่าเฟรมเวิร์ก UI จำนวนเท่าใดที่จะพังโดยการเปลี่ยนคลาสของหน้าต่างเป็นปิดผนึก
ปฏิกิริยา

คำตอบ:


46

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

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

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

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


17
+1 สำหรับย่อหน้าสุดท้าย ฉันมักจะพบว่าการห่อหุ้มมากเกินไปในห้องสมุดบุคคลที่สาม (หรือแม้กระทั่งชั้นเรียนห้องสมุดมาตรฐาน!) ที่จะทำให้เกิดอาการปวดที่ใหญ่กว่าการห่อหุ้มน้อยเกินไป
Mason Wheeler

5
อาร์กิวเมนต์ปกติสำหรับการปิดผนึกคลาสคือคุณไม่สามารถคาดการณ์ได้หลายวิธีที่ไคลเอนต์สามารถแทนที่ชั้นเรียนของคุณและดังนั้นคุณจึงไม่สามารถรับประกันได้เกี่ยวกับพฤติกรรมของมัน ดูblogs.msdn.com/b/ericlippert/archive/2004/01/22/…
Robert Harvey

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

6
@ RobertHarvey ไม่เพียง แต่มีคนทำลาย LSP ที่ได้รับสิ่งที่พวกเขาสมควรได้รับ?
StuperUser

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

11

นั่นเป็นบทความที่ยอดเยี่ยมโดย Eric Lippert แต่ฉันไม่คิดว่ามันจะสนับสนุนมุมมองของคุณ

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

หลักฐานของคุณคือว่าทุกชั้นควรเป็นนามธรรมหรือปิดผนึก

แตกต่างใหญ่

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


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

ฉันคิดว่าความคิดที่ชั้นเรียนควรเป็นนามธรรมหรือปิดผนึกเป็นส่วนหนึ่งของหลักการที่กว้างขึ้นซึ่งเป็นสิ่งหนึ่งที่ควรหลีกเลี่ยงการใช้ตัวแปรประเภทชั้นเรียนได้ทันที การหลีกเลี่ยงดังกล่าวจะทำให้สามารถสร้างประเภทที่ผู้บริโภคสามารถใช้งานได้โดยไม่ต้องมีการสืบทอดสมาชิกส่วนตัวทุกคน น่าเสียดายที่การออกแบบดังกล่าวไม่ได้ทำงานกับไวยากรณ์ตัวสร้างสาธารณะ รหัสแทนจะต้องเปลี่ยนกับสิ่งที่ต้องการnew List<Foo>() List<Foo>.CreateMutable()
supercat

5

จากมุมมองของจาวาฉันคิดว่าคลาสสุดท้ายนั้นไม่ฉลาดเท่าที่ควร

เครื่องมือจำนวนมาก (โดยเฉพาะอย่างยิ่ง AOP, JPA ฯลฯ ) ทำงานร่วมกับความเร็วในการโหลดเพื่อให้พวกเขาต้องขยายส่วนของคุณ อีกวิธีหนึ่งคือการสร้างผู้รับมอบสิทธิ์ (ไม่ใช่คน. NET) แทนทุกอย่างให้กับคลาสดั้งเดิมซึ่งจะยุ่งกว่าการขยายคลาสผู้ใช้


5

กรณีทั่วไปสองกรณีที่คุณจะต้องมีคลาสวานิลลาและไม่มีการปิดผนึก:

  1. วิเคราะห์ทางเทคนิค:หากคุณมีลำดับชั้นที่มีความลึกมากกว่าสองระดับและคุณต้องการที่จะสร้างอินสแตนซ์ที่อยู่ตรงกลาง

  2. หลักการ:บางครั้งมันเป็นที่พึงปรารถนาเพื่อการเรียนการเขียนที่มีexplicity ออกแบบเพื่อให้สามารถขยายได้อย่างปลอดภัย (สิ่งนี้เกิดขึ้นมากมายเมื่อคุณเขียน API เช่น Eric Lippert หรือเมื่อคุณทำงานเป็นทีมในโครงการขนาดใหญ่) บางครั้งคุณต้องการเขียนคลาสที่ทำงานได้ดีด้วยตัวเอง แต่ถูกออกแบบโดยคำนึงถึงความสามารถในการขยาย

ความคิดของเอริค Lippert ในการปิดผนึกที่ทำให้รู้สึก แต่เขาก็ยอมรับว่าพวกเขาทำในการออกแบบสำหรับการขยายโดยการออกจากชั้นเรียน "เปิด"

ใช่ชั้นเรียนจำนวนมากได้รับการผนึกใน BCL แต่มีชั้นเรียนจำนวนมากที่ไม่สามารถเข้าร่วมได้และสามารถขยายออกไปได้หลายวิธี ตัวอย่างหนึ่งที่นึกถึงคือใน Windows Forms ซึ่งคุณสามารถเพิ่มข้อมูลหรือลักษณะการทำงานให้กับเกือบทุกอย่างControlผ่านการรับมรดก แน่นอนว่าสิ่งนี้สามารถทำได้ในรูปแบบอื่น ๆ (รูปแบบมัณฑนากร, องค์ประกอบประเภทต่าง ๆ ฯลฯ ) แต่มรดกก็ใช้ได้ดีเช่นกัน

หมายเหตุเฉพาะ. NET สองรายการ:

  1. ในกรณีสวนใหญการเรียนการปดผนึกมักไมสําคัญเพื่อความปลอดภัยvirtualทำงานยกเว้นการใช้งานอินเทอร์เฟซที่ชัดเจน
  2. บางครั้งทางเลือกที่เหมาะสมคือการสร้าง Constructor internalแทนที่จะปิดผนึกคลาสซึ่งอนุญาตให้สืบทอดใน codebase ของคุณ แต่ไม่ใช่ภายนอก

4

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

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

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

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

อย่างไรก็ตามเมื่อคุณทำการบันทึกคลาสที่สามารถขยายได้อย่างถูกต้องคุณต้องมีอย่างน้อยดังต่อไปนี้ :

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

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

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

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

ฉันคิดว่าองค์ประกอบบางอย่างของการแก้ปัญหาคือ:

  • ครั้งแรกเพื่อให้แน่ใจว่าการขยายเป็นความคิดที่ดีเมื่อคุณลูกค้าของรหัสและเพื่อจริงๆโปรดปรานองค์ประกอบมรดก
  • ประการที่สองเพื่ออ่านคู่มืออย่างครบถ้วน (อีกครั้งในฐานะลูกค้า) เพื่อให้แน่ใจว่าคุณไม่ได้มองสิ่งที่กล่าวถึง
  • ประการที่สามเมื่อคุณเขียนรหัสชิ้นส่วนที่ลูกค้าจะใช้ให้เขียนเอกสารที่เหมาะสมสำหรับรหัส (ใช่ทางยาว) เป็นตัวอย่างในเชิงบวกฉันสามารถมอบเอกสาร iOS ของ Apple พวกเขาจะไม่เพียงพอสำหรับผู้ใช้ที่มักจะถูกขยายชั้นเรียนของพวกเขา แต่พวกเขาอย่างน้อยรวมถึงบางข้อมูลเกี่ยวกับมรดก มีอะไรมากกว่าที่ฉันสามารถพูดได้สำหรับ API ส่วนใหญ่
  • ข้อสี่ลองขยายชั้นเรียนของคุณเองเพื่อให้แน่ใจว่าใช้ได้จริง ฉันเป็นผู้สนับสนุนรายใหญ่ของการรวมตัวอย่างและการทดสอบจำนวนมากใน API และเมื่อคุณทำการทดสอบคุณอาจทดสอบเครือข่ายการรับมรดกด้วย: นี่เป็นส่วนหนึ่งของสัญญาของคุณ!
  • ประการที่ห้าในสถานการณ์ที่คุณมีข้อสงสัยให้ระบุว่าชั้นไม่ได้หมายถึงการขยายและการทำมันเป็นความคิดที่ไม่ดี (TM) บ่งบอกว่าคุณไม่ควรรับผิดชอบต่อการใช้งานที่ไม่ได้ตั้งใจ แต่ก็ยังไม่ปิดผนึกชั้นเรียน เห็นได้ชัดว่านี่ไม่ครอบคลุมกรณีที่คลาสควรได้รับการปิดผนึก 100%
  • ในที่สุดเมื่อปิดผนึกชั้นเรียนให้อินเตอร์เฟซเป็นเบ็ดกลางเพื่อให้ลูกค้าสามารถ "เขียน" รุ่นที่แก้ไขของตัวเองของชั้นเรียนและทำงานรอบคลาส 'ปิดผนึก' ของคุณ ด้วยวิธีนี้เขาสามารถแทนที่ชั้นเรียนที่ปิดผนึกด้วยการใช้งานของเขา ตอนนี้สิ่งนี้ควรชัดเจนเนื่องจากเป็นข้อต่อหลวมในรูปแบบที่ง่ายที่สุด แต่ก็ยังมีค่าควรแก่การกล่าวถึง

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


3

คลาสไม่ควรเป็นครั้งสุดท้าย / ปิดผนึกหรือเป็นนามธรรมถ้า:

  • มันมีประโยชน์ในตัวมันเองนั่นคือมีประโยชน์ที่จะมีอินสแตนซ์ของคลาสนั้น
  • มันเป็นประโยชน์สำหรับชั้นเรียนนั้นจะเป็นคลาสย่อย / ฐานของชั้นเรียนอื่น ๆ

ตัวอย่างเช่นใช้ObservableCollection<T>ชั้นใน C # จำเป็นต้องเพิ่มการเพิ่มของเหตุการณ์ให้กับการดำเนินการปกติของ a Collection<T>เท่านั้นซึ่งเป็นสาเหตุให้คลาสย่อยCollection<T>นั้น เป็นชั้นที่มีศักยภาพในตัวเองและดังนั้นจึงCollection<T>ObservableCollection<T>


ถ้าฉันเป็นผู้ดูแลเรื่องนี้ฉันอาจจะทำCollectionBase(นามธรรม), Collection : CollectionBase(ปิดผนึก), ObservableCollection : CollectionBase(ปิดผนึก) หากคุณดูคอลเล็กชัน <T>อย่างใกล้ชิดคุณจะเห็นว่าเป็นระดับนามธรรมแบบครึ่งทาง
Nicolas Repiquet

2
คุณได้เปรียบอะไรจากการมีสามคลาสแทนที่จะเป็นแค่สองคลาส? นอกจากนี้Collection<T>"คลาสนามธรรมแบบครึ่งตัว" เป็นอย่างไร?
FishBasketGordo

Collection<T>เปิดเผยอวัยวะภายในจำนวนมากผ่านวิธีการและคุณสมบัติที่ได้รับการป้องกันและมีความหมายอย่างชัดเจนว่าเป็นคลาสพื้นฐานสำหรับการเก็บรวบรวมแบบพิเศษ แต่มันไม่ชัดเจนว่าคุณควรใส่รหัสของคุณไว้ที่ใดเนื่องจากไม่มีวิธีการเชิงนามธรรมที่จะนำไปใช้ ObservableCollectionสืบทอดมาจากCollectionและไม่ได้ถูกผนึกดังนั้นคุณจึงสามารถสืบทอดจากมันได้อีกครั้ง และคุณสามารถเข้าถึงItemsคุณสมบัติที่มีการป้องกันช่วยให้คุณสามารถเพิ่มรายการในคอลเลกชันโดยไม่ต้องเพิ่มกิจกรรม ... ดี
Nicolas Repiquet

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

3

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

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

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


1
สิ่งสุดท้ายที่ปิดผนึกในซอฟต์แวร์แก้ปัญหาของ "ฉันรู้สึกว่าจำเป็นต้องกำหนดความประสงค์ของฉันในการดูแลรักษารหัสนี้ในอนาคต"
Kaz

ไม่ได้สุดท้าย / ปิดผนึกบางสิ่งบางอย่างที่เพิ่มใน OOP เพราะฉันจำไม่ได้ว่ามันอยู่ในช่วงที่ฉันยังเด็ก ดูเหมือนว่าจะเป็นฟีเจอร์ที่ได้รับการยอมรับ
เปิดใช้งานอีกครั้ง

การสรุปมีอยู่เป็นขั้นตอน toolchain ในระบบ OOP ก่อนที่ OOP จะกลายเป็นภาษาที่ล้าสมัยเช่น C ++ และ Java โปรแกรมเมอร์ทำงานใน Smalltalk, Lisp ด้วยความยืดหยุ่นสูงสุด: ทุกสิ่งสามารถขยายได้เพิ่มวิธีการใหม่ตลอดเวลา จากนั้นอิมเมจที่คอมไพล์ของระบบขึ้นอยู่กับการปรับให้เหมาะสม: มีการสันนิษฐานว่าผู้ใช้ปลายทางจะไม่ขยายระบบดังนั้นนี่หมายความว่าวิธีการจัดส่งสามารถปรับให้เหมาะสมที่สุดโดยพิจารณาจากการเก็บสต็อคของวิธีการใดและ เรียนอยู่ในขณะนี้
Kaz

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

เพียงเพราะมันปรากฏตัวเป็นประกาศบางอย่างที่คุณต้องใส่รหัสไม่ได้หมายความว่ามันไม่เหมือนกัน
Kaz

2

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

กล่าวคือเราทำให้มันยากสำหรับระบบที่จะเปลี่ยนเป็นอย่างอื่นเป็นการแลกเปลี่ยนเพื่อประสิทธิภาพ (นั่นคือสาระสำคัญของการเพิ่มประสิทธิภาพมากที่สุด)

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

เราไม่ได้รับฟังก์ชั่นใหม่ ๆ ในวันนี้โดยทำตามขั้นตอนเพื่อป้องกันการขยายในอนาคต

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


1

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


คุณกำลังพูดถึงอะไร การทดสอบในชั้นเรียนต้องไม่ปิดท้าย / ปิดท้าย / นามธรรมอย่างไร?

1

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

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

นี่เป็นโอกาสที่ดีสำหรับการขยายชั้นเรียน

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

นอกเหนือจากนี้ฉันมีผู้ส่งออกที่แตกต่างกันในการทำงานกับข้อมูลแต่ละประเภทบางทีอาจมีกิจกรรมของผู้ใช้ข้อมูลการทำธุรกรรมข้อมูลการจัดการเงินสดเป็นต้น

ด้านบนของสแต็กนี้ฉันวางเลเยอร์เฉพาะลูกค้าซึ่งใช้โครงสร้างไฟล์ข้อมูลที่ลูกค้าต้องการ

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

ดังนั้นโครงสร้างดูเหมือนว่า:

Base
 Function1
  Customer1
  Customer2
 Function2
 ...

จุดหลักของฉันคือการสร้างรหัสด้วยวิธีนี้ฉันสามารถใช้การสืบทอดเป็นหลักสำหรับการใช้รหัสซ้ำ

ฉันต้องบอกว่าฉันไม่สามารถคิดเหตุผลที่จะผ่านสามชั้นได้

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


1

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


1
นี่เป็นความคิดเห็นที่ดี แต่ไม่ตอบคำถามโดยตรง โปรดพิจารณาขยายความคิดของคุณที่นี่

1

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

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

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

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

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