ใน MVC ถือว่าเป็นแนวปฏิบัติที่ดีที่จะมีฟังก์ชั่นส่วนตัวที่ไม่ใช่แอ็คชั่นในคลาสคอนโทรลเลอร์หรือไม่?


10

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

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

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

คำตอบ:


16

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

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

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


+1 สำหรับการเปรียบเทียบความคิดสร้างสรรค์ :) คุณสร้างประเด็นที่น่าสนใจ โดยเฉพาะอย่างยิ่งในการสร้างนิสัยที่ไม่ดี ขอบคุณ.
เดวิด 'ขิงหัวล้าน'

8

คำตอบที่ดีที่สุดที่ฉันสามารถให้ได้คืออ้างจากหนังสือยอดเยี่ยมของ Robert Martin "Clean Code" ที่ฉันขอแนะนำให้ทุกคนที่สนใจในเรื่องนี้:

กฎข้อแรกของฟังก์ชั่นคือมันควรมีขนาดเล็ก กฎข้อที่สองคือพวกเขาควรจะเล็กกว่านั้น

ไม่สามารถพูดได้ดีกว่า มีการอ้างอิงที่ดีเยี่ยมจากหนังสือเล่มเดียวกันอีก:

ฟังก์ชั่นควรทำสิ่งหนึ่ง พวกเขาควรทำมันให้ดี พวกเขาควรทำมันเท่านั้น

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

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


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

1
@Aaraught ฉันคลุมเครือกับ "ตรรกะบางอย่าง" สิ่งที่ฉันมีอยู่ในใจคือ Backbone.js ไลบรารี่ที่คุณใส่เหตุการณ์ผู้ใช้และฟังก์ชั่นเพื่อจัดการกับพวกเขาในมุมมองของคุณ ใน MVC แบบคลาสสิกนี่คืองานของคอนโทรลเลอร์ อย่างไรก็ตามสิ่งนี้อาจไม่สามารถทำได้เนื่องจากคุณจะต้องปรับทั้ง View และ Controller ในแต่ละครั้งที่ UI ของคุณเปลี่ยนไป โดยการวางฟังก์ชั่นตัวจัดการ UI ของคุณในมุมมองคุณจะต้องปรับมุมมอง นั่นเป็นเพียงมุมมองส่วนตัวของฉัน - ฉันขาดอะไรไปหรือเปล่า
Dmitri Zaitsev

1
เพียงเพราะสิ่งที่ได้รับการส่งมอบในด้านลูกค้าไม่ได้หมายความว่ามันเป็นส่วนหนึ่งของมุมมองเหตุผล การผูกข้อมูลในมุมมองแน่นอน แต่ Backbone เป็นกรอบ MV * (ชนิดของ MVC ชนิด MVP ไม่ใช่อย่างใดอย่างหนึ่ง) และสคริปต์ฝั่งไคลเอ็นต์ของคุณควรจัดระเบียบตามนั้น ไม่อย่างนั้นคุณก็แค่แฮ็ค
Aaronaught

0

ใน MVC ฉันลองและตรวจสอบให้แน่ใจว่าคอนโทรลเลอร์ของฉันนั้น "ผอม" ที่สุดเท่าที่จะเป็นไปได้และรุ่นของฉันก็จะเป็นใบ้ที่สุด

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

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

เราพัฒนาเว็บไซต์ MVC ของเรากับหน่วยงานฐานข้อมูลทั้งหมดของเรา (ไม่ใช่รุ่น mvc ของเรา, ฐานข้อมูลจริงของเรา), ที่เก็บข้อมูลของเรา, คลาสผู้ช่วยของเราและตรรกะของเราในการแยก dll เดี่ยว ๆ เรามีเพียงแค่ทุกคนมีเว็บไซต์เดียว แต่เราก็ทำอย่างนี้ต่อไป

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


2
โมเดลใน MVC เป็นเลเยอร์เดียวที่ไม่ควรโง่ หากสมาร์ทไม่ได้อยู่ในรูปแบบและพวกเขาไม่ได้อยู่ในตัวควบคุมแล้วพวกเขาอยู่ที่ไหน ... ในมุมมอง? ผู้ควบคุมไม่ควรทดสอบยาก ความสามารถในการใช้ DI และ fakes / mocks เพื่ออำนวยความสะดวกในการทดสอบหน่วยเป็นหนึ่งในการดึง MVC ผ่านกรอบงานอื่น ๆ การทดสอบคอนโทรลเลอร์ส่วนใหญ่ของฉันต่ำกว่า 5 บรรทัด
Aaronaught

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

ฉันมีความรู้สึกว่าคำตอบนี้มีความหมายดี แต่เป็นคำที่ไม่ถูกต้อง .. หรืออาจจะเป็นคำศัพท์ที่แตกต่างกัน
Simon Whitehead

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

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

-2

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

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

จำไว้เสมอว่าหลักการจูบ: ทำให้มันง่ายโง่


5
นั่นไม่ใช่เหตุผลที่ดีในการหลีกเลี่ยงวิธีการแบบส่วนตัวและไม่มีอะไรเกี่ยวข้องกับสถาปัตยกรรม MVC คุณไม่พยายามทดสอบวิธีการส่วนตัว แต่ควรทดสอบด้วยวิธีสาธารณะ หากคุณไม่สามารถครอบคลุมพวกเขาได้นั่นเป็นสัญญาณว่าชั้นของคุณซับซ้อนเกินไปและจำเป็นต้องได้รับการปรับสภาพใหม่ ไม่ได้หมายความว่าคุณไม่ควรมีวิธีการส่วนตัวหรือ (ฉันหวังเป็นอย่างยิ่งว่านี่ไม่ใช่สิ่งที่คุณหมายถึงจริง ๆ ) ว่าพวกเขาควรเป็นแบบสาธารณะแทน
Aaronaught
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.