更新於 2024/09/07閱讀時間約 8 分鐘

軟體設計模式 | 模板模式 : 以Vue.js為例

模板模式的定義極為簡單,卻是大型系統程式、WEB/APP應用框架的設計核心,完美展現設計模式的價值: 簡單、高效、強大。
raw-image

定義

由父類別制定演算法的執行步驟, 將每個步驟的實作細節延後由子類別實現。

模板模式的定義雖然簡單,但對於初學者來說,往往難以真正體會其背後的概念與優勢。然而,透過經典的應用場景範例,這些概念與優勢就變得清晰易懂。


WEB前端框架生命週期 : VUE.js

在Vue.js編譯完成後,會生成一個包含 "app" id 的 index.html 作為首頁。當開啟網頁時,瀏覽器會將編譯後的整包 JavaScript 掛載到這個 "app" DOM元素上,並建立 Vue應用實例,負責監控網頁與使用者的所有互動以及從網路端獲取的資訊。

應用頁面的生命週期回調函數

當我們導航到客製化開發的應用頁面時,Vue應用實例會將該頁面實例化為Vue組件(component),並依次呼叫該組件的生命週期回調函數。

我們則需要在合適的回調函數內實作業務邏輯。以下是各個生命週期回調函數的實際應用範例:

onBeforeMount

在組件即將被掛載到 DOM 之前呼叫。通常會在這個階段呼叫透端API準備資料。

onBeforeMount(() => {
// 通常在這裡call API準備要顯示的資料
try {
this.data = (await axios.get('/api/data')).data;
} catch (error) {
this.error = error; console.error('Error fetching data:', error); }
});

onMounted

在組件掛載到DOM之後呼叫,這是開發著可以開始訪問和操作DOM元素的地方。適合在這裡進行與DOM相關的初始化操作,例如初始化圖表或設置事件監聽器。

最重要的是,如果在template裡有設定ref,onMounted後就可以開始操作他了。

<template>
<div ref="chartContainer">
這是我的圖表容器
</div>
</template>

<script>
import { onMounted, ref } from 'vue';

export default {
setup() {
const chartContainer = ref(null);

onMounted(() => {
// 操作ref
chartContainer.value.init();

// 有時候想要監聽視窗大小的改變進行畫面上的處理
window.addEventListener('resize', handleResize);
});
},
};
</script>

onBeforeUpdate

在數據更新之前呼叫,此時虛擬DOM(Virtual DOM)已經重新渲染,但新的數據還未應用到真實DOM中。這裡可以進行一些在數據改變後需要在DOM更新前完成的操作。

onBeforeUpdate(() => {
// 可以在這裡進行一些準備工作
console.log("onBeforeUpdate: 數據即將更新");
});

onUpdated

在數據更新並且虛擬DOM重新渲染和差異更新完成之後調用,這時可以進行與更新後DOM相關的操作。

onUpdated(() => { 
// 可以在這裡執行與更新後 DOM 相關的操作
console.log('onUpdated: 數據更新完成,DOM 已重新渲染');
});

onBeforeUnmount

Vue組件被卸載之前調用,通常用於進行一些清理工作,例如移除事件監聽器。

onBeforeUnmount(() => { 
// 移除事件監聽器 window.removeEventListener('resize', handleResize);
console.log('onBeforeUnmount: 組件即將被卸載');
});

onUnmounted

Vue組件被完全卸載並且不再存在於DOM中時調用,可以在這裡進行最終的清理操作,例如銷毀圖表實例。

onUnmounted(() => { 
console.log('onUnmounted: 組件已經從 DOM 中移除');
// 銷毀圖表實例
destroyChart();
});

其他框架的模板設計

Android APP(手機應用框架): Activity生命週期回調函數

onCreate:應用程式第一次開啟時呼叫。例如設定佈局、初始化資料等。

onStart:應用程式即將可見時呼叫。進行界面更新等操作。

onResume:應用程式與使用者互動前的最後準備。例如恢復播放動畫。

onPause:系統即將啟動另一個活動時呼叫。例如暫停播放動畫或音樂。

onStop:應用程式不再可見時呼叫。例如停止播放動畫或音樂、保存應用程式狀態。

onDestroy:應用程式即將被銷毀時呼叫。執行最終清理工作,釋放所有資源。

onRestart:應用程式從停止狀態重新啟動時呼叫。恢復暫停前的操作。

由於手機與使用者的互動即時性比網頁更高,並且涉及了更多系統層級的資源管理,因此Android APP的生命週期更加複雜。開發者需要在合適的回調函數中,更細膩地關注使用者與系統的行為,並處理業務邏輯。


Pytest(Python測試框架) : Test Class回調函數Test Method回調函數

  • setup_class:在整個測試類別開始前呼叫。
  • teardown_class:在整個測試類別結束後呼叫。
  • setup_method:在每個測試案例開始前呼叫。
  • teardown_method:在每個測試案例結束後呼叫。

在撰寫測試腳本時,有一些初始化狀態的前置作業是整個類別共用的,需要在整個類別測試開始時執行一次,並在整個類別測試結束後清理。有些則是每個測試案例開始前執行,測試案例結束後清理。為了方便開發人員在不同的時機撰寫相關的測試邏輯,Pytest 提供了四種回調函數,幫助開發人員根據需求選擇合適的使用時機。


關鍵影響

從實際的應用可以看出,應用框架的設計者使用模板模式預先定義好網頁應用程式、手機應用程式、測試腳本的執行步驟。

使用者可以在這些既定步驟下實作業務需求,但這些步驟的呼叫時機卻是由系統決定。這樣的設計具有以下這些優勢。

一致性:確保整個系統的算法結構和流程一致,避免因個別實現差異而導致的不可預測行為。

靈活性:父類別定義通用流程,子類別可以根據具體需求覆寫部分步驟,使得同一流程可以適應不同的情境和需求。

重用性:父類別中的通用部分可以被多個子類別重用,減少程式碼重複,提高程式碼的可維護性和擴展性。

控制權限:父類別控制流程的執行順序,確保關鍵步驟不會被子類別隨意修改,保障系統的穩定性和安全性。

清晰分工:將算法的固定部分與可變部分分離,使得程式碼結構更加清晰,便於理解和維護。


隱藏的缺點 : 呼叫控制的反轉

雖然模板模式有諸多好處,但這種體現好萊塢原則("Don't call us, we'll call you")的設計反轉了函數的呼叫控制。

這樣的設計卻可能會導致我們開發出許多自己都不知道為什麼能正常運行的程式。

原因在於一些簡單的業務邏輯在各個不同的回調函數下實作時可能不會發生問題,這反而會讓工程師誤以為自己已經完全理解了框架的運作原理。

直到BUG實際在客戶手上發生的那一天,工程師們才能真正感受到誤用框架的恐懼。

當你在凝視框架的同時,框架也在凝視著你。

圖片來源: google

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.