คำถามติดแท็ก open-close

8
LSP เทียบกับการทดแทน OCP / Liskov VS เปิดปิด
ฉันพยายามที่จะเข้าใจหลักการของ OOP และฉันได้ข้อสรุปว่า LSP และ OCP มีความคล้ายคลึงกัน (ถ้าไม่พูดมากกว่านี้) หลักการเปิด / ปิดระบุ "เอนทิตีของซอฟต์แวร์ (คลาส, โมดูล, ฟังก์ชั่น, อื่น ๆ ) ควรจะเปิดสำหรับการขยาย แต่ปิดสำหรับการปรับเปลี่ยน" ในคำง่ายๆ LSP ระบุว่าอินสแตนซ์ใด ๆ ของFooสามารถถูกแทนที่ด้วยอินสแตนซ์ใด ๆBarที่ได้มาจากFooและโปรแกรมจะทำงานในลักษณะเดียวกัน ฉันไม่ใช่โปรแกรมเมอร์ OOP มืออาชีพ แต่สำหรับฉันแล้วดูเหมือนว่า LSP จะเป็นไปได้ก็ต่อเมื่อBarได้รับมาจากFooไม่ได้เปลี่ยนแปลงอะไรเลย แต่จะขยายออกไปเท่านั้น นั่นหมายความว่าโดยเฉพาะอย่างยิ่งโปรแกรม LSP จะเป็นจริงเฉพาะเมื่อ OCP เป็นจริงและ OCP เป็นจริงเฉพาะในกรณีที่ LSP เป็นจริง นั่นหมายความว่าพวกเขาเท่าเทียมกัน ช่วยแก้ให้ด้วยนะถ้าฉันผิด. ฉันต้องการเข้าใจแนวคิดเหล่านี้จริงๆ ขอบคุณมากสำหรับคำตอบ

8
การเอาชนะ Object.finalize () ไม่ดีจริงเหรอ?
ข้อโต้แย้งหลักสองข้อต่อการยกเลิกObject.finalize()คือ: คุณไม่ต้องตัดสินใจเมื่อมันถูกเรียก มันอาจจะไม่ถูกเรียกเลย หากฉันเข้าใจสิ่งนี้อย่างถูกต้องฉันไม่คิดว่าสิ่งเหล่านี้เป็นเหตุผลที่ดีพอที่จะเกลียดObject.finalize()มาก มันขึ้นอยู่กับการนำ VM ไปใช้และ GC เพื่อพิจารณาว่าเวลาที่เหมาะสมในการจัดสรรคืนวัตถุนั้นไม่ใช่นักพัฒนา เหตุใดจึงสำคัญที่ต้องตัดสินใจเมื่อObject.finalize()ถูกเรียก ตามปกติและแก้ไขให้ถูกต้องหากฉันผิดเวลาที่Object.finalize()จะไม่ถูกเรียกก็คือเมื่อแอปพลิเคชันถูกยกเลิกก่อนที่ GC จะมีโอกาสเรียกใช้ อย่างไรก็ตามวัตถุได้ถูกจัดสรรคืนเมื่อกระบวนการของแอปพลิเคชันสิ้นสุดลง จึงObject.finalize()ไม่ได้รับการเรียกเนื่องจากไม่จำเป็นต้องโทร ทำไมนักพัฒนาถึงสนใจ? ทุกครั้งที่ฉันใช้วัตถุที่ฉันต้องปิดเอง (เช่นตัวจัดการไฟล์และการเชื่อมต่อ) ฉันจะผิดหวังมาก ฉันต้องตรวจสอบอย่างต่อเนื่องว่าวัตถุมีการนำไปใช้close()หรือไม่และฉันแน่ใจว่าฉันไม่ได้รับสายบางครั้งในอดีต ทำไมมันไม่ได้เป็นเพียงที่เรียบง่ายและปลอดภัยในการเพียงแค่ปล่อยให้มันไป VM และ GC ในการกำจัดของวัตถุเหล่านี้โดยการวางclose()การดำเนินงานในObject.finalize()?

1
เหตุใดเบอร์ทรานด์เมเยอร์จึงคิดว่าการแบ่งคลาสย่อยเป็นวิธีเดียวที่จะขยายโมดูล“ ปิด”?
ในการสร้างซอฟต์แวร์เชิงวัตถุของเมเยอร์(1988) เขาได้กำหนดหลักการเปิด / ปิดดังต่อไปนี้: โมดูลจะได้รับการกล่าวถึงว่าเป็นเปิดถ้ามันยังคงมีอยู่สำหรับส่วนขยาย ตัวอย่างเช่นควรเป็นไปได้ที่จะเพิ่มเขตข้อมูลลงในโครงสร้างข้อมูลที่มีอยู่หรือองค์ประกอบใหม่ในชุดของฟังก์ชันที่ดำเนินการ โมดูลจะถูกปิดหากมีการใช้งานโดยโมดูลอื่น นี่ถือว่าโมดูลนั้นได้รับการกำหนดรายละเอียดที่ดีและมีเสถียรภาพ (อินเทอร์เฟซในแง่ของการซ่อนข้อมูล) เขาพูดต่อไปว่า: หากคุณเปิดโมดูลอีกครั้งคุณจะต้องเปิดไคลเอนต์ทั้งหมดอีกครั้งเพื่ออัปเดตโมดูลเนื่องจากใช้รุ่นเก่า … [ปัญหานี้] เกิดขึ้นทุกครั้งที่โมดูลจะต้องถูกขยายโดยฟังก์ชั่นใหม่หรือองค์ประกอบข้อมูลทำให้เกิดการเปลี่ยนแปลงในไคลเอนต์ทั้งทางตรงและทางอ้อม ... ด้วยวิธีการคลาสสิกในการออกแบบและการเขียนโปรแกรมจึงไม่มีวิธีเขียนโมดูลที่เปิดและปิด วิธีการแก้ปัญหาของเมเยอร์ในภาวะที่กลืนไม่เข้าคายไม่ออกนี้คือ: ไม่ขยายโมดูลห้องสมุดโดยการปรับเปลี่ยนคลาสที่มีอยู่; ให้เขียนโมดูลใหม่แทนคลาสย่อยที่มีอยู่แล้วและให้ไคลเอนต์ใหม่พึ่งพาโมดูลใหม่นั้น ตอนนี้ในปี 1988 ฉันเขียนโปรแกรมของเล่น (ขั้นตอน) ใน Turbo Pascal และ Blankenship Basic และประสบการณ์ระดับมืออาชีพในศตวรรษที่ 21 ของฉันคือ JVM, CLR และในภาษาไดนามิกดังนั้นฉันจึงไม่รู้ว่า Meyer แปลว่าอะไร โดย "แนวทางคลาสสิคเพื่อการออกแบบและการเขียนโปรแกรม" ตัวอย่างหนึ่งที่เป็นรูปธรรมของเมเยอร์ที่ว่าทำไมโมดูลลูกค้าจึงต้องเปิดใหม่ (คำสั่งเปลี่ยนจากการแจงนับซึ่งขณะนี้มีสมาชิกมากขึ้นต้องใช้เคสมากขึ้น) ดูสมเหตุสมผลพอสมควร แต่เขาไม่เกือบยืนยันว่าทุกครั้งที่คุณเพิ่มฟังก์ชันการทำงาน โมดูลคุณต้องอัปเดตไคลเอ็นต์ทั้งหมด มีเหตุผลทางประวัติศาสตร์ที่การยืนยันนี้ดูเหมือนชัดเจนในปี 1988? พูดหรือไม่ว่าการเพิ่มฟังก์ชั่นหรือโครงสร้างข้อมูลไปยัง C static library …

4
mocks ละเมิดหลักการเปิด / ปิดหรือไม่?
เมื่อนานมาแล้วที่ฉันอ่านคำตอบสแต็คโอเวอร์โฟลว์ที่ฉันหาไม่พบประโยคที่อธิบายว่าคุณควรทดสอบ API สาธารณะและผู้เขียนบอกว่าคุณควรทดสอบอินเทอร์เฟซ ผู้เขียนอธิบายว่าหากมีการเปลี่ยนแปลงวิธีการใช้งานคุณไม่จำเป็นต้องแก้ไขกรณีทดสอบเนื่องจากการทำเช่นนี้จะเป็นการผิดสัญญาที่ทำให้ระบบภายใต้การทดสอบทำงานได้ กล่าวอีกนัยหนึ่งการทดสอบควรล้มเหลวหากวิธีการไม่ทำงาน แต่ไม่ใช่เพราะการใช้งานมีการเปลี่ยนแปลง สิ่งนี้เรียกร้องความสนใจของฉันเมื่อเราพูดถึงการล้อเลียน เนื่องจากการเยาะเย้ยต้องอาศัยการเรียกร้องอย่างคาดหวังจากระบบภายใต้การทดสอบของผู้ทดสอบดังนั้น mocks จึงผนวกเข้ากับการใช้งานอย่างแน่นหนามากกว่าอินเตอร์เฟส ในขณะที่ทำการค้นคว้าmock vs stubหลายบทความเห็นด้วยว่าควรใช้ต้นขั้วแทน mocks เนื่องจากไม่ต้องพึ่งพาความคาดหวังจากการพึ่งพาซึ่งหมายความว่าการทดสอบไม่จำเป็นต้องมีความรู้เกี่ยวกับระบบพื้นฐานภายใต้การใช้งานการทดสอบ คำถามของฉันจะเป็น: mocks ละเมิดหลักการเปิด / ปิดหรือไม่? มีบางสิ่งที่ขาดหายไปในการโต้แย้งเพื่อช่วยสตับในย่อหน้าสุดท้ายที่ทำให้สตับไม่ดีเทียบกับ mocks หรือไม่? ถ้าเป็นเช่นนั้นเมื่อไรจะเป็นกรณีการใช้งานที่ดีในการเยาะเย้ยและเมื่อไหร่จะเป็นกรณีการใช้งานที่ดีในการใช้สตับ

5
การบรรทุกเกินพิกัดเป็นตัวอย่างของหลักการเปิด / ปิดหรือไม่
Wikipedia พูดว่า "เอนทิตีของซอฟต์แวร์ (คลาส, โมดูล, ฟังก์ชั่น, ฯลฯ ) ควรเปิดเพื่อขยาย แต่ปิดเพื่อแก้ไข" ฟังก์ชั่นคำดึงดูดสายตาของฉันและตอนนี้ฉันสงสัยว่าเราสามารถสันนิษฐานได้ว่าการสร้างเกินพิกัดสำหรับวิธีการสามารถถือได้ว่าเป็นตัวอย่างของหลักการเปิด / ปิดหรือไม่? ให้ฉันอธิบายตัวอย่าง พิจารณาว่าคุณมีวิธีการในชั้นบริการซึ่งใช้ในสถานที่เกือบ 1,000 แห่ง วิธีการได้รับ userId และกำหนดว่าผู้ใช้เป็นผู้ดูแลหรือไม่: bool IsAdmin(userId) ตอนนี้ให้พิจารณาว่ามีบางสิ่งที่จำเป็นในการพิจารณาว่าผู้ใช้เป็นผู้ดูแลระบบหรือไม่โดยยึดตามชื่อผู้ใช้ไม่ใช่ชื่อผู้ใช้ หากเราเปลี่ยนลายเซ็นของวิธีการที่กล่าวถึงข้างต้นแสดงว่าเรามีรหัสที่ไม่สมบูรณ์ใน 1000 แห่ง (ฟังก์ชั่นควรปิดเพื่อแก้ไข) ดังนั้นเราสามารถสร้างโอเวอร์โหลดเพื่อรับชื่อผู้ใช้ค้นหา userId ตามชื่อผู้ใช้และวิธีการดั้งเดิม: public bool IsAdmin(string username) { int userId = UserManager.GetUser(username).Id; return IsAdmin(userId); } ด้วยวิธีนี้เราได้ขยายฟังก์ชั่นของเราผ่านการสร้างโอเวอร์โหลด (ฟังก์ชั่นควรจะเปิดเพื่อขยาย) มันเป็นตัวอย่างหลักการเปิด / ปิดหรือไม่?

7
หลักการการเปลี่ยนโครงสร้างและเปิด / ปิด
ฉันเพิ่งอ่านเว็บไซต์เกี่ยวกับการพัฒนาโค้ดที่สะอาด (ฉันไม่ได้ใส่ลิงค์ไว้ที่นี่เพราะไม่ใช่ภาษาอังกฤษ) หนึ่งในหลักการที่โฆษณาโดยไซต์นี้คือหลักการเปิดปิด : ส่วนประกอบซอฟต์แวร์แต่ละรายการควรเปิดเพื่อขยายและปิดเพื่อการปรับเปลี่ยน เช่นเมื่อเรานำไปใช้และทดสอบคลาสเราควรแก้ไขเพื่อแก้ไขข้อบกพร่องหรือเพื่อเพิ่มฟังก์ชั่นใหม่ (เช่นวิธีการใหม่ที่ไม่มีผลต่อคลาสที่มีอยู่) ไม่ควรเปลี่ยนฟังก์ชันการทำงานและการใช้งานที่มีอยู่ ผมปกติใช้หลักการนี้ด้วยการกำหนดอินเตอร์เฟซและระดับการดำเนินงานที่สอดคล้องกันI Aเมื่อชั้นเรียนAมีเสถียรภาพ (ดำเนินการและทดสอบ) ปกติแล้วฉันจะไม่แก้ไขมากเกินไป (อาจไม่เลย) เช่น หากข้อกำหนดใหม่มาถึง (เช่นประสิทธิภาพหรือการใช้อินเทอร์เฟซใหม่ทั้งหมด) ที่ต้องมีการเปลี่ยนแปลงโค้ดอย่างมากฉันจะเขียนการใช้งานใหม่Bและใช้ต่อไปAตราบเท่าที่Bยังไม่ครบกำหนด เมื่อBครบกำหนดแล้วสิ่งที่จำเป็นต้องมีก็คือเปลี่ยนวิธีการIสร้างอินสแตนซ์ หากความต้องการใหม่แนะนำการเปลี่ยนแปลงอินเตอร์เฟซเป็นอย่างดีฉันกำหนดอินเตอร์เฟซใหม่และการดำเนินงานใหม่I' A'ดังนั้นI, Aมีแช่แข็งและยังคงอยู่ในการดำเนินการสำหรับระบบการผลิตเป็นเวลานานเป็นI'และA'มีไม่เพียงพอที่มั่นคงเพื่อแทนที่พวกเขา ดังนั้นในมุมมองของการสังเกตเหล่านี้ฉันรู้สึกประหลาดใจเล็กน้อยที่หน้าเว็บนั้นแนะนำให้ใช้การปรับโครงสร้างที่ซับซ้อน "... เนื่องจากไม่สามารถเขียนโค้ดโดยตรงในรูปแบบสุดท้าย" ไม่มีความขัดแย้ง / ความขัดแย้งระหว่างการบังคับใช้หลักการเปิด / ปิดและแนะนำให้ใช้การปรับโครงสร้างที่ซับซ้อนเป็นวิธีปฏิบัติที่ดีที่สุดหรือไม่? หรือความคิดในที่นี้คือเราสามารถใช้ refactorings ที่ซับซ้อนในระหว่างการพัฒนาคลาสAแต่เมื่อคลาสนั้นได้รับการทดสอบสำเร็จแล้วควรจะถูกแช่แข็งหรือไม่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.