ป้ายกำกับ: Binding

MVVM ( Model-View-ViewModel )MVVM ( Model-View-ViewModel )

MVVM ( Model-View-ViewModel ) คือสถาปัตยกรรมที่ถูกสร้างขึ้นมาเพื่อลดภาระความเหนื่อยล้าในการเขียนโค้ดสั่งงานหน้าจอที่เราเจอกันใน MVP ครับ

ใน MVP เรามี Presenter ที่ต้องคอยสั่ง View แบบละเอียดยิบ ( เช่น “View เอ้ย ช่วยเปลี่ยนข้อความบรรทัดนี้หน่อย”, “View ช่วยซ่อนปุ่มนี้ที” ) พอระบบใหญ่ขึ้น โค้ดสั่งงานพวกนี้จะยาวและน่าเบื่อมาก

MVVM เลยเอาเวทมนตร์ที่เรียกว่า Data Binding ( การผูกข้อมูล ) เข้ามาช่วยแก้ปัญหานี้ครับ โดยแบ่งการทำงานออกเป็น 3 ส่วนดังนี้:

  1. Model ( ข้อมูลและตรรกะ )
    ยังคงทำหน้าที่เหมือนเดิมทุกประการครับ คือจัดการกับข้อมูล การคำนวณ ติดต่อฐานข้อมูล หรือเรียก API โดยไม่สนใจหน้าจอเลย
  2. ViewModel ( ตัวแทนของหน้าจอ )
    หน้าที่ของมันคล้าย Presenter คือการดึงข้อมูลจาก Model มาเตรียมไว้ให้หน้าจอ แต่จุดที่ต่างกันโดยสิ้นเชิงคือ ViewModel จะ “ไม่รู้จัก View” เลยครับ มันไม่มีฟังก์ชันในการสั่งงาน View ไม่มีการจับคู่กันโดยตรง หน้าที่ของมันมีแค่เก็บ “สถานะ ( State )” หรือข้อมูลล่าสุดของหน้าจอนั้น ๆ เอาไว้ เช่น count = 0 หรือ isLoading = true
  3. View ( หน้าจอและการผูกข้อมูล )
    หน้าตา UI ของระบบ ( เช่น HTML / CSS ) ใน MVVM ตัว View จะมีความฉลาดเพิ่มขึ้นมานิดหน่อยตรงที่มันสามารถ “ผูก ( Bind )” ตัวเองเข้ากับตัวแปรใน ViewModel ได้

หัวใจสำคัญ: การทำงานของ Data Binding

ความมหัศจรรย์ของ MVVM อยู่ที่กลไกอัตโนมัตินี้ครับ เมื่อ View ผูกข้อมูลเข้ากับ ViewModel แล้ว

  • ถ้าข้อมูลใน ViewModel เปลี่ยน: View จะอัปเดตหน้าจอตัวเองโดยอัตโนมัติทันที! ( ไม่ต้องมีใครไปสั่งมัน )
  • ถ้าผู้ใช้พิมพ์ข้อมูลลงใน View: ข้อมูลใน ViewModel ก็จะถูกอัปเดตตามไปพร้อม ๆ กันแบบเรียลไทม์ ( Two-way Data Binding )

เปรียบเทียบให้เห็นภาพง่าย ๆ

  • MVP: Presenter ต้องสั่งงานว่า document.getElementById('text').innerText = "Hello"; ( สั่งงานตรง ๆ )
  • MVVM: ViewModel แค่ประกาศตัวแปรว่า this.text = "Hello"; แล้วเดี๋ยวกลไก Data Binding ของ Framework ( เช่น Vue.js, Angular, React ) จะเอาคำว่า Hello ไปแปะบนหน้าจอให้เองแบบอัตโนมัติ!

ตัวอย่างโค้ด Counter ด้วย MVVM ( สไตล์ Vue.js )

ลองเทียบกับโค้ด MVP ก่อนหน้านี้นะครับ จะเห็นว่าสั้นลงมหาศาล เพราะเราไม่ต้องเขียนโค้ดจับคู่ปุ่มหรือสั่งเรนเดอร์หน้าจอเองเลย

ฝั่ง View ( HTML )

<div id="app">
 <h1>จำนวนปัจจุบัน: {{ count }}</h1>
 <button @click="increment">Add</button>
</div>

ฝั่ง ViewModel ( JavaScript )

// ViewModel แค่สนใจการจัดการ Data ตัวเอง ไม่มีการไปยุ่งกับ DOM เลย
const app = Vue.createApp({
 data() {
 return {
  count: 0 // เก็บ State
 }
 },
 methods: {
 increment() {
  this.count++; // แค่บวกเลข เดี๋ยวหน้าจอ HTML จะอัปเดตเลขนี้เองอัตโนมัติ!
 }
 }
});

app.mount('#app');

สรุปข้อดีหลัก ๆ ของ MVVM: โค้ดสั้นลงมาก, แยกการทำงานระหว่างคนทำ UI กับคนเขียน Logic ได้เด็ดขาด, และตัว ViewModel นำไปเขียน Unit Test ได้ง่ายสุด ๆ เพราะไม่มีโค้ดที่เกี่ยวกับหน้าจอ (DOM) ปนอยู่เลยครับ


อ่านเพิ่มเติม