การเขียนโปรแกรมแบบไม่เน้นวัตถุในภาษาเชิงวัตถุ [ปิด]


15

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

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

PS: ฉันไม่ได้ขอให้ที่นี่เพื่อบอกข้อดีของการเขียนโปรแกรมเชิงวัตถุมากกว่าการเขียนโปรแกรมตามขั้นตอน


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

3
ฉันไม่เคยมีปัญหาเลย ภาษาเป็นเครื่องมือที่กำหนดให้กับทีมและ / หรือสถาปัตยกรรมอื่น ๆ


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

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

คำตอบ:


25

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

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


หากโปรแกรม "แบบฝึกหัด" อย่างง่ายเริ่มที่จะพัฒนาวิธีที่ดีที่สุดคือการนำโปรแกรมไปใช้ในลักษณะที่สามารถนำกลับมาใช้ใหม่ได้ในภายหลัง ขอบคุณสำหรับการแบ่งปัน :) +1
FaizanRabbani

@CarlSmith: อย่างแน่นอน แต่เมื่อฉันเขียนคำตอบของฉันฉันพยายามที่จะมุ่งเน้นไปที่จุดและขนาดของคำถามจริง
Doc Brown

10

โปรแกรมเมอร์มืออาชีพทำการเรียกวิจารณญาณว่าจะใช้ OOP หรือไม่อย่างไร มันจะเป็นประโยชน์สำหรับฉันจริงๆ

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

โครงการส่วนใหญ่นั้นไม่ค่อยชัดเจนนัก จุดตัดสินใจที่สองคือเมื่อส่วนย่อยของโครงการโตขึ้นเป็นจำนวนมากของคำสั่ง if-then หรือคำสั่ง switch-case และโดยเฉพาะอย่างยิ่งเมื่อคำสั่ง if-then ต้องใช้รหัสการติดตั้งจำนวนมากเพื่อให้ทำงานได้อย่างถูกต้อง ฉันรู้สึกว่าตัวเองเริ่มสูญเสียตรรกะของสิ่งที่ฉันพยายามทำให้สำเร็จและรหัสก็เริ่มรู้สึกเปราะบาง ณ จุดนั้นมันมักจะเป็นสัญญาณว่าถึงเวลาที่จะ refactor รหัสในชั้นเรียนฐานกับการใช้งานที่เฉพาะเจาะจง

ส่วนใหญ่ของการสลับเป็นลักษณะเชิงวัตถุเมื่อเทียบกับลักษณะการทำงานคือการแปลงคำสั่ง if-then เป็นคำสั่ง "เรียกใช้การกระทำนี้" แทนที่จะเป็นชุดคำสั่ง if-then ขนาดใหญ่คุณเพียงบอกรหัสให้เรียกใช้การกระทำของมัน การทำงานใดที่ทำงานจริงขึ้นอยู่กับการใช้งานที่คุณให้

ตัวอย่างเช่นนี่คือสไตล์การทำงานใน C # -style pseudocode:

if ( action == "email" ) { 
    callEmailFunction(userInfo);
}
else if ( action == "sms" ) { 
    callSmsFunction(userInfo);
}
else if ( action == "web" ) { 
    endpoint = "http://127.0.0.1/confirm";
    confirmWeb(endpoint, userinfo);
} 
...

แต่บางทีคุณอาจจะเขียนมันใหม่แบบนี้:

interface IConfirmable {
    void Confirm(UserInfo userinfo);
}

public class ConfirmEmail : IConfirmable { 
    public void Confirm(UserInfo userinfo) {
        // do the appropriate thing to confirm via email
    }
}

public class ConfirmSms : IConfirmable { 
    public void Confirm(UserInfo userinfo) {
        // do the appropriate thing to confirm via email
    }
}

public class ConfirmWeb : IConfirmable { 
    // this is a constructor
    public ConfirmWeb(string endpoint) { 
        ...
    }

    public void Confirm(UserInfo userinfo) {
        // do the appropriate thing to confirm via web
    }
} 

แล้วรหัสเอง:

// An implementation that decides which implementation of the base class to use
// This replaces the if-then statements in the functional programmming.
IConfirmable confirmer = ConfirmerFactory.GetConfirmer();

// get the userinfo however you get it, 
// which would be the same way you get it in the functional example.
UserInfo userinfo = ...;

// perform the action.
confirmer.Confirm(userinfo);

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

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


+1 สำหรับการวิเคราะห์อย่างละเอียด :) ฉันมีความคิดเล็กน้อยเกี่ยวกับเรื่องนี้
FaizanRabbani

1
นอกเหนือ: โปรดหยุดโพสต์ความคิดเห็น "ขอบคุณ" ในทุกคำตอบ เราต้องการเน้นเฉพาะคำถามและคำตอบไม่ใช่การสนทนา
Philip Kendall

5
ตัวอย่างนั้นมีความจำเป็นมากกว่าการใช้งาน
OrangeDog

cf เลย รูปแบบห่วงโซ่ของความรับผิดชอบ
Eric

1
เพียงแค่ทราบเมื่อคุณเอนตัวไปที่ if / else หรือ switch statement มันเป็นตัวเลือกที่จะพิจารณาตาราง lookupt บางประเภท ดังนั้นวิธีการเขียนใหม่ที่ไปตามเส้นของvar dict = new Dictionary<string,Action<UserInfo>{ { "email", callEmailFunction }, { "sms", callSmsFunction } }; dict[ action ]( userInfo );(dict อาจเป็นแบบคงที่, การจัดการข้อผิดพลาดถูกละเว้น)
stijn

3

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


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

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