เป็นไปได้หรือไม่ที่ตรรกะทางธุรกิจจะไม่คืบคลานเข้ามาในมุมมอง?


31

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

ในกรณีส่วนใหญ่จะมีปัญหาเช่น "ถ้าผู้ใช้เลือกตัวเลือก x ดังนั้นแอปพลิเคชันจะต้องเปิดใช้งานเขาสามารถให้ข้อมูลสำหรับ y ถ้าไม่เช่นนั้น s / เขาควรจะให้ข้อมูล z" หรือดำเนินการ AJAX ซึ่งควรใช้การเปลี่ยนแปลงบางอย่างกับโมเดล แต่ไม่ยอมรับจนกว่าผู้ใช้จะร้องขออย่างชัดเจน นี่เป็นปัญหาที่ง่ายที่สุดที่ฉันพบและฉันไม่สามารถเข้าใจได้ว่าจะหลีกเลี่ยงตรรกะที่ซับซ้อนในมุมมองได้อย่างไร

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

เป็นไปได้ไหมที่จะมีมุมมองโดยไม่มีเหตุผลทางธุรกิจเลย?


2
ลองดูที่ MVC derivations MVP และ MVVM (ดูen.wikipedia.org/wiki/Model_View_Presenterและen.wikipedia.org/wiki/Model_View_ViewModel ) พวกเขาอาจเป็นสิ่งที่คุณกำลังมองหา
Doc Brown

เกี่ยวข้อง (อาจซ้ำกัน): Decoupling คลาสจากส่วนติดต่อผู้ใช้
gnat

2
มุมมองเป็นรูปแบบภายนอกที่มองเห็นได้ของข้อมูลและตรรกะของคุณ มันเป็นไปไม่ได้สำหรับมุมมองที่ไม่แสดงตรรกะทางธุรกิจ หรือคุณกำลังบอกว่ามุมมองไม่ควรมีรหัสใด ๆ ในนั้น? แน่นอนคุณสามารถสร้างมุมมอง HTML เท่านั้น
BobDalgleish

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

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

คำตอบ:


22

เป็นไปได้ไหมที่จะมีมุมมองโดยไม่มีเหตุผลทางธุรกิจเลย?

ฉันพบว่านี่เป็นคำถามที่ตอบยาก (คำถามที่กระตุ้นความคิด!)

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

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

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

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


2
The best conceptual location may not be the best location for other reasons: ไชโย !!
Magno C

8

ฉันมักจะทำสิ่งนี้: หากผู้ใช้เลือกตัวเลือก x การเรียกดู

controller->OptionXChanged()

จากนั้นคอนโทรลเลอร์จะเปิดใช้งาน y ในมุมมอง:

view->SetEnableInfoY(True) // suppose False=SetDisable

มุมมองแจ้งให้ผู้ควบคุมของสิ่งที่เกิดขึ้นโดยไม่ต้องตัดสินใจอะไร


+1 ปัญหาเล็ก ๆ น้อย ๆ ของ OP มักจะได้รับการจัดการเช่นนี้ในแอปพลิเคชั่นที่ไม่สำคัญ
dev_feed

การวางตรรกะนี้ไว้ในคอนโทรลเลอร์มีปัญหาสองประการ: 1) มันทำให้การทดสอบหน่วยซับซ้อนและเป็นไปไม่ได้ที่จะสนับสนุนมุมมองหลายมุมของข้อมูลเดียวกัน
kevin cline

4

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

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

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

บรรทัดล่างฉันคิดว่านิยามของตรรกะทางธุรกิจของคุณไม่เหมือนกับนิยามอื่น ๆ


1

ฉันทำงานด้วยวิธีนี้ (Struts2 + Hibernate):

My Struts Actions รับผิดชอบเฉพาะการแสดงข้อมูลบนเว็บเบราว์เซอร์เท่านั้น ไม่คิดอะไร

ผู้ใช้ -> การกระทำ -> บริการ -> พื้นที่เก็บข้อมูล -> การเข้าถึงข้อมูล

หรือ:

ฉันต้องการดู -> วิธีดู -> สิ่งที่ต้องทำ -> วิธีรับ -> หาได้ที่ไหน

ดังนั้นในชั้นแรก (มุมมอง) ฉันมีสิ่งที่ชอบ:

public String execute ()   {
    try {
        CourseService cs = new CourseService();
        Course course = cs.getCourse(idCourse);
    } catch (NotFoundException e) {
        setMessageText("Course not found.");
    } catch (Exception e) {

    }
    return "ok";
}

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

ดังนั้นถ้าฉันใส่ Services, Repositories และ DAOS ในไลบรารีที่แตกต่างกันฉันสามารถใช้มันได้แม้ในโปรแกรมแบบข้อความหรือระบบเดสก์ท็อปที่ใช้ Window โดยไม่ต้องเปลี่ยนอะไรเลย

บริการรู้ว่าต้องทำอะไร แต่ไม่รู้จะแสดงอย่างไร มุมมองรู้วิธีที่จะแสดง แต่ไม่รู้ว่าจะทำอย่างไร เช่นเดียวกับ Service / Repository: บริการส่งและร้องขอข้อมูล แต่ไม่ทราบว่าข้อมูลอยู่ที่ใดและใช้อย่างไร พื้นที่เก็บข้อมูล "สร้าง" ข้อมูลดิบเพื่อสร้างออบเจ็กต์เพื่อให้บริการสามารถทำงานได้

แต่พื้นที่เก็บข้อมูลไม่ทราบอะไรเกี่ยวกับฐานข้อมูล ชนิดฐานข้อมูล (MySQL, PostgreSQL, ... ) เกี่ยวข้องกับ DAO

คุณสามารถเปลี่ยน DAO ได้หากคุณต้องการเปลี่ยนฐานข้อมูลและจะต้องไม่ส่งผลต่อเลเยอร์ด้านบน คุณสามารถเปลี่ยน Repository ได้หากคุณต้องการอัพเดทการจัดการข้อมูล แต่สิ่งนี้จะต้องไม่ส่งผลกระทบต่อ DAO และเลเยอร์ด้านบน คุณสามารถเปลี่ยนบริการได้หากคุณต้องการเปลี่ยนตรรกะ แต่สิ่งนี้ต้องไม่ยุ่งกับเลเยอร์ด้านบนหรือด้านล่าง

และคุณสามารถเปลี่ยนแปลงอะไรก็ได้ในมุมมองแม้กระทั่งเทคโนโลยี (เว็บเดสก์ท็อปข้อความ) แต่สิ่งนี้ต้องไม่บอกเป็นนัยในการสัมผัสสิ่งใดด้านล่าง

ตรรกะทางธุรกิจคือบริการ แต่วิธีการโต้ตอบกับสิ่งนี้คือการดู ปุ่มใดที่จะแสดงในตอนนี้ ผู้ใช้สามารถเห็นลิงก์นี้ได้หรือไม่? คิดว่าระบบของคุณเป็นโปรแกรมที่ใช้คอนโซล: คุณต้องปฏิเสธหากผู้ใช้เลือกผิด#> myprogram -CourseService -option=getCourse -idCourse=234หรือหยุดเขาให้กดปุ่มเพื่อเขียนคำสั่งนี้?

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

                <div id="userDetailSubBox">
                    <c:forEach var="actionButton" items="${actionButtons}" varStatus="id">
                        ${actionButton.buttonCode}
                    </c:forEach>
                </div>

และ

private List<ActionButton> actionButtons;

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


1

ในกรณีส่วนใหญ่จะมีปัญหาเช่น "ถ้าผู้ใช้เลือกตัวเลือก x ดังนั้นแอปพลิเคชันจะต้องเปิดใช้งานเขาสามารถให้ข้อมูลสำหรับ y ถ้าไม่เช่นนั้น s / เขาควรจะให้ข้อมูล z"

นั่นคือตรรกะสำหรับโมเดลไม่ใช่มุมมอง อาจเป็น "view-model" ซึ่งสร้างขึ้นเพื่อรองรับ UI แต่ยังคงเป็นตรรกะของรุ่น ลำดับการควบคุมคือ:

  • คอนโทรลเลอร์แนบตัวจัดการสำหรับดูเหตุการณ์
  • ดูแนบตัวจัดการสำหรับเหตุการณ์โมเดล
  • ผู้ใช้เลือกตัวเลือก X
  • มุมมองยกเหตุการณ์ "ตัวเลือก X ที่เลือก"
  • คอนโทรลเลอร์รับเหตุการณ์และเรียก model.selectOptionX ()
  • โมเดลทำให้เกิดเหตุการณ์ "เปลี่ยนสถานะของโมเดล"
  • มุมมองรับโมเดลเหตุการณ์ที่เปลี่ยนแปลงและอัพเดตมุมมองเพื่อให้ตรงกับสถานะใหม่: inputY.enable(model.yAllowed()); inputZ.enable(model.zAllowed());

UI View Controller Model |.checkbox X checked.> | | | | | .. X selected ...>| | | | |-----> set X ------->| | | | | | |< .............state changed ............| | | | | | |-------------- Get state --------------->| | | | | | |<----------- new state ------------------| | <-- UI updates ------| นี่คือรูปแบบ MVC คลาสสิก เป็นไปได้ที่จะทดสอบลอจิกรุ่นแยกจาก UI คอนโทรลเลอร์และมุมมองนั้นบางและง่ายต่อการทดสอบ

=== เพื่อตอบสนองต่อ Dunk ===

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


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

เควินโปรดตอบกลับของคุณที่นี่ในช่องแสดงความคิดเห็นดังนั้นเราจึงสามารถตอบคุณได้อย่างง่ายดาย ฉันเห็นด้วยกับคุณ. เป็นไปไม่ได้ที่จะรักษาข้อมูลอินเทอร์เฟซ (UI) โดยไม่มีโครงสร้างใด ๆ แต่การตั้งชื่อ "MODEL" อาจทำให้เกิดความสับสน ฉันชอบที่จะจัดการสิ่งต่าง ๆ ของ UI ในแพ็คเกจที่สามารถเปลี่ยนได้ต่าง ๆ เพื่อให้ง่ายต่อการทำสิ่งที่ @Dunk กำลังพูดถึง ดูคำตอบของฉัน
Magno C

@MagnoC: ฉันแก้ไขเขาตอบในการตอบสนองต่อ Dunk เพราะฉันคิดว่าข้อความที่เพิ่มเข้ามาปรับปรุงคำตอบ นั่นคือสิ่งที่เว็บไซต์เป็นเรื่องเกี่ยวกับ: คำถามและคำตอบ โมเดลเป็นคำทั่วไปที่ค่อนข้างสวยและในรูปแบบ MVC หมายถึง "โมเดลสถานะ UI"
kevin cline

0

ตรรกะทางธุรกิจมีลักษณะคล้ายกันมากขึ้นIf X then return InfoType.Yจากนั้น UI จะแสดงฟิลด์ตามผลลัพธ์ที่ส่งคืนโดยโดเมน

// Controller method pseudocode
option changed routine

    get selected option

    get required info type from domain routine based on selected option

    display fields based on required info type

หาก UI ต้องการตรรกะทางธุรกิจให้มอบสิทธิ์ตัวเลือกให้กับโดเมน UI จะดำเนินการตามการตัดสินใจ


0

หากผู้ใช้เลือกตัวเลือก x ดังนั้นแอปพลิเคชันจะต้องเปิดใช้งานเขาสามารถให้ข้อมูลสำหรับ y ถ้าไม่เช่นนั้น s / เขาควรจะให้ข้อมูล z "

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

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

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

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

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