OOP แก้ปัญหาในทางปฏิบัติอย่างไร


17

ผมได้ศึกษาหนังสือ"C ++ Demystified" ตอนนี้ฉันเริ่มอ่าน"การเขียนโปรแกรมเชิงวัตถุใน Turbo C ++ รุ่นแรก (รุ่นที่ 1)"โดย Robert Lafore ฉันไม่มีความรู้เกี่ยวกับการเขียนโปรแกรมใด ๆ ซึ่งอยู่นอกเหนือหนังสือเหล่านี้ หนังสือเล่มนี้อาจล้าสมัยเพราะอายุ 20 ปี ฉันมีฉบับล่าสุดฉันใช้รุ่นเก่าเพราะฉันชอบส่วนใหญ่ฉันแค่ศึกษาแนวคิดพื้นฐานของ OOP ที่ใช้ใน C ++ ผ่านหนังสือรุ่นแรกของ Lafore

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

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

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

ฉันได้ศึกษาหนังสือ "dysmystified C ++" โดย Jeff Kent ฉันชอบหนังสือเล่มนี้มากในหนังสือเล่มนี้ส่วนใหญ่จะอธิบายการเขียนโปรแกรมขั้นตอน ฉันไม่เข้าใจว่าทำไมการเขียนโปรแกรม (โครงสร้าง) ขั้นตอนจึงอ่อน!

หนังสือของ Lafore อธิบายแนวคิดอย่างดีด้วยตัวอย่างที่ดี นอกจากนี้ฉันได้เข้าใจสัญชาตญาณโดยการอ่านหนังสือของ Lafore ว่า OOP นั้นดีกว่าการเขียนโปรแกรมตามขั้นตอน แต่ฉันอยากรู้ว่าวิธีการเขียนโปรแกรมเชิงปฏิบัติในเชิงปฏิบัตินั้นอ่อนแอกว่า OOP อย่างไร

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

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

ดังนั้นนี่คือคำถามของฉัน:

ข้อ จำกัด ของการเขียนโปรแกรมเชิงโพรซีเดอร์ทำที่อยู่ของ OOP ได้อย่างไรและจะกำจัดข้อ จำกัด เหล่านี้ได้อย่างมีประสิทธิภาพในทางปฏิบัติอย่างไร

โดยเฉพาะอย่างยิ่งมีตัวอย่างของโปรแกรมที่ยากต่อการออกแบบโดยใช้กระบวนทัศน์กระบวนงาน แต่ออกแบบโดยใช้ OOP ได้อย่างง่ายดายหรือไม่?

PS: ข้ามโพสต์จาก: /programming//q/22510004/3429430


3
ความแตกต่างระหว่างการโปรแกรมเชิงโพรซีเดอร์กับการเขียนโปรแกรมเชิงวัตถุคือการนำเสนอและการเน้นในระดับหนึ่ง ภาษาส่วนใหญ่ที่โฆษณาตัวเองเป็นแบบเชิงวัตถุก็มีขั้นตอนเช่นกัน - คำศัพท์จะพิจารณาแง่มุมต่าง ๆ ของภาษา
Gilles 'SO- หยุดความชั่วร้าย'

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

ความคิดในการออกแบบ GUI เดสก์ท็อป (ทันสมัย) ที่ไม่มี OOP และเทคนิคบางอย่างที่เพิ่มขึ้นบนมัน (เช่นรูปแบบเหตุการณ์ / ผู้ฟัง) ทำให้ฉันกลัว ไม่ได้หมายความว่าไม่สามารถทำได้ (มันแน่นอนสามารถ ) แต่ นอกจากนี้หากคุณต้องการเห็นความล้มเหลวของ PP ในที่ทำงานให้ดูที่ PHP และเปรียบเทียบ API กับพูดว่า Ruby
Raphael

1
"ว่าวิธีที่ดีวิธีการเขียนโปรแกรมโครงสร้างจะดำเนินการไม่มีโปรแกรมขนาดใหญ่กลายเป็นความซับซ้อนมากเกินไป ..." ที่เป็นจริงมากของ OOP ยัง แต่โดยทั่วไปจะจัดการความซับซ้อนที่ดีกว่าถ้าใช้ในทางที่กำหนดโดยนักพัฒนา ...และไม่ ส่วนใหญ่จะผ่านขอบเขต / ข้อ จำกัด ที่ดีกว่าและคมชัดกว่านั่นคือระบบการแยกประเภทแบบแยกส่วน ... aka APIE: Abstraction, Polymorphism, Inheritance, Encapsulation
vzn

คำตอบ:


9

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

ประเภทการประกาศเป็นข้อ จำกัด ที่ชัดเจนที่สุดในการประกาศ (เช่น: "พิสูจน์ว่า x คือการลอย") การบังคับให้การกลายพันธุ์ของข้อมูลเพื่อส่งผ่านฟังก์ชั่นที่รู้จักกันว่าได้รับการออกแบบสำหรับข้อมูลนั้นเป็นอีกสิ่งหนึ่ง การบังคับใช้โพรโทคอล (การเรียกใช้เมธอดสั่งซื้อ) เป็นข้อ จำกัด อื่นที่สนับสนุนบางส่วนเช่น: "constructor -> othermethods * -> destructor"

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

type x1 เป็นประเภทย่อยของ x, t1 เป็นประเภทย่อยของ t

นี่เป็นวิธีหนึ่งในการห่อหุ้มข้อมูลในภาษาเชิงโพรซีเดอร์เพื่อให้มีชนิด t พร้อมเมธอด f และ g และคลาสย่อย t1 ที่ทำเช่นเดียวกัน:

t_f (t, x, y, z, ... ), t_g (t, x, y, ... ) t1_f (t1, x, y, z, ... )

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

พิมพ์ t {d: data f: function g: function}

ดังนั้นคุณจึงเรียกใช้ tf (x, y, z) แทนโดยที่ typecheck และสวิตช์เพื่อค้นหาเมธอดจะถูกแทนที่ด้วยตอนนี้มีเพียงพอยน์เตอร์เมธอดที่เก็บแต่ละอินสแตนซ์อย่างชัดเจน ตอนนี้ถ้าคุณมีฟังก์ชั่นจำนวนมากต่อหนึ่งประเภทนี่เป็นการแสดงที่สิ้นเปลือง จากนั้นคุณสามารถใช้กลยุทธ์อื่นเช่นให้ t ชี้ไปที่ตัวแปร m ซึ่งมีฟังก์ชันสมาชิกทั้งหมด หากคุณลักษณะนี้เป็นส่วนหนึ่งของภาษาคุณสามารถให้คอมไพเลอร์หาวิธีจัดการกับการแสดงรูปแบบนี้อย่างมีประสิทธิภาพ

แต่การห่อหุ้มข้อมูลเป็นการรับรู้ว่าสถานะที่ไม่แน่นอนนั้นไม่ดี วิธีแก้ปัญหาเชิงวัตถุคือการซ่อนมันไว้ข้างหลังวิธีการ ตามหลักการแล้ววิธีการทั้งหมดในวัตถุจะมีลำดับการเรียกที่ชัดเจน (เช่น: constructor -> open -> [read | write] -> close -> destruct); ซึ่งบางครั้งเรียกว่า 'โปรโตคอล' (การวิจัย: "Microsoft Singularity") แต่นอกเหนือจากการสร้างและการทำลายความต้องการเหล่านี้มักจะไม่ได้เป็นส่วนหนึ่งของระบบประเภท - หรือเอกสารที่ดี ในแง่นี้วัตถุเป็นอินสแตนซ์ที่เกิดขึ้นพร้อมกันของเครื่องจักรสถานะที่ถูกเปลี่ยนโดยการเรียกเมธอด เช่นที่คุณอาจมีหลายอินสแตนซ์และใช้พวกเขาในแฟชั่น interleaved โดยพลการ

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

เปรียบเทียบการเรียกใช้เมธอด Java ในบริบทแบบมัลติเธรดกับกระบวนการ Erlang ส่งข้อความ (ซึ่งอ้างอิงค่าที่ไม่เปลี่ยนรูปแบบได้เท่านั้น) ซึ่งกันและกัน

การวางแนววัตถุที่ไม่ จำกัด ร่วมกับการขนานเป็นปัญหาเนื่องจากการล็อค มีเทคนิคมากมายตั้งแต่ Software Transactional Memory (เช่น: ธุรกรรม ACID ในวัตถุหน่วยความจำคล้ายกับฐานข้อมูล) ไปจนถึงการใช้ "แชร์หน่วยความจำโดยการสื่อสาร

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


คุณกำลังบอกว่าในภาษา OO คอมไพเลอร์สามารถตรวจสอบว่ามีการใช้วิธีการตามลำดับที่กำหนดหรือข้อ จำกัด อื่น ๆ ในการใช้โมดูลหรือไม่? ทำไม "การห่อหุ้มข้อมูล [... ] การรับรู้ว่าสถานะไม่แน่นอนไม่ดี"? เมื่อคุณพูดถึงความแตกต่างคุณคิดว่าคุณใช้ภาษา OO หรือไม่?
Babou

ใน OO ความสามารถที่สำคัญที่สุดคือสามารถซ่อนโครงสร้างข้อมูล (เช่น: ต้องการการอ้างอิงที่มาจาก like this.x) เพื่อพิสูจน์ว่าการเข้าถึงทั้งหมดผ่านเมธอด ในภาษา OO ที่พิมพ์แบบคงที่คุณจะประกาศข้อ จำกัด เพิ่มเติม (ตามประเภท) หมายเหตุเกี่ยวกับการจัดระเบียบวิธีการเพียงแค่บอกว่า OO บังคับให้ตัวสร้างถูกเรียกเป็นอันดับแรกและตัวทำลายจะคงอยู่ ซึ่งเป็นขั้นตอนแรกในการห้ามคำสั่งซื้อที่มีโครงสร้างไม่ดี พิสูจน์ง่าย ๆ เป็นเป้าหมายสำคัญในการออกแบบภาษา
Rob

8

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

กระบวนทัศน์การเขียนโปรแกรมบางอย่างวิวัฒนาการมาจากวิสัยทัศน์ทางทฤษฎีของการคำนวณ ภาษาอย่าง Lisp วิวัฒนาการมาจากแลมบ์ดาแคลคูลัสและความคิดเกี่ยวกับmeta-circularityของภาษา (คล้ายกับการสะท้อนแสงในภาษาธรรมชาติ) ฮอร์นส่วนคำสั่งบิดาและการเขียนโปรแกรม จำกัด ตระกูลอัลกอลเป็นหนี้ของแลมบ์ดาแคลคูลัส แต่ไม่มีการสะท้อนกลับในตัว

เสียงกระเพื่อมเป็นตัวอย่างที่น่าสนใจเนื่องจากมันได้รับการทดสอบนวัตกรรมทางภาษาโปรแกรมจำนวนมาก

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

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

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

ตัวอย่าง: การสร้างการวางแนววัตถุใหม่

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

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

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

สมมติว่าฉันต้องการสร้างคลาสที่เรียกว่าเวกเตอร์ซึ่งเป็นตัวแทนเวกเตอร์ 2 มิติด้วยวิธีการ ได้แก่ : การบวกเวกเตอร์, ขนาดเวกเตอร์และการขนาน

function vectorrec () {  
  function createrec(x,y) { return [x,y] }  
  function xcoordrec(v) { return v[0] }  
  function ycoordrec(v) { return v[1] }  
  function plusrec (u,v) { return [u[0]+v[0], u[1]+v[1]] }  
  function sizerec(v) { return sqrt(v[0]*v[0]+v[1]*v[1]) }  
  function parallelrec(u,v) { return u[0]*v[1]==u[1]*v[0]] }  
  return [createrec, xcoordrec, ycoordrec, plusrec, sizerec, parallelrec]  
  }  

จากนั้นฉันสามารถกำหนดเวกเตอร์ที่สร้างให้กับชื่อฟังก์ชั่นจริงที่จะใช้

[เวกเตอร์, xcoord, ycoord, vplus, vsize, vparallel] = vectorclass ()

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

เราสามารถสร้างคอลเล็กชันอื่นในพิกัดเชิงขั้วได้

function vectorpol () {  
  ...  
  function pluspol (u,v) { ... }  
  function sizepol (v) { return v[0] }  
  ...  
  return [createpol, xcoordpol, ycoordpol, pluspol, sizepol, parallelpol]  
  }  

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

function vector () {  
    ...  
    function plusrec (u,v) { ... }  
    ...  
    function pluspol (u,v) { ... }  
    ...  
    function plus (u,v) { if u[2]='rec' and v[2]='rec'  
                            then return plusrec (u,v) ... }  

    return [ ..., plus, ...]  
    }

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

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

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

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

ฉันจะหยุดที่นี่ในการสร้างสิ่งอำนวยความสะดวกเชิงวัตถุ

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

ผู้ใช้คนแรกของการวางแนววัตถุได้ทำการทดลองแนวคิดด้วยวิธีดังกล่าว และโดยทั่วไปแล้วจะเป็นจริงในการปรับปรุงภาษาการเขียนโปรแกรมจำนวนมาก แน่นอนว่าการวิเคราะห์เชิงทฤษฎีก็มีบทบาทและช่วยให้เข้าใจหรือปรับปรุงแนวคิดเหล่านี้

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

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

ผมเชื่อว่าหนังสือที่ดีที่จะเข้าใจทั้งหมดนี้อาจจะAbelson & Sussman:โครงสร้างและการแปลความหมายของโปรแกรมคอมพิวเตอร์


8

ฉันคิดว่าประวัติศาสตร์เป็นเรื่องเล็กน้อย

ยุคตั้งแต่กลางทศวรรษ 1960 ถึงกลางปี ​​1970 เป็นที่รู้จักกันในปัจจุบันในชื่อ "วิกฤตการณ์ซอฟต์แวร์" ฉันไม่สามารถทำให้ดีกว่า Dijkstra ในการบรรยายรางวัลทัวริงของเขาจากปี 1972:

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

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

น่าแปลกใจที่มันเป็นช่วงเวลาที่อุดมสมบูรณ์อย่างน่าทึ่งในการวิจัยการเขียนโปรแกรม ก่อนกลางทศวรรษที่ 1960 เรามี LISP และ AP / L แต่ภาษา "หลัก" เป็นขั้นตอนพื้นฐาน: FORTRAN, ALGOL, COBOL, PL / I และอื่น ๆ ตั้งแต่กลางทศวรรษ 1960 ถึงกลางปี ​​1970 เราได้รับโลโก้, Pascal, C, Forth, Smalltalk, Prolog, ML และ Modula และนั่นไม่นับ DSL เช่น SQL และรุ่นก่อน

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

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

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

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

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

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

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

เวลาจากช่วงกลางทศวรรษ 1980 ถึงกลางปี ​​1990 ก็เป็นช่วงเวลาในประวัติศาสตร์เช่นกันเมื่อสิ่งต่าง ๆ เปลี่ยนแปลงไป ในช่วงเวลานี้เรามีคอมพิวเตอร์ 32 บิตราคาถูกที่แพร่หลายดังนั้นธุรกิจและบ้านจำนวนมากสามารถที่จะวางคอมพิวเตอร์ที่มีประสิทธิภาพเกือบเท่ากับเมนเฟรมต่ำสุดของวันบนโต๊ะทุกโต๊ะ มันก็เป็นความมั่งคั่งของนี่ก็เป็นยุคของการเพิ่มขึ้นของ GUI ที่ทันสมัยและระบบปฏิบัติการเครือข่าย

ในบริบทนี้การวิเคราะห์และออกแบบเชิงวัตถุเกิดขึ้น

อิทธิพลของ OOAD, ผลงานของ "สาม Amigos" (Booch, Rumbar และ Jacobson) และอื่น ๆ (เช่นวิธี Shlaer-Mellor, การออกแบบที่ขับเคลื่อนด้วยความรับผิดชอบ ฯลฯ ) ไม่สามารถพูดได้ นี่คือเหตุผลที่ว่าทำไมภาษาใหม่ส่วนใหญ่ที่ได้รับการพัฒนามาตั้งแต่ต้นปี 1990 (อย่างน้อยก็ส่วนใหญ่ที่คุณเคยได้ยิน) มีวัตถุสไตล์ Simula

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

ตั้งแต่นั้นมาเนื่องจากเรามีค้อนเราใช้ OOP กับปัญหาทุกอย่างที่เกิดขึ้นตั้งแต่นั้นมา OOAD และโมเดลวัตถุที่ใช้สนับสนุนและเปิดใช้งานการพัฒนาแบบขับเคลื่อนและทดสอบแบบคลัสเตอร์และระบบกระจายอื่น ๆ และอื่น ๆ

GUIs ที่ทันสมัยและระบบปฏิบัติการใด ๆ ที่ได้รับการออกแบบในช่วง 20 ปีที่ผ่านมามีแนวโน้มที่จะให้บริการในฐานะวัตถุดังนั้นภาษาใหม่ที่จำเป็นต้องใช้ในการเขียนโปรแกรมเชิงปฏิบัติอย่างน้อยที่สุดก็เป็นวิธีการผูกกับระบบที่เราใช้ในปัจจุบัน

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

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


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

1
OOP ปรากฏตัวครั้งแรกในSimula-67 (การจำลอง) ในองค์กรภายในของระบบปฏิบัติการ (ความคิดของ "คลาสอุปกรณ์" ในระบบปฏิบัติการยูนิกซ์นั้นเป็นคลาสที่ไดรเวอร์สืบทอดมา) Parnas ' "ในเกณฑ์ที่จะใช้ในการย่อยสลายระบบในโมดูล" , CACM 15:12 (1972), หน้า 1052-1058, ภาษาModulaของ Wirth จากอายุเจ็ดสิบ "ประเภทข้อมูลนามธรรม" ล้วนเป็นบรรพบุรุษในทางเดียวหรือ อื่น ๆ
vonbrand

นั่นเป็นความจริงทั้งหมด แต่ฉันยืนยันว่า OOP ไม่ได้ถูกมองว่าเป็น "วิธีแก้ปัญหาของการโปรแกรมเชิงกระบวนงาน" จนถึงช่วงกลางทศวรรษที่ 70 การนิยาม "OOP" นั้นยากมาก การใช้คำดั้งเดิมของ Alan Kay ไม่เห็นด้วยกับแบบจำลองของ Simula และน่าเสียดายที่โลกได้สร้างแบบจำลองของ Simula แบบจำลองวัตถุบางอย่างมีการตีความเหมือน Curry-Howard แต่ Simula ไม่มี Stepanov อาจถูกต้องเมื่อเขากล่าวว่าการสืบทอดนั้นไม่ปลอดภัย
นามแฝง

6

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

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

ว่าฉันต้องการเขียนการ์ดเกมใน Python ฉันจะแสดงบัตรอย่างไร

ถ้าฉันไม่รู้เกี่ยวกับ OOP ฉันอาจทำเช่นนี้:

cards=["1S","2S","3S","4S","5S","6S","7S","8S","9S","10S","JS","QS","KS","1H","2H",...,"10C","JC","QC","KC"]

ฉันอาจเขียนโค้ดเพื่อสร้างการ์ดเหล่านั้นแทนที่จะเขียนด้วยมือ แต่คุณจะได้คะแนน "1S" หมายถึง 1 ของ Spades "JD" หมายถึง Jack of Diamonds และอื่น ๆ ฉันต้องการรหัสสำหรับ Joker ด้วย แต่เราจะแกล้งทำเป็นไม่มีโจ๊กเกอร์ในตอนนี้

ตอนนี้เมื่อฉันต้องการสับไพ่ฉันต้อง "สลับ" รายการเท่านั้น จากนั้นเมื่อต้องการถอดการ์ดออกจากบนสุดของดาดฟ้าฉันป๊อปอัพรายการบนสุดของรายการโดยให้สาย ง่าย

ตอนนี้ถ้าฉันต้องการทราบว่าฉันทำงานกับการ์ดใดเพื่อแสดงให้ผู้เล่นเห็นฉันต้องการฟังก์ชั่นเช่นนี้:

def card_code_to_name(code):
    suit=code[1]

    if suit=="S":
        suit="Spades"
    elif suit=="H"
        suit="Hearts"
    elif suit=="D"
        suit="Diamonds"
    elif suit=="C"
        suit="Clubs"

    value=code[0]

    if value=="J":
        value="Jack"
    elif value="Q":
        value="Queen"
    elif value="K"
        value="King"

    return value+" of "+suit

ใหญ่ยาวและไร้ประสิทธิภาพเล็กน้อย แต่ใช้งานได้ (และไม่มีเสียงแหลมมาก แต่อยู่ข้างจุดนี้)

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

cardpositions=( (1,1), (2,1), (3,1) ...)

จากนั้นฉันเขียนรหัสของฉันเพื่อให้ดัชนีตำแหน่งของการ์ดแต่ละใบในรายการเหมือนกับดัชนีของการ์ดในเด็ค

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

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

ทีนี้ลองใช้วิธี OOP กัน

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

class Card:

    def __init__(self,value,suit,pos,sprite,flipped=False):
        self.value=value
        self.suit=suit
        self.pos=pos
        self.sprite=sprite
        self.flipped=flipped

    def __str__(self):
        return self.value+" of "+self.suit

    def flip(self):
        if self.flipped:
            self.flipped=False
            self.sprite=load_card_sprite(value, suit)
        else:
            self.flipped=True
            self.sprite=load_card_back_sprite()

deck=[]
for suit in ("Spades","Hearts","Diamonds","Clubs"):
    for value in ("1","2","3","4","5","6","7","8","9","10","Jack","Queen","King"):
        sprite=load_card_sprite(value, suit)
        thecard=Card(value,suit,(0,0),sprite)
        deck.append(thecard)

ทันใดนั้นทุกอย่างก็ง่ายขึ้นมาก ถ้าฉันต้องการย้ายไพ่ฉันไม่ต้องคิดว่ามันอยู่ที่ไหนในสำรับแล้วใช้มันเพื่อให้ได้ตำแหน่งของมันออกมาจากตำแหน่งต่าง ๆ thecard.pos=newposผมก็ต้องบอกว่า เมื่อฉันนำการ์ดออกจากรายการสำรับหลักฉันไม่จำเป็นต้องสร้างรายการใหม่เพื่อเก็บข้อมูลอื่น ๆ ทั้งหมด เมื่อวัตถุการ์ดเคลื่อนที่คุณสมบัติทั้งหมดจะเคลื่อนที่ไปพร้อมกับมัน และถ้าฉันต้องการการ์ดที่ทำงานแตกต่างกันเมื่อพลิกฉันไม่จำเป็นต้องแก้ไขฟังก์ชั่นการพลิกในรหัสหลักของฉันเพื่อตรวจจับการ์ดเหล่านี้และทำงานที่แตกต่างกัน ฉันต้อง subclass Card และปรับฟังก์ชั่น flip () บน subclass

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

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


1
หากสิ่งเดียวที่คุณนำออกจาก OOP คือ "การจัดการหน่วยความจำ" ฉันไม่คิดว่าคุณจะเข้าใจมันเป็นอย่างดี มีปรัชญาการออกแบบทั้งหมดและขวด "แก้ไขโดยการออกแบบ" ที่ใจกว้าง! นอกจากนี้การจัดการหน่วยความจำก็ไม่มีอะไรเกิดขึ้นกับการวางแนววัตถุ (C ++?) ถึงแม้ว่าความต้องการมันจะเด่นชัดขึ้น
Raphael

แน่นอน แต่นั่นเป็นเวอร์ชันเต็มประโยค และฉันใช้คำศัพท์ในลักษณะที่ไม่เป็นมาตรฐานเช่นกัน อาจเป็นการดีกว่าถ้าพูดว่า "การจัดการข้อมูล" มากกว่า "การจัดการหน่วยความจำ"
Schilcote

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

3

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

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

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

ฉันคิดว่าการตอบคำถามของคุณง่ายขึ้นหากคุณมองในแง่ที่น้อยกว่า - ไม่ใช่ 'มันแก้ปัญหาอะไร' แต่เพิ่มเติมจากมุมมองของ 'นี่คือปัญหาและนี่คือวิธีที่ทำให้ง่ายขึ้น' ในกรณีพอร์ตอนุกรมของฉันโดยเฉพาะเรามี #ifdefs เวลารวบรวมที่เพิ่มและลบรหัสที่เปิดและปิดพอร์ตอนุกรมแบบคงที่ ฟังก์ชั่นเปิดพอร์ตนั้นถูกเรียกไปทั่วทุกที่และสามารถอยู่ที่ใดก็ได้ในบรรทัดรหัส OS ขนาด 100k ที่เรามีและ IDE ไม่ได้เทาในสิ่งที่ไม่ได้กำหนดไว้ - คุณต้องติดตามมันด้วยตนเองและ พกมันไว้ในหัวของคุณ อย่างหลีกเลี่ยงไม่ได้คุณอาจมีงานหลายอย่างที่พยายามเปิดพอร์ตอนุกรมที่กำหนดโดยคาดว่าอุปกรณ์ของพวกเขาจะอยู่ที่ปลายอีกด้านหนึ่งจากนั้นก็ไม่มีรหัสที่คุณเพิ่งเขียนงานและคุณไม่สามารถหาสาเหตุได้

สิ่งที่เป็นนามธรรมถึงแม้จะยังอยู่ใน C ซึ่งเป็น 'คลาส' ของพอร์ตอนุกรม (ดีแค่โครงสร้างของข้อมูล) ที่เรามีอาร์เรย์ - หนึ่งสำหรับแต่ละพอร์ตอนุกรม - และแทนที่จะมี [DMA เทียบเท่าในพอร์ตอนุกรม] "OpenSerialPortA" "SetBaudRate" ฟังก์ชั่นอื่น ๆ ที่เรียกว่าโดยตรงบนฮาร์ดแวร์จากงานเราเรียกว่าฟังก์ชั่นผู้ช่วยที่คุณผ่านพารามิเตอร์การสื่อสารทั้งหมด (baud, parity, ฯลฯ ) ไปยังซึ่งเป็นครั้งแรกที่ตรวจสอบอาร์เรย์โครงสร้างเพื่อดูว่า พอร์ตถูกเปิดแล้ว - ถ้าเป็นเช่นนั้นงานใดบ้างที่จะบอกคุณว่าเป็น debug printf เพื่อให้คุณสามารถข้ามไปยังส่วนของรหัสที่คุณต้องการปิดการใช้งานได้ทันทีและหากไม่ทำเช่นนั้นจะดำเนินการตั้งค่า พารามิเตอร์ทั้งหมดผ่านฟังก์ชั่นการประกอบ HAL ของพวกเขาและในที่สุดก็เปิดพอร์ต

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


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

2
@ DavidRicherby โดยที่เรามีไลบรารี่ขั้นตอน แต่นั่นคือสิ่งที่เราคัดค้านมันไม่ได้เกี่ยวกับรหัสเท่านั้น ประเด็นคือเราทำสิ่งนี้ย้อนหลัง ไม่มีใครพยายาม OOP อะไรมันแค่เกิดขึ้นเองตามธรรมชาติ
paIncrease

@DavidRicherby คุณสามารถยกตัวอย่างการใช้งานไลบรารี่ขั้นตอนเพื่อให้แน่ใจว่าเรากำลังพูดถึงสิ่งเดียวกันหรือไม่?
paIncrease

2
ขอบคุณสำหรับคำตอบและ +1 เมื่อนานมาแล้วโปรแกรมเมอร์ผู้มีประสบการณ์อีกคนเล่าว่า OOP ทำให้โครงการของเขาน่าเชื่อถือมากขึ้นforum.devshed.com/programming-42/ อย่างไรฉันคิดว่า OOP ได้รับการออกแบบมาอย่างชาญฉลาดโดยผู้เชี่ยวชาญบางคนที่อาจประสบปัญหาในการดำเนินการตามขั้นตอน
user31782

2

มีมากมาย เรียกร้องและความตั้งใจมากมายเกี่ยวกับสิ่งที่ / ที่การเขียนโปรแกรม OOP มีความได้เปรียบมากกว่าการเขียนโปรแกรมตามขั้นตอนรวมถึงนักประดิษฐ์และผู้ใช้ แต่เพียงเพราะเทคโนโลยีถูกออกแบบมาเพื่อวัตถุประสงค์บางอย่างโดยนักออกแบบไม่รับประกันว่าจะประสบความสำเร็จในวัตถุประสงค์เหล่านั้น นี่คือความเข้าใจที่สำคัญในสาขาวิศวกรรมซอฟต์แวร์ย้อนไปถึงเรียงความที่มีชื่อเสียงของ Brooks "No bullet bullet"ซึ่งยังคงมีความเกี่ยวข้องแม้จะมีการปฏิวัติรหัส OOP (ดูGartner Hype Cycleสำหรับเทคโนโลยีใหม่)

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

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

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

  • การเปรียบเทียบความเข้าใจของโปรแกรมเชิงวัตถุและขั้นตอนโดยโปรแกรมเมอร์มือใหม่ที่โต้ตอบกับคอมพิวเตอร์ ซูซาน Wiedenbeck, Vennila Ramalingam, Suseela Sarasamma, Cynthia L Corritore (1999)

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

ดูสิ่งนี้ด้วย:


1
ฉันเคารพการศึกษาทดลอง อย่างไรก็ตามมีปัญหาในการตรวจสอบว่าพวกเขาตอบคำถามที่ถูกต้อง มีตัวแปรมากเกินไปในสิ่งที่อาจเรียกว่า OOP และในการใช้มันเพื่อให้การศึกษาครั้งเดียวมีความหมาย imho เช่นเดียวกับหลายสิ่งหลายอย่างในการเขียนโปรแกรม, OOP ถูกสร้างขึ้นโดยผู้เชี่ยวชาญเพื่อตอบสนองความต้องการของตัวเอง เมื่อพูดถึงประโยชน์ของ OOP (ซึ่งฉันไม่ได้ใช้เป็นหัวข้อของ OP ซึ่งค่อนข้างจะระบุว่าข้อบกพร่องของการเขียนโปรแกรมเชิงโพรซีเดอร์) อาจจะถามว่า: คุณสมบัติอะไรสำหรับใครวัตถุประสงค์อะไร จากนั้นจะทำการศึกษาภาคสนามอย่างมีความหมายเท่านั้น
babou

1
คำเตือนเรื่องบันทึกย่อ:หากปัญหามีขนาดเล็ก (เช่นมากถึงประมาณ 500-1,000 บรรทัดของรหัส) OOP ไม่ได้สร้างความแตกต่างให้กับประสบการณ์ของฉัน หากปัญหามีขนาดใหญ่และมี "ชิ้นส่วนที่สามารถเปลี่ยนแทนได้" บางรูปแบบที่ยิ่งกว่านั้นจะต้องเพิ่มในภายหลัง (หน้าต่างใน GUI อุปกรณ์ในระบบปฏิบัติการ ... ) องค์กร OOP จะไม่สามารถหลีกเลี่ยงได้ แน่นอนคุณสามารถตั้งโปรแกรม OOP โดยไม่รองรับภาษา (ดูเช่นเคอร์เนล Linux)
vonbrand

1

ระวัง. อ่านคลาสสิกโดยอาร์คิง "แมวของฉันเป็นวัตถุเชิง" ใน "แนวคิดเชิงวัตถุฐานข้อมูลและแอปพลิเคชัน" (Kim and Lochovsky, eds) (ACM, 1989) "การวางเชิงวัตถุ" เป็นคำที่ฉวัดเฉวียนมากกว่าแนวคิดที่ชัดเจน

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


0

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


ปัญหาความปลอดภัยของข้อมูลมีอยู่ในขั้นตอนการโปรแกรมมิง?
user31782

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

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

ถ้าคุณไม่ประกาศทั่วโลกมันไม่ใช่ตัวแปรทั่วโลก
มนู

1
"ปลอดภัย" หรือ "ถูกต้อง" ไม่ได้มีความหมายอะไรเลยหากไม่มีสเปค สิ่งเหล่านี้เป็นความพยายามที่จะใส่ข้อมูลจำเพาะเกี่ยวกับรหัสไปยังเป้าหมายนั้น: ประเภท, คำจำกัดความของคลาส, DesignByContract ฯลฯ คุณได้รับ "ความปลอดภัย" ในแง่ที่ว่าคุณสามารถทำให้ขอบเขตข้อมูลส่วนตัวไม่สามารถทำลายได้ สมมติว่าคุณต้องปฏิบัติตามชุดคำสั่งเครื่องเสมือนเพื่อดำเนินการ การวางแนววัตถุจะไม่ซ่อนหน่วยความจำภายในจากใครบางคนที่สามารถอ่านหน่วยความจำโดยตรงและการออกแบบโพรโทคอลวัตถุที่ไม่ดีกำลังส่งความลับโดยการออกแบบ
Rob
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.