"เลเยอร์ตรรกะทางธุรกิจ" อยู่ตรงไหนในแอปพลิเคชัน MVC


87

ก่อนอื่นก่อนที่ใครจะกรีดร้องหลอกลวงฉันมีช่วงเวลาที่ยากลำบากในการสรุปเป็นชื่อเรื่องง่ายๆ ชื่ออื่นอาจเป็น "โมเดลโดเมนกับโมเดล MVC ต่างกันอย่างไร" หรือ "โมเดลคืออะไร"

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

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

ลองยกตัวอย่างง่ายๆ AccountController ที่มาพร้อมกับโครงการเริ่มต้น MVC ฉันได้อ่านความคิดเห็นหลายประการว่ารหัสบัญชีที่รวมอยู่มีการออกแบบที่ไม่ดีละเมิด SRP ฯลฯ .. ฯลฯ หากมีการออกแบบรูปแบบการเป็นสมาชิกที่ "เหมาะสม" สำหรับแอปพลิเคชัน MVC จะเป็นอย่างไร

คุณจะแยกบริการ ASP.NET (ผู้ให้บริการสมาชิกผู้ให้บริการบทบาท ฯลฯ ) ออกจากโมเดลอย่างไร หรือคุณจะทำเลย?

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

ใครสนใจที่จะให้ความกระจ่างเกี่ยวกับปัญหานี้?


1
นั่นคือเหตุผลที่คุณควรถามคำถามสี่ข้อแยกกัน
John Farrell

3
คีย์เวิร์ดคือ "เกือบ" เป็นคำถามเดียวกันจริงๆโดยอาจใช้คำถามย่อยเพื่อแสดงคำถามหลัก
Erik Funkenbusch

3
รุ่น - ดู - คอนโทรลเลอร์. reposirory / BL View หรือไม่? ไม่ใช่มันเป็นตัวควบคุม? ไม่เหลืออะไร :)? เป็น MVC ไม่ใช่ MSVC ไม่ใช่ MRVC ไม่ใช่ MBLVC มีแค่สามชั้น ที่เก็บจึงเป็นส่วนหนึ่งของโมเดล BL จึงเป็นส่วนหนึ่งของโมเดล และคุณสามารถทำการแยกเพิ่มเติมได้ แต่จะทำภายในเลเยอร์โมเดล
LukLed

3
@LukeLed, @bslm - ไม่ได้จริงๆ MVC ไม่ได้บอกว่าไม่มีเลเยอร์อื่นที่คอนโทรลเลอร์หรือโมเดลโต้ตอบด้วย
John Farrell

3
@LukLed - ไม่เห็นด้วย - MVC เป็นเพียงรูปแบบเลเยอร์การนำเสนอเท่านั้น ไม่มีผลกระทบต่อการจัดโครงสร้างเลเยอร์อื่น ๆ ของคุณเช่น BLL และ DAL
Cory House

คำตอบ:


69

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

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

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

ในกรณีนี้คือเมื่อทำงานกับบัตรเครดิต - ฉันต้องใช้ CVV ในการประมวลผลการชำระเงิน แต่ฉันไม่สามารถจัดเก็บ cvv ได้ (ต้องมีค่าปรับ 50,000 ดอลลาร์) แต่ฉันต้องการให้คุณสามารถแก้ไขบัตรเครดิตของคุณได้เช่นการเปลี่ยนที่อยู่ชื่อหรือวันหมดอายุ แต่คุณจะไม่ให้หมายเลขหรือ cvv แก่ฉันเมื่อแก้ไขและฉันจะไม่ใส่หมายเลขบัตรเครดิตของคุณเป็นข้อความธรรมดาบนหน้า โดเมนของฉันมีค่าเหล่านี้ที่จำเป็นสำหรับการบันทึกบัตรเครดิตใบใหม่เนื่องจากคุณให้ค่าดังกล่าวแก่ฉัน แต่รูปแบบการแก้ไขของฉันไม่มีแม้แต่หมายเลขบัตรหรือ cvv

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

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

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

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


เกี่ยวกับสิ่งที่ฉันมีในแอปพลิเคชัน MVC สำหรับองค์กรของเรา สถาปัตยกรรม N-Tier แอป MVC โต้ตอบกับวัตถุและบริการทางธุรกิจในพื้นที่ N-Tier เท่านั้น
Ed DeGagne

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

1
@ Josh มันจะมีประโยชน์ถ้าคุณสามารถแสดงภาพหน้าจอของโครงการตัวอย่างของคุณได้หรือไม่?
Shaiju T

@ Josh จะเกิดอะไรขึ้นถ้าโครงการของคุณไม่มีฐานข้อมูล มันโต้ตอบกับการอ้างอิงบริการ คลาสโดเมนและวิธีการทั้งหมดมาจากการอ้างอิงเหล่านี้ สถานการณ์นี้เหมาะสำหรับโครงสร้างแบบเลเยอร์หรือไม่
user6395764

17

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

ฉันเชื่อว่าความสับสนเกิดขึ้นเนื่องจากสถาปัตยกรรมที่ระบุไว้ข้างต้นและได้รับการยอมรับอย่างกว้างขวางซึ่งใช้รูปแบบ "anemic domain model" (ที่ถูกกล่าวหา) -anti ฉันจะไม่ลงรายละเอียดมากนักเกี่ยวกับ "การต่อต้านรูปแบบ" ของแบบจำลองข้อมูลโลหิตจาง (คุณสามารถดูความพยายามของฉันในการอธิบายสิ่งต่างๆได้ที่นี่ (ใช้ Java แต่เกี่ยวข้องกับภาษาใดก็ได้)) แต่ในระยะสั้นหมายความว่าโมเดลของเราเก็บข้อมูลเท่านั้นและตรรกะทางธุรกิจจะอยู่ในบริการ / ผู้จัดการ

แต่สมมติว่าเรามีสถาปัตยกรรมที่ขับเคลื่อนด้วยโดเมนและอ็อบเจ็กต์โดเมนของเราเป็นแบบที่คาดหวัง - มีทั้งตรรกะของรัฐและธุรกิจ และในมุมมองที่ขับเคลื่อนด้วยโดเมนนี้เกิดขึ้น:

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

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

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


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

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

3

ในความเห็นของฉัน,

รุ่น -

ไม่ควรมีตรรกะทางธุรกิจควรเสียบได้ (WCF เหมือนสถานการณ์) มันถูกใช้เพื่อผูกเข้ากับการดูดังนั้นควรมีคุณสมบัติ

ตรรกะทางธุรกิจ -

ควรวางไว้ที่ "Domain Services Layer" ซึ่งเป็นเลเยอร์ที่แยกจากกันทั้งหมด นอกจากนี้จะเพิ่มอีกหนึ่งเลเยอร์ที่นี่ "บริการแอปพลิเคชัน"

App Services พูดคุยกับ Domain Services layer เพื่อใช้ตรรกะทางธุรกิจจากนั้นจึงส่งคืน Model

ดังนั้น Controller จะถาม Application Service สำหรับ Model และโฟลว์จะเป็นดังนี้

    Controller->Application Services(using domain services)->Model

2

รูปแบบ MVC และกรอบงาน Asp.net ไม่ทำให้เกิดความแตกต่างว่า Model ควรจะเป็นอย่างไร

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

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

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

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

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