
關注點分離(Separation of Concerns,SoC)
定義
- 關注點分離是一種軟體設計原則,將一個系統劃分為不同的模組或元件,每個模組或元件集中於解決特定的關注點或任務,以提高系統的可操作性、可維護性、可擴展性和可重用性。該原則主張將不同層面的關注點獨立開發,使得修改一個關注點不會影響其他關注點。
- 傳統的網頁開發中,通常會將網頁的開發區分為HTML、CSS、JavaScript三個技術領域,並分別將它們拆分成不同的檔案,以負責各自的領域。
- HTML: 語意層,負責網頁結構和整體語意。
- CSS: 樣式層,負責網頁外觀和樣式。
- JavaScript: 邏輯層,負責處理事件邏輯和動態行為。
- 避免寫行內樣式(inline style)跟行內腳本(inline script)造成彼此領域的干涉。
1 2 3
| <h1 style="color:red;font-size:46px;" onclick="alert('Hi')"> Hello World </h1>
|
1 2 3 4
| h1 { color: red; font-size: 46px; }
|
1 2 3 4 5 6 7
| document.addEventListener('DOMContentLoaded', function () { const header = document.querySelector('h1'); header.addEventListener('click', function () { alert('Hi'); }); });
|
關注點分離- MVC概念
- Model:
- 負責處理數據的邏輯,包括數據的存儲、檢索、更新和刪除等操作。
- View:
- Controller:
- 負責接收用戶的輸入,處理業務邏輯,然後更新模型和視圖。
- 單純依賴Controller影響View的節點,使得View上呈現的節點難以維護。

我們希望透過MVC的概念讓維護上更為方便。
- 使用者與介面互動 -> Controller處理網頁邏輯 -> Controller調用Model方法,影響Model資料(新增或修改) -> 修改完Controller再次呼叫View渲染的方法 -> View根據更新後的資料重新渲染
- 達到View及Model透過Controller進行彼此的溝通而不直接互相影響。

- 透過以下流程搭配程式碼進行說明
- 用戶與界面互動,觸發 Controller 的相應方法。
- Controller 根據用戶的輸入操作 Model。
- 按鈕的點擊事件觸發了 removeData 方法,這是 Controller 中的一個相應方法。
- Model 的狀態發生變化。
- removeData方法中使用了 splice 方法來移除資料陣列 data 中的特定項目,即刪除了一個資料項。
- Controller 得知 Model 狀態的變化,通知相應的 View。
- removeData方法執行完畢後,立即呼叫了 render 方法,這是通知 View 部分。
- View 從 Model 中獲取最新的數據。
- render方法內部重新遍歷資料陣列,創建新的HTML元素,並更新 DOM 中的內容。
- View 使用這些數據更新界面。
- 新的HTML元素被注入到DOM中,此時界面上的列表已經更新,反映了資料變化。
- Codepen連結
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| const component = { data: [ '這是第一句話', '這是第二句話', '這是第三句話' ], removeData(id) { this.data.splice(id, 1); this.render(); },
renderList() { const list = document.querySelector('.component ul'); let content = ''; this.data.forEach((item, i) => { content = `${content}<li>${item} <button type="button" class="btn" data-id="${i}">移除</button></li>`; }); list.innerHTML = content; }, addEventListeners() { const btns = document.querySelectorAll('.btn'); btns.forEach(btn => btn.addEventListener('click', (e) => { const id = e.target.dataset.id; this.removeData(id); })); },
render() { this.renderList(); this.addEventListeners(); }, init() { this.render(); } }; component.init();
|