Training

MVC คืออะไร?

06 Jun 2013

หลายคนคงเคยได้ยินแนวคิดการเขียนโปรแกรมแบบ M-V-C แต่อาจยังไม่เข้าใจว่าแท้จริงแล้วมันเป็นอย่างไร มันต่างๆจากการเขียนโปรแกรมแบบ OOP มั๊ย วันนี้ผมจะพูดถึงแนวคิด MVC นี้พร้อมยกตัวอย่างทางเทคนิคเพื่อให้เห็นภาพด้วย Java (หากคุณยังไม่เข้าใจหลักการเขียนโปรแกรมแบบ OOP ผมแนะนำให้ไปอ่านบทความ "Object-Oriented Programming (OOP) คืออะไรกันแน่?" และ "Objects คืออะไร?" ก่อน)

ความหมายของ MVC

ก่อนอื่นผมขอเริ่มต้นที่ความหมายของ OOP ก่อน การเขียนโปรแกรมแบบ OOP คือการแบ่งโปรแกรมหรือแอพพลิเคชันออกเป็นออบเจกต์ย่อยๆ แต่ละออบเจกต์ทำหน้าที่หลักเพียงอย่างเดียว สุดท้ายทุกๆออบเจกต์ทำงานร่วมกันออกมาเป็นแอพพลิเคชันที่สมบูรณ์ แล้วในความเป็นจริงเราจะแบ่งออบเจกต์ด้วยหลักการใด? อันนี้ก็ขึ้นอยู่กับปัจจัยต่างๆและการออกแบบ แต่แล้วมันเกี่ยวอะไรกับ MVC หล่ะ เกี่ยวแน่นอนครับ เพราะ MVC คือหลักการออกแบบ (Design Pattern) รูปแบบหนึ่งนั่นเอง ซึ่งเป็นที่นิยมมากในการออกแบบและประยุกต์ใช้กับเว็บแอพพลิเคชัน ชื่อเต็มๆของมันคือ Model-View-Controller ซึ่งเจ้า MVC นี้จะแบ่งแอพพลิเคชันตามบทบาทหน้าที่ (Roles of Objects) โดยแบ่งออกเป็น 3 บทบาทด้วยกันคือ

  • Model (M)
  • View (V)
  • Controller (C)

Model คือออบเจกต์ที่ทำหน้าเป็นตัวแทนของข้อมูล ไม่ว่าข้อมูลจะถูกจัดเก็บในรูปแบบใดในระบบฐานข้อมูลหรือในไฟล์ เมื่อข้อมูลนั้นถูกโหลดเข้ามาในแอพพลิเคชัน เราจะเปลี่ยนมันให้อยู่ในรูปของออบเจกต์ และเราเรียกบทบาทของออบเจกต์นี้ว่า "Model" ยกตัวอย่างเช่นออบเจกต์ Customer, Employee, Product เป็นต้น ฟังดูแล้วออบเจกต์นี้คล้ายคลึงกับ Entity เลย จริงๆแล้วก็อันเดียวกันครับ เพียงแต่ใน Design Pattern นี้เค้าเรียกว่า Model และใน Java เรานิยมพัฒนาด้วย JavaBean

View คือออบเจกต์ที่ทำหน้าที่ในการแสดงผล เช่น แสดงหน้าฟอร์มกรอกข้อมูล, แสดงผลลัพธ์ของการค้นหา เป็นต้น ซึ่งมันจะประกอบไปด้วย Presentation Logic เป็นหลัก อย่าลืมว่าการแสดงผลก็มีโลจิกของมันอยู่ อาทิเช่น การเรียงลำดับสินค้าตามราคา เป็นต้น อันที่จริงแล้ว View ก็คือ User Interface (UI) นั่นเอง ใน Java Web เรานิยมพัฒนาด้วย JSP (ถึงแม้ว่า JSP จะมีลักษณะเหมือนเพจไฟล์ แต่ตอนรันมันก็คือออบเจกต์นั่นเอง)

สุดท้าย Controller คือออบเจกต์ที่ทำหน้าที่รับคำสั่ง เช่น คำสั่งค้นหา, คำสั่งลบข้อมูล เป็นต้น เมื่อมีคำสั่ง (หรือ Request) เข้ามาจากผู้ใช้ (User) ออบเจกต์ตัวนี้จะทำหน้าที่รับคำสั่งและเรียกใช้ออบเจกต์ตัวอื่นๆ (M และ V) ให้ทำงานร่วมกัน ดังนั้นมันจึงประกอบไปด้วย Control Logic ยกตัวอย่างหน้าที่ของ Controller เช่น

  • ดึงข้อมูลที่ถูกส่งมาจากผู้ใช้ เช่น มาจากการกรอกฟอร์ม
  • ทำการตรวจสอบ (Server-side Validation) ข้อมูลว่าครบถ้วนถูกต้องก่อนนำไปประมวลผลหรือไม่
  • เรียกใช้ Service เพื่อทำการประมวลผลคำสั่งพร้อมข้อมูล
  • ส่งต่อ (Forward) ผลลัพธ์จากการประมวลผลไปยัง View เพื่อแสดงต่อผู้ใช้ (เพราะการแสดงผลไม่ใช่หน้าที่ของ Controller)

เห็นมั๊ยครับว่าทำไมมันจึงชื่อว่า Controller เพราะมันเป็นตัวควบคุมเส้นทางการทำงานของคำสั่งต่างๆ (เช่นหากประมวลผลสำเร็จก็ส่งต่อไปยังหน้า Success แต่หากข้อมูลไม่ครบถ้วนถูกต้องก็ส่งต่อไปยังหน้าฟอร์มให้กรอกใหม่ เป็นต้น) และใน Java Web เรานิยมพัฒนาด้วย Servlet

จะเห็นได้ว่าโดยงานทั่วไปแล้วเราคงหลีกเลี่ยงสามบทบาทข้างต้นนี้ไปไม่ได้ เพราะยังไงก็ต้องมีหน้าแสดงผล (View) เพื่อใช้ตอบโต้กับผู้ใช้, ต้องมีตัวรับคำสั่ง (Controller) สั่งให้เพิ่มข้อมูลจะไปลบข้อมูลไม่ได้ใช่มั๊ยครับ, และสุดท้ายต้องมีข้อมูล (Model) ในทุกๆแอพพลิเคชัน ส่วนจะมี M, V, C อย่างละกี่ตัวก็ขึ้นอยู่กับ Use Cases ของแต่ละแอพพลิเคชันแล้ว ถึงตรงนี้คุณอาจยังไม่เห็นภาพไม่เป็นไรอ่านต่อไป :) และคุณเองก็อาจมีคำถามในใจว่า แล้วออบเจกต์ตัวไหนทำหน้าที่เข้าถึงระบบฐานข้อมูล, Model มาได้อย่างไรใครเปลี่ยนข้อมูลให้อยู่ในรูปของ Model, และออบเจกต์ตัวไหนทำหน้าที่ประมวลผล? ที่แน่ๆคงไม่ใช่ View แน่นอน แต่จะเป็น M หรือ C ดีหล่ะ? คำตอบคือไม่ใช่ทั้งคู่นั่นแหละ แต่เป็นหน้าที่ของออบเจกต์ Service

MVC+S

คุณอ่านหัวข้อไม่ผิดหรอกครับ MVC+S ซึ่ง S ก็คือ Service Object นั่นเอง ออบเจกต์นี้โผล่มาได้อย่างไร? ทำไมไม่เคยได้ยินมาก่อน ต้องไม่ลืมว่าในการออกแบบเราสามารถประยุกต์ใช้ Design Pattern ได้มากกว่าหนึ่งอย่าง ซึ่งการประยุกต์ใช้ออบเจกต์ Service นี้ ใน Java EE Design Patterns เราเรียกว่า Application Service Design Pattern ครับ มาลองดูบทบาทหน้าที่ของออบเจกต์ตัวนี้กันก่อน

Service คือออบเจกต์ที่ทำหน้าที่ในการประมวลผล โดยมันประกอบไปด้วยเมธอดต่างๆเพื่อรองรับการประมวลผล เช่น มีเมธอด checkPreOrderStatus() เพื่อตรวจสอบข้อมูลการสั่งสินค้า เป็นต้น โลจิกที่อยู่ในเมธอดต่างๆก็คือ Business Logic นั่นเอง เราจะเรียก Service Object นี้ว่า Business Object ก็ได้ และในการประมวลผลทุกครั้งจะต้องมีข้อมูลมาเกี่ยวข้องด้วยเสมอ ถ้าข้อมูลมาจากการรีเควสต์ของผู้ใช้ Controller ก็จะรับหน้าที่ในการเตรียมข้อมูลให้ เช่น ข้อมูลที่จะเพิ่มเข้าไปในระบบผ่านการกรอกฟอร์ม เป็นต้น แต่หากข้อมูลที่ต้องใช้อยู่ในระบบฐานข้อมูล ก็เป็นหน้าที่ของออบเจกต์ Service ที่จะต้องเข้าถึงข้อมูลเหล่านั้น เช่น การค้นหาสินค้า เป็นต้น ซึ่งข้อมูลที่รับส่งระหว่างแต่ละออบเจกต์ V, C, S ก็คือ Model (M) นั่นเอง ฟังดูแล้วออบเจกต์ Service นี้ประกอบไปด้วย Data Access Logic โลจิกที่ใช้เข้าถึงข้อมูลด้วย ใช่แล้วครับ หาก Business Logic และ Data Access Logic ไม่ซับซ้อนมาก เราสามารถรวบยอดมาเป็นออบเจกต์เดียวกันได้ แต่หากคิดว่าแยก Data Access Logic ออกมาเป็นอีกหนึ่งออบเจกต์ดีกว่า เราก็จะได้ออบเจกต์ DAO (Data Access Object) มาอีกหนึ่งตัว (ในบทความนี้ผมขอรวบยอด DAO มาไว้รวมกับ Service แล้วกัน) ใน Java เรานิยมพัฒนาออบเจกต์ Service ด้วย EJB, JPA, หรือ JDBC

[Note: Business Logic อาจอยู่ที่ Model หรืออยู่ที่ Service หรือทั้งสองที่ก็ได้นะครับ แต่เราควรออกแบบให้มีจุดศูนย์รวมในการเรียกใช้ที่เดียว เช่นให้เรียกผ่านออบเจกต์ Service ที่เดียว ส่วนออบเจกต์ Service จะเรียกใช้ออบเจกต์ตัวอื่นร่วมด้วยหรือไม่ก็ได้ ดังแสดงในรูปที่ 1]

รูปที่ 1: Application Service Design Pattern

สรุปแล้วเราสามารถแบ่งออบเจกต์ในแอพพลิเคชันของเราได้สี่บทบาทด้วยกันคือ M, V, C, และ S ดังแสดงในรูปที่ 2 และสามารถสรุปบทบาทของแต่ละออบเจกต์ได้ดังนี้

  • Model คือออบเจกต์ที่เป็นตัวแทนของข้อมูล ไม่ว่าจะเป็นข้อมูลขาเข้าหรือข้อมูลผลลัพธ์ที่จะนำไปใช้แสดงผล (เราจะมองว่ามันเป็น Transfer Object ใน Design Pattern อื่นก็ได้นะครับ)
  • View ทำหน้าที่แสดงผลหรือเป็นส่วนที่ติดต่อกับผู้ใช้ อาทิเช่น การแสดงฟอร์มกรอกข้อมูล, การแสดงผลลัพธ์การค้นหา เป็นต้น (Presentation Logic)
  • Controller ทำหน้าที่รับคำสั่งจากผู้ใช้, ทำการตรวจสอบข้อมูลก่อนการประมวลผล, เรียกออบเจกต์ Service เพื่อทำการประมวลผลจริง, และส่งต่อผลลัพธ์ที่ได้ไปแสดงผลยังออบเจกต์ View (Control Logic)
  • Service ทำหน้าที่ประมวลผลและเข้าถึงระบบจัดเก็บข้อมูล (Business Logic + Data Access Logic)
รูปที่ 2: MVC+S

แล้วการแบ่งออบเจกต์รูปแบบนี้ให้ประโยชน์อะไรกับเรา ผมขอยกตัวอย่างดังนี้แล้วกัน:

  • หากเรามีการเปลี่ยนแปลงระบบจัดเก็บข้อมูล เช่น จากไฟล์ไปเป็นระบบฐานข้อมูล เราก็เปลี่ยนที่ Service ตัวเดียวเท่านั้น เพราะสุดท้ายข้อมูลที่เราจะใช้ก็จะอยู่ในรูปของ Model เสมอทำให้ View และ Controller ไม่ต้องเปลี่ยนแปลง :)
  • หากเราต้องการเปลี่ยนแปลงการแสดงผลใหม่ เช่น ว่าให้มีรูปแบบที่สวยขึ้นหรือมีการจัดเรียงลำดับข้อมูลใหม่ เราก็เปลี่ยนที่ View เท่านั้น :)
  • หากเรามีการเปลี่ยนแปลงเงื่อนไขการตรวจสอบข้อมูลก่อนการประมวลผลใหม่ เราก็เปลี่ยนที่ Controller เท่านั้น :)

(**แต่หากข้อมูลมีการเปลี่ยนแปลงหล่ะ เช่นเพิ่มเติมข้อมูลลูกค้าที่ต้องมีการจัดเก็บ อันนี้เรื่องใหญ่เลย เพราะกระทบกับออบเจกต์อื่นๆที่เหลือทั้งหมด !!! ซึ่งอันนี้ Design Patterns คงช่วยอะไรไม่ได้ ดังนั้นตอนเก็บ Requirements คุณต้องทำด้วยความละเอียดรอบคอบ จะมาเปลี่ยนระหว่างพัฒนาแอพพลิเคชันไม่ได้ แต่ถ้าเปลี่ยนหลังจากใช้ไปแล้ว ก็คงทำอะไรไม่ได้จริงๆ)

นอกจากนี้ MVC+S ยังช่วยในเรื่องของการเปลี่ยนแปลงโครงสร้างการ Deploy หรือ Architecture ได้อีกด้วย รูปที่ 3 แสดงการ Deploy แบบ 3-Tier นั่นคือทุกๆออบเจกต์ถูก Deploy ขึ้นไปยัง Web Server ที่เดียว ทุกอย่างจบภายใน Web-Tier แต่หากในอนาคตคุณต้องการแยกการประมวลผลออกไปเป็นอีกหนึ่ง Tier เป็น Business-Tier เฉพาะของมันเอง คุณก็สามารถทำได้โดยง่าย เพราะเราได้แยกการประมวลผลออกเป็นออบเจกต์ Service แล้วดังแสดงในรูปที่ 4 (M คือออบเจกต์ที่รับส่งระหว่าง Tier) แล้วทำไมเราต้องแยก Service ออกเป็นอีกหนึ่ง Tier ด้วยหล่ะ? ก็เพราะเราอาจรองรับ Client ชนิดอื่นๆที่ไม่ใช่ Web Client อย่างเดียว อาทิเช่น Desktop Client นะครับ หรือแม้แต่ในอนาคตเราจะรองรับ Client จากแพลตฟอร์มอื่นอย่าง .Net เราก็เพียงแค่เพิ่ม Web Service-Tier เข้าไป ยังไงโลจิกการประมวลผลก็เหมือนเดิมก็เรียกใช้จาก Business-Tier ได้เลยจริงมั๊ยครับ

รูปที่ 3: MVC+S กับ 3-Tier Architecture
รูปที่ 4: MVC+S กับ 4-Tier Architecture

แล้วทำไมที่ผ่านมาถึงไม่เคยได้ยิน MVC+S มาก่อน เคยได้ยินแต่ MVC เฉยๆ อันนี้ผมเพิ่มของผมเองนะครับ อ่าว !!! อันนี้ต้องท้าวความกันนิดนึง MVC นั้นถูกคิดค้นมานานแล้ว ถูกคิดค้นก่อนจะมีเทคโนโลยีเว็บแอพพลิเคชันเสียอีก แต่ปัจจุบันได้มีการนำแนวคิดนี้มาประยุกต์ใช้กับการทำเว็บแอพพลิเคชันและเป็นที่นิยมกันอย่างมาก เรียกได้ว่าทุกโปรแกรมมิ่งแพลตฟอร์มเลยก็ว่าได้ อาทิเช่น ASP.Net, Ruby on Rails, Django, Zend, เป็นต้น แพลตฟอร์มอื่นๆเขาไม่มีการแยกตัว S กัน แต่จะเหมารวมว่าเป็นตัว M ไปเลย (จะรวมออบเจกต์หรือแยกออบเจกต์แต่อยู่ในแพ็คเกจเดียวกันก็แล้วแต่) อย่างใน Rails ก็รวม S ไว้ใน M ไม่มี DAO เหมือนใน Java และ Rails เรียกมันว่า Active Record Design Pattern นอกจากนี้หลายๆแพลตฟอร์มถูกออกแบบมาเพื่องานเว็บแอพพลิเคชันโดยเฉพาะ จึงไม่มีความจำเป็นต้องแยก S และ M แต่อย่างใด แต่ใน Java หากคุณลองดูรูปที่ 4 ข้างต้นอีกครั้งหนึ่ง หากเรารวม M และ S เราจะแบ่ง Business-Tier ออกมาอย่างไรโดยไม่ให้ V และ C กระทบกระเทือน? เพราะ M มันต้องถูกใช้และเกี่ยวข้องกับตัวอื่นๆทุกตัว

อันที่จริงแล้วใน Java เราไม่เรียกแนวคิดนี้ว่า MVC ด้วยซ้ำ แต่จะมี Design Patterns อื่นๆที่สุดท้ายก็ทำงานเหมือนๆกับ MVC นี่แหละ (ลองไปหาอ่าน Java EE Design Patterns ดูจะเห็นว่าไม่มีนะครับ) แต่เนื่องจากกระแสโลกเค้านิยมเรียกกันแบบนี้ ทำให้ใน Java เองและ Frameworks ต่างๆใน Java เช่น JSF, Struts ก็ต้องเรียกแบบนี้เช่นกัน สรุปนะครับไปคุยกับใครก็เรียกแค่ MVC เฉยๆก็ได้ แต่เวลาจะพัฒนาก็ให้ตระหนักว่า MVC มันต้องบวก S เสมอมันถึงจะได้แอพพลิเคชันที่ดี

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


Books By Me

JavaScript Programming Guide book cover

JavaScript Programming Guide
Thai language
Kontentblue Publishing

About This Site

I use this site to share my knowledge in form of articles. I also use it as an experimental space, trying and testing things. If you have any problems viewing this site, please tell me.

→ More about me

→ Contact me

→ Me on facebook

Creative Commons Attribution License

creative commons logo

This license lets you distribute, remix, tweak my articles, even commercially, as long as you credit me for the original creation.

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