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

ขั้นตอนของการออกแบบระบบ
- ระบบซอฟต์แวร์. ออกแบบแอปพลิเคชันโดยรวม
- แบ่งออกเป็นระบบย่อย/แพ็คเกจ กำหนดส่วนที่แตกต่างกันอย่างมีเหตุผลและกำหนดกฎสำหรับการโต้ตอบระหว่างกัน
- การแบ่งระบบย่อยออกเป็นคลาส แบ่งส่วนต่างๆ ของระบบออกเป็นคลาสและอินเทอร์เฟซเฉพาะ และกำหนดการโต้ตอบระหว่างกัน
- การแบ่งชั้นเรียนเป็นวิธีการ สร้างคำจำกัดความที่สมบูรณ์ของเมธอดที่จำเป็นสำหรับคลาส ตามความรับผิดชอบที่ได้รับมอบหมาย
- การออกแบบวิธีการ สร้างคำจำกัดความโดยละเอียดของฟังก์ชันการทำงานของแต่ละวิธี
หลักการและแนวคิดทั่วไปในการออกแบบระบบ
การเริ่มต้นขี้เกียจ ในสำนวนการเขียนโปรแกรมนี้ แอปพลิเคชันจะไม่เสียเวลาในการสร้างวัตถุจนกว่าจะใช้งานจริง สิ่งนี้จะเร่งกระบวนการเริ่มต้นและลดภาระของตัวรวบรวมขยะ ที่กล่าวว่าคุณไม่ควรใช้สิ่งนี้มากเกินไปเพราะอาจละเมิดหลักการของโมดูลาร์ได้ บางทีมันอาจจะคุ้มค่าที่จะย้ายอินสแตนซ์ทั้งหมดของการก่อสร้างไปยังส่วนเฉพาะ ตัวอย่างเช่น วิธีการหลักหรือไปยังคลาสโรงงาน คุณลักษณะหนึ่งของรหัสที่ดีคือการไม่มีรหัสต้นแบบซ้ำๆ ตามกฎแล้วรหัสดังกล่าวจะอยู่ในคลาสแยกต่างหากเพื่อให้สามารถเรียกใช้ได้เมื่อจำเป็นอปท
ฉันต้องการทราบการเขียนโปรแกรมเชิงแง่มุมด้วย กระบวนทัศน์การเขียนโปรแกรมนี้เกี่ยวกับการแนะนำตรรกะที่โปร่งใส นั่นคือรหัสซ้ำ ๆ จะถูกใส่ในคลาส (ลักษณะ) และถูกเรียกใช้เมื่อตรงตามเงื่อนไขบางประการ ตัวอย่างเช่น เมื่อเรียกใช้เมธอดด้วยชื่อเฉพาะหรือเข้าถึงตัวแปรประเภทเฉพาะ บางครั้งแง่มุมต่างๆ อาจทำให้เกิดความสับสน เนื่องจากไม่ชัดเจนในทันทีว่าโค้ดถูกเรียกใช้จากที่ใด แต่นี่ยังคงเป็นฟังก์ชันที่มีประโยชน์มาก โดยเฉพาะอย่างยิ่งเมื่อแคชหรือเข้าสู่ระบบ เราเพิ่มฟังก์ชันนี้โดยไม่ต้องเพิ่มตรรกะเพิ่มเติมให้กับคลาสทั่วไป กฎสี่ข้อของ Kent Beck สำหรับสถาปัตยกรรมที่เรียบง่าย:- การแสดงออก — ควรแสดงเจตนาของชั้นเรียนอย่างชัดเจน สิ่งนี้เกิดขึ้นได้จากการตั้งชื่อที่เหมาะสม ขนาดที่เล็ก และการยึดมั่นในหลักการความรับผิดชอบเดียว (ซึ่งเราจะพิจารณาในรายละเอียดเพิ่มเติมด้านล่าง)
- จำนวนคลาสและวิธีการขั้นต่ำ — ถ้าคุณต้องการสร้างคลาสให้มีขนาดเล็กและเน้นแคบที่สุดเท่าที่จะเป็นไปได้ คุณอาจไปไกลเกินไป (ส่งผลให้เกิดการต่อต้านรูปแบบการผ่าตัดด้วยปืนลูกซอง) หลักการนี้เรียกร้องให้รักษาระบบให้มีขนาดกะทัดรัดและไม่มากเกินไป โดยสร้างคลาสแยกต่างหากสำหรับทุกการกระทำที่เป็นไปได้
- ไม่มีการทำซ้ำ — โค้ดที่ซ้ำกันซึ่งสร้างความสับสนและเป็นตัวบ่งชี้ถึงการออกแบบระบบที่ไม่เหมาะสมจะถูกแยกและย้ายไปยังตำแหน่งอื่น
- รันการทดสอบทั้งหมด — ระบบที่ผ่านการทดสอบทั้งหมดสามารถจัดการได้ การเปลี่ยนแปลงใด ๆ อาจทำให้การทดสอบล้มเหลว เผยให้เห็นว่าการเปลี่ยนแปลงของเราในตรรกะภายในของเมธอดยังเปลี่ยนพฤติกรรมของระบบด้วยวิธีการที่ไม่คาดคิด
แข็ง
เมื่อออกแบบระบบ หลักการ SOLID ที่รู้จักกันดีนั้นควรค่าแก่การพิจารณา:S (ความรับผิดชอบเดียว), O (เปิด-ปิด), L (การแทนที่ Liskov), I (การแยกส่วนต่อประสาน), D (การผกผันการพึ่งพา)
เราจะไม่ยึดติดกับหลักการของแต่ละคน นั่นอาจเกินขอบเขตของบทความนี้เล็กน้อย แต่คุณสามารถอ่านเพิ่มเติมได้ที่นี่อินเตอร์เฟซ
บางทีขั้นตอนที่สำคัญที่สุดขั้นตอนหนึ่งในการสร้างคลาสที่ออกแบบมาอย่างดีคือการสร้างอินเทอร์เฟซที่ออกแบบมาอย่างดีซึ่งแสดงถึงสิ่งที่เป็นนามธรรมที่ดี ซ่อนรายละเอียดการใช้งานของคลาส และนำเสนอกลุ่มของเมธอดที่สอดคล้องกันอย่างชัดเจนในเวลาเดียวกัน ลองมาดูหนึ่งในหลักการ SOLID อย่างละเอียดยิ่งขึ้น — การแยกอินเทอร์เฟซ: ไคลเอนต์ (คลาส) ไม่ควรใช้วิธีการที่ไม่จำเป็นซึ่งพวกเขาจะไม่ใช้ กล่าวอีกนัยหนึ่ง หากเรากำลังพูดถึงการสร้างอินเทอร์เฟซที่มีจำนวนเมธอดน้อยที่สุดที่มุ่งทำงานเฉพาะของอินเทอร์เฟซ (ซึ่งฉันคิดว่าคล้ายกับหลักการความรับผิดชอบเดียว) จะเป็นการดีกว่าหากสร้างอันที่เล็กกว่าสองสามอันแทน ของอินเทอร์เฟซหนึ่งป่อง โชคดีที่คลาสสามารถใช้อินเทอร์เฟซได้มากกว่าหนึ่งอินเทอร์เฟซ อย่าลืมตั้งชื่ออินเทอร์เฟซให้ถูกต้อง: ชื่อควรสะท้อนถึงงานที่ได้รับมอบหมายอย่างถูกต้องที่สุด และแน่นอนว่ายิ่งสั้นเท่าใดก็จะยิ่งทำให้เกิดความสับสนน้อยลงเท่านั้น ความคิดเห็นเกี่ยวกับเอกสารมักจะเขียนที่ระดับอินเทอร์เฟซ ความคิดเห็นเหล่านี้ให้รายละเอียดว่าแต่ละเมธอดควรทำอย่างไร ใช้อาร์กิวเมนต์ใด และส่งคืนอะไรระดับ

- ค่าคงที่สาธารณะ
- ค่าคงที่ส่วนตัว;
- ตัวแปรอินสแตนซ์ส่วนตัว
ขนาดชั้นเรียน
ตอนนี้ฉันต้องการพูดคุยเกี่ยวกับขนาดของชั้นเรียน ลองนึกถึงหลักการ SOLID ข้อหนึ่ง — หลักความรับผิดชอบเดียว มันระบุว่าวัตถุแต่ละอย่างมีจุดประสงค์เดียวเท่านั้น (ความรับผิดชอบ) และตรรกะของวิธีการทั้งหมดนั้นมีจุดมุ่งหมายเพื่อให้บรรลุผลสำเร็จ สิ่งนี้บอกเราให้หลีกเลี่ยงคลาสขนาดใหญ่ที่บวม (ซึ่งจริง ๆ แล้วเป็นรูปแบบต่อต้านวัตถุของพระเจ้า) และหากเรามีวิธีการมากมายที่มีตรรกะต่าง ๆ มากมายอัดแน่นอยู่ในคลาส เราต้องคิดที่จะแยกมันออกจากกันเป็น ส่วนตรรกะสองสามส่วน (คลาส) ซึ่งจะช่วยเพิ่มความสามารถในการอ่านโค้ด เนื่องจากจะใช้เวลาไม่นานในการทำความเข้าใจจุดประสงค์ของแต่ละเมธอด หากเราทราบจุดประสงค์โดยประมาณของคลาสที่กำหนด นอกจากนี้ จับตาดูชื่อคลาสซึ่งควรสะท้อนถึงตรรกะที่มีอยู่ ตัวอย่างเช่น ถ้าเรามีชั้นเรียนที่มีคำศัพท์มากกว่า 20 คำ เราต้องคิดถึงการปรับโครงสร้างใหม่ ชั้นเรียนที่เคารพตนเองไม่ควรมีตัวแปรภายในมากมายขนาดนั้น ในความเป็นจริง แต่ละเมธอดจะทำงานร่วมกับหนึ่งหรือสองสามวิธี ทำให้เกิดความเชื่อมโยงกันอย่างมากภายในคลาส (ซึ่งก็ตรงตามที่ควรจะเป็น เนื่องจากคลาสควรเป็นหนึ่งเดียว ผลที่ตามมาคือ การเพิ่มความสามัคคีของชั้นเรียนนำไปสู่การลดขนาดชั้นเรียน และแน่นอนว่าจำนวนชั้นเรียนก็เพิ่มขึ้นด้วย สิ่งนี้น่ารำคาญสำหรับบางคน เนื่องจากคุณต้องอ่านไฟล์คลาสเพิ่มเติมเพื่อดูว่างานขนาดใหญ่นั้นทำงานอย่างไร เหนือสิ่งอื่นใด แต่ละคลาสเป็นโมดูลขนาดเล็กที่ควรเกี่ยวข้องกับผู้อื่นให้น้อยที่สุด การแยกนี้ช่วยลดจำนวนการเปลี่ยนแปลงที่เราต้องทำเมื่อเพิ่มตรรกะเพิ่มเติมให้กับคลาส แต่ละวิธีทำงานร่วมกับหนึ่งหรือสองสามวิธี ทำให้เกิดการเชื่อมโยงกันอย่างมากภายในชั้นเรียน (ซึ่งตรงตามที่ควรจะเป็น เนื่องจากชั้นเรียนควรเป็นหนึ่งเดียวทั้งหมด) ผลที่ตามมาคือ การเพิ่มความสามัคคีของชั้นเรียนนำไปสู่การลดขนาดชั้นเรียน และแน่นอนว่าจำนวนชั้นเรียนก็เพิ่มขึ้นด้วย สิ่งนี้น่ารำคาญสำหรับบางคน เนื่องจากคุณต้องอ่านไฟล์คลาสเพิ่มเติมเพื่อดูว่างานขนาดใหญ่นั้นทำงานอย่างไร เหนือสิ่งอื่นใด แต่ละคลาสเป็นโมดูลขนาดเล็กที่ควรเกี่ยวข้องกับผู้อื่นให้น้อยที่สุด การแยกนี้ช่วยลดจำนวนการเปลี่ยนแปลงที่เราต้องทำเมื่อเพิ่มตรรกะเพิ่มเติมให้กับคลาส แต่ละวิธีทำงานร่วมกับหนึ่งหรือสองสามวิธี ทำให้เกิดการเชื่อมโยงกันอย่างมากภายในชั้นเรียน (ซึ่งตรงตามที่ควรจะเป็น เนื่องจากชั้นเรียนควรเป็นหนึ่งเดียวทั้งหมด) ผลที่ตามมาคือ การเพิ่มความสามัคคีของชั้นเรียนนำไปสู่การลดขนาดชั้นเรียน และแน่นอนว่าจำนวนชั้นเรียนก็เพิ่มขึ้นด้วย สิ่งนี้น่ารำคาญสำหรับบางคน เนื่องจากคุณต้องอ่านไฟล์คลาสเพิ่มเติมเพื่อดูว่างานขนาดใหญ่นั้นทำงานอย่างไร เหนือสิ่งอื่นใด แต่ละคลาสเป็นโมดูลขนาดเล็กที่ควรเกี่ยวข้องกับผู้อื่นให้น้อยที่สุด การแยกนี้ช่วยลดจำนวนการเปลี่ยนแปลงที่เราต้องทำเมื่อเพิ่มตรรกะเพิ่มเติมให้กับคลาส ความสามัคคีนำไปสู่การลดขนาดชั้นเรียน และแน่นอน จำนวนชั้นเรียนเพิ่มขึ้น สิ่งนี้น่ารำคาญสำหรับบางคน เนื่องจากคุณต้องอ่านไฟล์คลาสเพิ่มเติมเพื่อดูว่างานขนาดใหญ่นั้นทำงานอย่างไร เหนือสิ่งอื่นใด แต่ละคลาสเป็นโมดูลขนาดเล็กที่ควรเกี่ยวข้องกับผู้อื่นให้น้อยที่สุด การแยกนี้ช่วยลดจำนวนการเปลี่ยนแปลงที่เราต้องทำเมื่อเพิ่มตรรกะเพิ่มเติมให้กับคลาส ความสามัคคีนำไปสู่การลดขนาดชั้นเรียน และแน่นอน จำนวนชั้นเรียนเพิ่มขึ้น สิ่งนี้น่ารำคาญสำหรับบางคน เนื่องจากคุณต้องอ่านไฟล์คลาสเพิ่มเติมเพื่อดูว่างานขนาดใหญ่นั้นทำงานอย่างไร เหนือสิ่งอื่นใด แต่ละคลาสเป็นโมดูลขนาดเล็กที่ควรเกี่ยวข้องกับผู้อื่นให้น้อยที่สุด การแยกนี้ช่วยลดจำนวนการเปลี่ยนแปลงที่เราต้องทำเมื่อเพิ่มตรรกะเพิ่มเติมให้กับคลาสวัตถุ
การห่อหุ้ม
ในที่นี้เราจะพูดถึงหลักการ OOP กันก่อน: การห่อหุ้ม การซ่อนการนำไปใช้ไม่ได้เท่ากับการสร้างเมธอดเพื่อป้องกันตัวแปร (การจำกัดการเข้าถึงผ่านแต่ละเมธอด getters และ setters โดยไม่คิด ซึ่งไม่ดี เนื่องจากจุดรวมของการห่อหุ้มหายไป) การซ่อนการเข้าถึงมีเป้าหมายเพื่อสร้างสิ่งที่เป็นนามธรรม นั่นคือคลาสจัดเตรียมวิธีการที่เป็นรูปธรรมร่วมกันที่เราใช้เพื่อทำงานกับข้อมูลของเรา และผู้ใช้ไม่จำเป็นต้องรู้แน่ชัดว่าเราทำงานกับข้อมูลนี้อย่างไร — ใช้งานได้แค่นั้นก็เพียงพอแล้วกฎของดีมีเตอร์
นอกจากนี้ เรายังสามารถพิจารณากฎของดีมีเตอร์ ซึ่งเป็นกฎชุดเล็กๆ ที่ช่วยในการจัดการความซับซ้อนในระดับคลาสและเมธอด สมมติว่าเรามี วัตถุ Carและมีเมธอดmove(Object arg1, Object arg2) ตามกฎของ Demeter วิธีนี้จำกัดเฉพาะการโทร:- วิธีการของ วัตถุ รถยนต์เอง (กล่าวอีกนัยหนึ่งคือวัตถุ "นี้");
- วิธีการของวัตถุที่สร้างขึ้นภายในวิธีการย้าย
- วิธีการของวัตถุที่ส่งผ่านเป็นอาร์กิวเมนต์ ( arg1 , arg2 );
- วิธีการของวัตถุภายในรถยนต์ (อีกครั้ง "สิ่งนี้")
โครงสร้างข้อมูล
โครงสร้างข้อมูลคือชุดขององค์ประกอบที่เกี่ยวข้อง เมื่อพิจารณาว่าวัตถุเป็นโครงสร้างข้อมูล มีชุดขององค์ประกอบข้อมูลซึ่งเมธอดดำเนินการอยู่ การมีอยู่ของวิธีการเหล่านี้ถูกสันนิษฐานโดยปริยาย นั่นคือโครงสร้างข้อมูลเป็นวัตถุที่มีวัตถุประสงค์เพื่อจัดเก็บและทำงานกับ (ประมวลผล) ข้อมูลที่เก็บไว้ ความแตกต่างที่สำคัญจากอ็อบเจกต์ทั่วไปคืออ็อบเจกต์ธรรมดาคือชุดของเมธอดที่ดำเนินการกับองค์ประกอบข้อมูลที่ถือว่ามีอยู่โดยปริยาย คุณเข้าใจไหม? ลักษณะสำคัญของวัตถุธรรมดาคือวิธีการ ตัวแปรภายในช่วยอำนวยความสะดวกในการทำงานที่ถูกต้อง แต่ในโครงสร้างข้อมูล มีเมธอดเพื่อสนับสนุนงานของคุณด้วยองค์ประกอบข้อมูลที่เก็บไว้ ซึ่งเป็นสิ่งสำคัญยิ่งในที่นี้ โครงสร้างข้อมูลประเภทหนึ่งคือ Data Transfer Object (DTO) นี่คือคลาสที่มีตัวแปรสาธารณะและไม่มีเมธอด (หรือเมธอดสำหรับการอ่าน/เขียนเท่านั้น) ที่ใช้ในการถ่ายโอนข้อมูลเมื่อทำงานกับฐานข้อมูล การแยกวิเคราะห์ข้อความจากซ็อกเก็ต ฯลฯ โดยปกติข้อมูลจะไม่ถูกจัดเก็บไว้ในออบเจกต์ดังกล่าวเป็นระยะเวลานาน เกือบจะทันทีที่แปลงเป็นประเภทของเอนทิตีที่แอปพลิเคชันของเราทำงาน ในทางกลับกัน เอนทิตีก็เป็นโครงสร้างข้อมูลเช่นกัน แต่จุดประสงค์ของเอนทิตีคือการมีส่วนร่วมในตรรกะทางธุรกิจในระดับต่างๆ ของแอปพลิเคชัน วัตถุประสงค์ของ DTO คือเพื่อส่งข้อมูลไปยัง/จากแอปพลิเคชัน ตัวอย่างของ DTO: ยังเป็นโครงสร้างข้อมูล แต่จุดประสงค์คือการมีส่วนร่วมในตรรกะทางธุรกิจในระดับต่างๆ ของแอปพลิเคชัน วัตถุประสงค์ของ DTO คือเพื่อส่งข้อมูลไปยัง/จากแอปพลิเคชัน ตัวอย่างของ DTO: ยังเป็นโครงสร้างข้อมูล แต่จุดประสงค์คือการมีส่วนร่วมในตรรกะทางธุรกิจในระดับต่างๆ ของแอปพลิเคชัน วัตถุประสงค์ของ DTO คือเพื่อส่งข้อมูลไปยัง/จากแอปพลิเคชัน ตัวอย่างของ DTO:
@Setter
@Getter
@NoArgsConstructor
public class UserDto {
private long id;
private String firstName;
private String lastName;
private String email;
private String password;
}
ทุกอย่างดูชัดเจนเพียงพอ แต่ที่นี่เราเรียนรู้เกี่ยวกับการมีอยู่ของลูกผสม ไฮบริดคือวัตถุที่มีเมธอดสำหรับจัดการลอจิกที่สำคัญ จัดเก็บอิลิเมนต์ภายใน และยังรวมถึงเมธอด accessor (get/set) วัตถุดังกล่าวยุ่งเหยิงและทำให้ยากต่อการเพิ่มวิธีการใหม่ คุณควรหลีกเลี่ยงสิ่งเหล่านี้ เนื่องจากยังไม่ชัดเจนว่ามีไว้เพื่ออะไร — จัดเก็บองค์ประกอบหรือดำเนินการตรรกะ?
หลักการสร้างตัวแปร
ลองไตร่ตรองเล็กน้อยเกี่ยวกับตัวแปร โดยเฉพาะอย่างยิ่ง ลองนึกถึงหลักการที่ใช้เมื่อสร้าง:- ตามหลักการแล้ว คุณควรประกาศและเริ่มต้นตัวแปรก่อนที่จะใช้งาน (อย่าสร้างตัวแปรขึ้นมาแล้วลืมมันไปซะ)
- เมื่อใดก็ตามที่เป็นไปได้ ให้ประกาศตัวแปรเป็นขั้นสุดท้ายเพื่อป้องกันไม่ให้ค่าเปลี่ยนแปลงหลังจากเริ่มต้น
- อย่าลืมเกี่ยวกับตัวแปรตัวนับ ซึ่งเรามักจะใช้ในforวนซ้ำ บางประเภท นั่นคืออย่าลืมทำให้เป็นศูนย์ มิฉะนั้นตรรกะทั้งหมดของเราอาจพัง
- คุณควรพยายามเริ่มต้นตัวแปรในตัวสร้าง
- หากมีตัวเลือกระหว่างการใช้อ็อบเจ็กต์ที่มีการอ้างอิงหรือไม่มี ( new SomeObject() ) ให้เลือกไม่ใช้ เนื่องจากหลังจากใช้อ็อบเจ็กต์แล้ว วัตถุนั้นจะถูกลบในรอบการรวบรวมขยะรอบถัดไป และทรัพยากรของวัตถุนั้นจะไม่สูญเปล่า
- รักษาอายุการใช้งานของตัวแปร (ระยะห่างระหว่างการสร้างตัวแปรและครั้งสุดท้ายที่มีการอ้างอิง) ให้สั้นที่สุด
- เริ่มต้นตัวแปรที่ใช้ในลูปก่อนลูป ไม่ใช่ที่จุดเริ่มต้นของเมธอดที่มีลูป
- เริ่มต้นด้วยขอบเขตที่จำกัดที่สุดเสมอ และขยายเมื่อจำเป็นเท่านั้น (คุณควรพยายามสร้างตัวแปรให้อยู่ในท้องถิ่นมากที่สุด)
- ใช้แต่ละตัวแปรเพื่อจุดประสงค์เดียวเท่านั้น
- หลีกเลี่ยงตัวแปรที่มีจุดประสงค์แอบแฝง เช่น ตัวแปรที่แยกระหว่างสองงาน — หมายความว่าประเภทของตัวแปรนี้ไม่เหมาะสำหรับการแก้งานใดงานหนึ่ง
วิธีการ

จากภาพยนตร์เรื่อง "Star Wars: Episode III - Revenge of the Sith" (2548)
-
กฎข้อที่ 1 – ความกระชับ ตามหลักการแล้ว วิธีการไม่ควรเกิน 20 บรรทัด ซึ่งหมายความว่าหากเมธอดสาธารณะ "ขยาย" อย่างมาก คุณต้องคิดถึงการแยกลอจิกออกจากกันและย้ายไปยังเมธอดส่วนตัวที่แยกจากกัน
-
กฎข้อที่ 2 — if , else , whileและคำสั่งอื่นๆ ไม่ควรมีบล็อกที่ซ้อนกันอย่างหนาแน่น: การซ้อนกันจำนวนมากจะลดความสามารถในการอ่านโค้ดลงอย่างมาก ตามหลักการแล้ว คุณไม่ควรมี บล็อก{}ที่ซ้อนกันไม่เกินสองบล็อก
และควรเก็บโค้ดไว้ในบล็อกเหล่านี้ให้กะทัดรัดและเรียบง่าย
-
กฎ #3 — วิธีการควรดำเนินการเพียงครั้งเดียว นั่นคือ ถ้าเมธอดใช้ตรรกะที่ซับซ้อนทุกประเภท เราจะแบ่งเมธอดนั้นออกเป็นเมธอดย่อย เป็นผลให้วิธีการนี้จะเป็นซุ้มที่มีจุดประสงค์เพื่อเรียกการดำเนินการอื่น ๆ ทั้งหมดตามลำดับที่ถูกต้อง
แต่จะเป็นอย่างไรหากการดำเนินการดูเหมือนง่ายเกินไปที่จะแยกเป็นวิธีการอื่น จริงอยู่ บางครั้งอาจรู้สึกเหมือนยิงปืนใหญ่ใส่นกกระจอก แต่วิธีการเล็กๆ น้อยๆ ก็มีข้อดีหลายประการ:
- ความเข้าใจโค้ดที่ดีขึ้น
- วิธีการมีแนวโน้มที่จะซับซ้อนมากขึ้นเมื่อการพัฒนาดำเนินไป หากวิธีการเริ่มต้นง่าย ๆ จะทำให้ฟังก์ชันการทำงานซับซ้อนขึ้นเล็กน้อย
- รายละเอียดการใช้งานถูกซ่อนไว้
- ใช้รหัสซ้ำได้ง่ายขึ้น
- รหัสที่เชื่อถือได้มากขึ้น
-
กฎ stepdown — ควรอ่านโค้ดจากบนลงล่าง ยิ่งคุณอ่านต่ำเท่าไร คุณก็ยิ่งเจาะลึกลงไปในตรรกะมากขึ้นเท่านั้น และในทางกลับกัน ยิ่งคุณไปสูง วิธีการยิ่งเป็นนามธรรมมากขึ้นเท่านั้น ตัวอย่างเช่น คำสั่ง switch ค่อนข้างไม่กระชับและไม่พึงปรารถนา แต่ถ้าคุณไม่สามารถหลีกเลี่ยงการใช้สวิตช์ได้ คุณควรพยายามย้ายคำสั่งให้ต่ำที่สุดเท่าที่จะเป็นไปได้ ไปยังเมธอดระดับต่ำสุด
-
อาร์กิวเมนต์เมธอด — จำนวนในอุดมคติคืออะไร เป็นการดีที่ไม่มีเลย :) แต่มันเกิดขึ้นจริงเหรอ? ที่กล่าวว่า คุณควรพยายามมีข้อโต้แย้งให้น้อยที่สุด เพราะยิ่งมีน้อย วิธีการก็จะยิ่งง่ายขึ้น และการทดสอบก็ง่ายขึ้น เมื่อมีข้อสงสัย ให้พยายามคาดการณ์สถานการณ์ทั้งหมดสำหรับการใช้วิธีการด้วยพารามิเตอร์อินพุตจำนวนมาก
-
นอกจากนี้ จะเป็นการดีที่จะแยกเมธอดที่มีบูลีนแฟล็กเป็นพารามิเตอร์อินพุต เนื่องจากทั้งหมดนี้หมายความว่าเมธอดดำเนินการมากกว่าหนึ่งการดำเนินการ (หากเป็นจริง ให้ทำสิ่งหนึ่ง หากเป็นเท็จ ให้ทำอีกสิ่งหนึ่ง) ดังที่ฉันได้เขียนไว้ข้างต้น สิ่งนี้ไม่ดีและควรหลีกเลี่ยงหากเป็นไปได้
-
หากเมธอดมีพารามิเตอร์อินพุตจำนวนมาก (ค่าสุดขีดคือ 7 แต่คุณควรเริ่มคิดจริงๆ หลังจาก 2-3 ค่า) อาร์กิวเมนต์บางส่วนควรจัดกลุ่มเป็นวัตถุแยกต่างหาก
-
หากมีเมธอดที่คล้ายกัน (โอเวอร์โหลด) หลายวิธี จะต้องส่งพารามิเตอร์ที่คล้ายกันในลำดับเดียวกัน ซึ่งจะช่วยเพิ่มความสามารถในการอ่านและการใช้งาน
-
เมื่อคุณส่งพารามิเตอร์ไปยังเมธอด คุณต้องแน่ใจว่าใช้ทั้งหมดแล้ว มิฉะนั้นทำไมคุณต้องใช้ ตัดพารามิเตอร์ที่ไม่ได้ใช้ออกจากอินเทอร์เฟซและดำเนินการกับมัน
- try/catchดูไม่ค่อยดีนักในธรรมชาติ ดังนั้นจึงเป็นความคิดที่ดีที่จะย้ายไปใช้วิธีขั้นกลางแยกต่างหาก (วิธีสำหรับจัดการข้อยกเว้น):
public void exceptionHandling(SomeObject obj) { try { someMethod(obj); } catch (IOException e) { e.printStackTrace(); } }
GO TO FULL VERSION