ฉันจะใช้รูปแบบ MVC กับแอปพลิเคชัน C # WinForms ได้อย่างไร


11

ฉันเป็นนักพัฒนา C ++ ที่ใช้รูปแบบ MVC ในการออกแบบ GUI นับตั้งแต่นั้นมา

เมื่อเร็ว ๆ นี้ฉันต้องการกลับสู่ C # และฉันตั้งค่าแอปพลิเคชัน Windows Forms แต่ตอนนี้ฉันหลงทางเล็กน้อยเกี่ยวกับวิธีการผลักดันมันไปยังโครงสร้างที่สอดคล้องกับ MVC

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

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

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


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

1
@PeterM: เพราะแม้หลังจาก 10 ปี WPF sucks และยังคงช้า
whatsisname

3
ในการถอดความ @ whatsisname ความคิดเห็น WPF จะมุ่งสู่การใช้งานที่มีขนาดใหญ่ แอปพลิเคชั่นขนาดเล็กอาจให้บริการที่ดีขึ้นด้วย Winforms เนื่องจาก Winforms นั้นง่ายกว่า อย่างไรก็ตามหากคุณต้องการโต้แย้งคุณสามารถโต้แย้งว่าแอปพลิเคชั่น Winforms ของคุณนั้นเล็กพอที่มันอาจไม่ต้องการ MVP MVVM ถูกนำเข้าสู่ WPF WPF มีกราฟิกแบบเวกเตอร์ดังนั้นจึงไม่ประสบปัญหาการปรับขนาดแบบเดียวกับที่ Winforms ทำ WPF นั้นสามารถคอมโพสิตได้มาก (คุณสามารถวางตัวควบคุมไว้ในส่วนควบคุมอื่น ๆ ได้อย่างง่ายดาย) และมันก็มีการเชื่อมโยงข้อมูลของนักฆ่า ไม่ชอบอะไร
Robert Harvey

3
@whatsisname WPF อาจดูด แต่มันห่วยมากน้อยกว่า Winforms สำหรับสิ่งที่เหนือกว่าและโปรแกรมของเล่น
ปีเตอร์เอ็ม

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

คำตอบ:


3

บังเอิญฉันกำลังทำงานในโครงการ WinForms ที่มีลวดลายหลัง MVC ฉันจะไม่เรียกสิ่งนี้ว่าคำตอบที่สมบูรณ์แบบ แต่ฉันจะอธิบายการออกแบบโดยรวมของฉันและหวังว่าสิ่งนี้จะช่วยให้คุณได้มาด้วยตัวคุณเอง

จากการอ่านที่ฉันทำก่อนเริ่มโครงการนี้ดูเหมือนจะไม่มีวิธีที่ "ถูกต้อง" ในการดำเนินการนี้ ฉันทำตามหลักการออกแบบที่เรียบง่ายของ OOP และ MVC ส่วนที่เหลือคือการลองผิดลองถูกเมื่อฉันพัฒนาเวิร์กโฟลว์

MVC เป็นเพียงสถาปัตยกรรมที่ไม่เหมาะสมสำหรับกรณีการใช้งานนี้หรือไม่?

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

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

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

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

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

คิดว่าการดำเนินงานหรือคำสั่งเป็นพื้นฐานสำหรับการใช้งาน คุณต้องการให้ใบสมัครของคุณทำอะไร ทำลายมันลงไปในปฏิบัติการขั้นพื้นฐานที่สุด ตัวอย่างเช่น: CreateProject, WriteNotes, SaveProject, LoadProject เป็นต้น GUI (หรือคลาสฟอร์ม) จะเกิดเหตุการณ์บางอย่าง (เช่นกดปุ่ม) ทุกการดำเนินการมีวิธีการควบคุมที่เกี่ยวข้อง ในกรณีนี้สิ่งที่ต้องการออกง่ายเกินไป แอปพลิเคชันสามารถปิดได้จากคลาสฟอร์ม แต่สมมติว่าฉันต้องการเก็บข้อมูลแอปพลิเคชั่นบางไฟล์ไว้ก่อน? ฉันจะเรียกวิธีการ "บันทึก" จากคลาสคอนโทรลเลอร์ที่เกี่ยวข้องภายในวิธีการกดปุ่มของฉัน

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

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

ตัวอย่างเช่น: FileMenuController(การดำเนินการ: NewProject, SaveProject, LoadProject) -> ProjectServices(CreateProject, PersistProjectToFile, LoadProjectFromFile) ที่Projectจะเป็นชั้นโดเมนในรูปแบบข้อมูลของคุณ คลาส Controller และ Service ในกรณีของฉันเป็นคลาสที่ไม่สามารถใช้งานได้ทันทีด้วยวิธีการคงที่

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

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

ฉันหวังว่านี่จะช่วยให้คุณเป็นจุดเริ่มต้น

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