[{"data":1,"prerenderedAt":974},["ShallowReactive",2],{"navigation_docs":3,"-nuxt-adapter-abstraction-layer":352,"-nuxt-adapter-abstraction-layer-surround":969},[4,54,83,116,125,161,179,200],{"title":5,"path":6,"stem":7,"children":8},"Ai","/ai","ai",[9,12,42,46,50],{"title":10,"path":6,"stem":11},"AI 技術探索","ai/index",{"title":13,"path":14,"stem":15,"children":16,"page":41},"Rag","/ai/rag","ai/RAG",[17,21,25,29,33,37],{"title":18,"path":19,"stem":20},"BM25 演算法深入解析：從 TF-IDF 到現代搜尋引擎的核心技術","/ai/rag/bm25-deep-dive-from-tf-idf-to-rag","ai/RAG/bm25-deep-dive-from-tf-idf-to-rag",{"title":22,"path":23,"stem":24},"Dense Retrieval（向量檢索）深入解析","/ai/rag/dense-retrieval-deep-dive","ai/RAG/dense-retrieval-deep-dive",{"title":26,"path":27,"stem":28},"RAG（Retrieval-Augmented Generation）原理與實作入門","/ai/rag/rag-intro-principles-and-implementation","ai/RAG/rag-intro-principles-and-implementation",{"title":30,"path":31,"stem":32},"RAG Retrieval Strategy 深入解析","/ai/rag/rag-retrieval-strategy-deep-dive","ai/RAG/rag-retrieval-strategy-deep-dive",{"title":34,"path":35,"stem":36},"Reciprocal Rank Fusion（RRF）教學：打造更穩定的檢索融合策略","/ai/rag/rrf-reciprocal-rank-fusion-guide","ai/RAG/rrf-reciprocal-rank-fusion-guide",{"title":38,"path":39,"stem":40},"TF-IDF（Term Frequency–Inverse Document Frequency）深入解析","/ai/rag/tf-idf-deep-dive","ai/RAG/tf-idf-deep-dive",false,{"title":43,"path":44,"stem":45},"Docus AI 功能完整實作指南","/ai/docus-ai-implementation","ai/docus-ai-implementation",{"title":47,"path":48,"stem":49},"llms.txt 是什麼？在 Nuxt 中控制 AI 與搜尋引擎爬蟲的新方式","/ai/llms-txt","ai/llms-txt",{"title":51,"path":52,"stem":53},"MCP（Model Context Protocol）是什麼？用「AI 的 USB-C」理解模型如何安全連接工具與資料","/ai/mcp_concept","ai/mcp_concept",{"title":55,"path":56,"stem":57,"children":58,"page":41},"Data Analysis","/data-analysis","data-analysis",[59,63,67,71,75,79],{"title":60,"path":61,"stem":62},"Exploratory Data Analysis（EDA）資料探索分析入門","/data-analysis/exploratory-data-analysis-eda","data-analysis/exploratory-data-analysis-eda",{"title":64,"path":65,"stem":66},"PR-AUC 深入解析：不平衡分類問題的重要評估指標","/data-analysis/pr-auc-for-imbalanced-classification","data-analysis/pr-auc-for-imbalanced-classification",{"title":68,"path":69,"stem":70},"ROC-AUC 深入解析：理解分類模型的判斷能力","/data-analysis/roc-auc-complete-guide","data-analysis/roc-auc-complete-guide",{"title":72,"path":73,"stem":74},"SHAP（SHapley Additive exPlanations）模型解釋方法深入解析","/data-analysis/shap-model-interpretation-complete-guide","data-analysis/shap-model-interpretation-complete-guide",{"title":76,"path":77,"stem":78},"Social Network Analysis（SNA）深入解析","/data-analysis/social-network-analysis-sna","data-analysis/social-network-analysis-sna",{"title":80,"path":81,"stem":82},"Time-based Split：為什麼時間序列資料不能使用 Random Split？","/data-analysis/time-based-split-vs-random-split","data-analysis/time-based-split-vs-random-split",{"title":84,"path":85,"stem":86,"children":87,"page":41},"MachineLearning","/machine_learning","machine_learning",[88,92,96,100,104,108,112],{"title":89,"path":90,"stem":91},"Confusion Matrix（混淆矩陣）完整解析","/machine_learning/confusion-matrix","machine_learning/confusion-matrix",{"title":93,"path":94,"stem":95},"Decision Tree 模型完整教學：從原理到 Python 實作","/machine_learning/decision-tree-complete-guide","machine_learning/decision-tree-complete-guide",{"title":97,"path":98,"stem":99},"為什麼 Decision Tree 在 Tabular Data 上常常勝過 Deep Learning？","/machine_learning/decision-tree-vs-deep-learning-on-tabular-data","machine_learning/decision-tree-vs-deep-learning-on-tabular-data",{"title":101,"path":102,"stem":103},"LightGBM 模型入門：理解高效能的 Gradient Boosting 演算法","/machine_learning/lightgbm-intro-for-tabular-data","machine_learning/lightgbm-intro-for-tabular-data",{"title":105,"path":106,"stem":107},"Logistic Regression（Logit 回歸）完整教學","/machine_learning/logistic-regression-complete-guide","machine_learning/logistic-regression-complete-guide",{"title":109,"path":110,"stem":111},"為什麼模型訓練需要 Train / Validation / Test Dataset？","/machine_learning/train-validation-test-dataset","machine_learning/train-validation-test-dataset",{"title":113,"path":114,"stem":115},"XGBoost 原理與實務教學","/machine_learning/xgboost-complete-guide","machine_learning/xgboost-complete-guide",{"title":117,"path":118,"stem":119,"children":120,"page":41},"Network","/network","network",[121],{"title":122,"path":123,"stem":124},"DNS 設定入門：CNAME vs A Record 完整解析","/network/dns-cname-vs-a-record-guide","network/dns-cname-vs-a-record-guide",{"title":126,"path":127,"stem":128,"children":129},"Nuxt","/nuxt","nuxt",[130,133,137,141,145,149,153,157],{"title":131,"path":127,"stem":132},"Nuxt 實戰指南","nuxt/index",{"title":134,"path":135,"stem":136},"Abstraction Layer 與 Adapter 的差別，一次搞懂設計角色","/nuxt/adapter_abstraction_layer","nuxt/adapter_abstraction_layer",{"title":138,"path":139,"stem":140},"Nuxt 4 全面理解 — 專案檔案結構解析","/nuxt/directory_structure","nuxt/directory_structure",{"title":142,"path":143,"stem":144},"Nuxt 前端 build 流程完整解析","/nuxt/frontend_build","nuxt/frontend_build",{"title":146,"path":147,"stem":148},"Nitro 是什麼？從 Nuxt 專案到 Server 與 Edge 的關鍵引擎","/nuxt/nitro","nuxt/nitro",{"title":150,"path":151,"stem":152},"深入理解 Nuxt 的 .nuxt 與 .output：為什麼部署時一定要分清楚？","/nuxt/nuxt_and_output","nuxt/nuxt_and_output",{"title":154,"path":155,"stem":156},"Nuxt 中 dev、build、preview 的差異一次搞懂","/nuxt/nuxt_dev_build_preview","nuxt/nuxt_dev_build_preview",{"title":158,"path":159,"stem":160},"Nuxt Image vs \u003Cimg>：為什麼 Nuxt 3 專案幾乎都該用 \u003CNuxtImg>？","/nuxt/nuxt_image","nuxt/nuxt_image",{"title":162,"path":163,"stem":164,"children":165},"Python 程式開發","/python","python/index",[166,167,171,175],{"title":162,"path":163,"stem":164},{"title":168,"path":169,"stem":170},"如何在 FastAPI 中調用記憶體 Buffer 回傳圖片 (附實例)","/python/memory_buffer","python/memory_buffer",{"title":172,"path":173,"stem":174},"Python 單元測試教學：如何為你的程式撰寫 Test","/python/python-unit-testing-unittest-pytest","python/python-unit-testing-unittest-pytest",{"title":176,"path":177,"stem":178},"如何使用 uv 取代 pip：改善 Python 專案的開發流程","/python/uv","python/uv",{"title":180,"path":181,"stem":182,"children":183,"page":41},"Statistic","/statistic","statistic",[184,188,192,196],{"title":185,"path":186,"stem":187},"卡方檢定（Chi-Square Test）入門教學","/statistic/chi-square-test-intro","statistic/chi-square-test-intro",{"title":189,"path":190,"stem":191},"常見抽樣方法（Sampling Methods）教學：Stratified、Quota、Convenience、Systematic、Simple Random","/statistic/common-sampling-methods-guide","statistic/common-sampling-methods-guide",{"title":193,"path":194,"stem":195},"Cramér’s V 指標介紹：如何衡量兩個類別變數之間的關聯","/statistic/cramers-v-for-categorical-association","statistic/cramers-v-for-categorical-association",{"title":197,"path":198,"stem":199},"Mann–Whitney U 與 Kolmogorov–Smirnov（KS）檢定：非參數統計檢定的入門指南","/statistic/mann-whitney-u-and-ks-test-intro","statistic/mann-whitney-u-and-ks-test-intro",{"title":201,"path":202,"stem":203,"children":204},"WebDev","/web_dev","web_dev",[205,208,234,248,282,312,334],{"title":206,"path":202,"stem":207},"Web 前端開發","web_dev/index",{"title":209,"path":210,"stem":211,"children":212},"瀏覽器與渲染","/web_dev/browser","web_dev/browser/index",[213,214,218,222,226,230],{"title":209,"path":210,"stem":211},{"title":215,"path":216,"stem":217},"瀏覽器儲存空間完整解析：Cookie、localStorage、IndexedDB 到 Cache Storage","/web_dev/browser/browser-storage-comprehensive-guide","web_dev/browser/browser-storage-comprehensive-guide",{"title":219,"path":220,"stem":221},"DOM (Document Object Model) 深入解析","/web_dev/browser/dom","web_dev/browser/dom",{"title":223,"path":224,"stem":225},"Service Worker Request Flow 深入解析","/web_dev/browser/service-worker-request-flow","web_dev/browser/service-worker-request-flow",{"title":227,"path":228,"stem":229},"CSR、SSR 與 SSG 是什麼？前端渲染策略完整比較","/web_dev/browser/ssr_csr_ssg","web_dev/browser/ssr_csr_ssg",{"title":231,"path":232,"stem":233},"Virtual DOM 深入解析：為什麼它能優化前端效能？","/web_dev/browser/virtual_dom","web_dev/browser/virtual_dom",{"title":235,"path":236,"stem":237,"children":238},"圖形技術","/web_dev/graphics","web_dev/graphics/index",[239,240,244],{"title":235,"path":236,"stem":237},{"title":241,"path":242,"stem":243},"為什麼 Three.js 專案幾乎都選擇 CSR？從 SSR 問題談起","/web_dev/graphics/threejs_csr","web_dev/graphics/threejs_csr",{"title":245,"path":246,"stem":247},"WebGL 是什麼？為什麼前端 3D 幾乎都靠它？","/web_dev/graphics/webgl","web_dev/graphics/webGL",{"title":249,"path":250,"stem":251,"children":252},"架構與配置","/web_dev/infrastructure","web_dev/infrastructure/index",[253,254,258,262,266,270,274,278],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257},"Zeabur + K3s + Nuxt 部署架構完整解析","/web_dev/infrastructure/k3s-zeabur","web_dev/infrastructure/K3s-zeabur",{"title":259,"path":260,"stem":261},"ECS vs Docker vs Kubernetes：從部署堆疊理解三層架構","/web_dev/infrastructure/ecs-docker-kubernetes-stack","web_dev/infrastructure/ecs-docker-kubernetes-stack",{"title":263,"path":264,"stem":265},"ECS vs VPS 是什麼？從部署網站的角度一次搞懂差別","/web_dev/infrastructure/ecs-vs-vps","web_dev/infrastructure/ecs-vs-vps",{"title":267,"path":268,"stem":269},"Zeabur 內網服務連線完整入門指南","/web_dev/infrastructure/k3s-internal-networking","web_dev/infrastructure/k3s-internal-networking",{"title":271,"path":272,"stem":273},"使用 Microservices 架構設計系統的優勢解析","/web_dev/infrastructure/microservices-architecture-advantages","web_dev/infrastructure/microservices-architecture-advantages",{"title":275,"path":276,"stem":277},"Nginx 入門教學：從反向代理到與 Kubernetes 的架構比較","/web_dev/infrastructure/nginx-intro","web_dev/infrastructure/nginx-intro",{"title":279,"path":280,"stem":281},"YAML 配置是什麼？為什麼現代開發都在用它","/web_dev/infrastructure/yaml-configuration","web_dev/infrastructure/yaml-configuration",{"title":283,"path":284,"stem":285,"children":286},"網絡與通訊","/web_dev/network","web_dev/network/index",[287,288,292,296,300,304,308],{"title":283,"path":284,"stem":285},{"title":289,"path":290,"stem":291},"HTTP Request 結構完整解析：從 Request Line 到 Header 一次看懂","/web_dev/network/http-request-structure","web_dev/network/http-request-structure",{"title":293,"path":294,"stem":295},"OSI 模型（Open Systems Interconnection Model）完整解析","/web_dev/network/osi-model","web_dev/network/osi-model",{"title":297,"path":298,"stem":299},"RESTful API 設計原則與實務解析","/web_dev/network/restful-api","web_dev/network/restful-api",{"title":301,"path":302,"stem":303},"RESTful API 五大設計原則深入解析","/web_dev/network/restful-api-principles","web_dev/network/restful-api-principles",{"title":305,"path":306,"stem":307},"Server-Sent Events (SSE) 深入解析與實作教學","/web_dev/network/sse-introduction","web_dev/network/sse-introduction",{"title":309,"path":310,"stem":311},"WebSocket 入門教學：從概念到 Node.js 實作","/web_dev/network/websocket-introduction","web_dev/network/websocket-introduction",{"title":313,"path":314,"stem":315,"children":316},"認證與安全","/web_dev/security","web_dev/security/index",[317,318,322,326,330],{"title":313,"path":314,"stem":315},{"title":319,"path":320,"stem":321},"使用 Cookie 與 Session 建立使用者驗證（完整新手教學）","/web_dev/security/cookie-session-authentication","web_dev/security/cookie-session-authentication",{"title":323,"path":324,"stem":325},"JWT 驗證機制完整解析：從登入流程到實務應用","/web_dev/security/jwt-authentication","web_dev/security/jwt-authentication",{"title":327,"path":328,"stem":329},"Secret Key 簽名是什麼？從零理解資料簽名的本質","/web_dev/security/secret-key-signing","web_dev/security/secret-key-signing",{"title":331,"path":332,"stem":333},"SSH（Secure Shell）是什麼？從遠端登入到安全通道的核心概念","/web_dev/security/ssh","web_dev/security/ssh",{"title":335,"path":336,"stem":337,"children":338},"SEO 與規範","/web_dev/seo","web_dev/seo/index",[339,340,344,348],{"title":335,"path":336,"stem":337},{"title":341,"path":342,"stem":343},"Canonical URL 是什麼？用生活化方式搞懂前端 SEO 的基本保命符","/web_dev/seo/canonical_link","web_dev/seo/canonical_link",{"title":345,"path":346,"stem":347},"robots.txt 是什麼？SEO 的第一道守門員","/web_dev/seo/robot_txt","web_dev/seo/robot_txt",{"title":349,"path":350,"stem":351},"Nuxt SEO 中的 Meta 與 SEO 工具是如何運作的？","/web_dev/seo/seo","web_dev/seo/seo",{"id":353,"title":134,"body":354,"description":956,"extension":957,"links":958,"meta":959,"navigation":721,"path":135,"seo":967,"stem":136,"__hash__":968},"docs/nuxt/adapter_abstraction_layer.md",{"type":355,"value":356,"toc":938},"minimark",[357,362,366,374,377,390,393,396,399,402,413,416,427,430,432,436,439,446,449,451,456,459,512,515,529,532,539,541,545,548,563,566,577,583,586,588,592,595,602,605,612,618,620,624,627,662,665,673,676,756,759,761,765,768,775,781,784,786,790,793,807,810,812,816,822,824,828,831,853,859,862,864,868,871,885,888,893,896,898,901,904,914,917,931,934],[358,359,361],"h2",{"id":360},"為什麼-abstraction-layer-跟-adapter-常被搞混","為什麼 abstraction layer 跟 adapter 常被搞混？",[363,364,365],"p",{},"在實務開發中，**abstraction layer（抽象層）**與 **adapter（適配器）**幾乎總是一起出現。\n也因為它們高度共存，很多人會以為這是「同一件事的不同說法」。",[363,367,368,369,373],{},"但實際上，它們解決的是",[370,371,372],"strong",{},"完全不同層級的問題","。",[363,375,376],{},"理解這兩者的差別，會直接影響你在：",[378,379,380,384,387],"ul",{},[381,382,383],"li",{},"架構系統",[381,385,386],{},"拆模組",[381,388,389],{},"設計可維護程式碼",[363,391,392],{},"時，做出正確的決策。",[394,395],"hr",{},[358,397,398],{"id":398},"一句話先建立直覺",[363,400,401],{},"在進入細節前，先給你一個工程師好記的版本：",[403,404,405],"blockquote",{},[363,406,407,410],{},[370,408,409],{},"Abstraction layer（抽象層）定義「要做什麼」",[370,411,412],{},"Adapter（適配器）負責「怎麼接上去」",[363,414,415],{},"如果用比喻來說：",[417,418,423],"pre",{"className":419,"code":421,"language":422},[420],"language-text","Abstraction layer = 規格 / 介面\nAdapter = 轉接頭\n","text",[424,425,421],"code",{"__ignoreMap":426},"",[363,428,429],{},"這個比喻在後面會反覆出現。",[394,431],{},[358,433,435],{"id":434},"abstraction-layer-是什麼","Abstraction layer 是什麼？",[363,437,438],{},"抽象層的核心目的只有一個：",[403,440,441],{},[363,442,443],{},[370,444,445],{},"隱藏底層實作細節，讓上層程式碼只關心「能力」，而不是「怎麼做」",[363,447,448],{},"當你在寫應用程式時，你其實不希望每一層都知道所有底層細節，否則整個系統會變得高度耦合、難以維護。",[394,450],{},[452,453,455],"h3",{"id":454},"一個常見的例子資料庫操作","一個常見的例子：資料庫操作",[363,457,458],{},"假設你在專案中寫的是：",[417,460,464],{"className":461,"code":462,"language":463,"meta":426,"style":426},"language-js shiki shiki-themes github-dark","database.query()\ndatabase.insert()\ndatabase.update()\ndatabase.delete()\n","js",[424,465,466,482,492,502],{"__ignoreMap":426},[467,468,471,475,479],"span",{"class":469,"line":470},"line",1,[467,472,474],{"class":473},"s95oV","database.",[467,476,478],{"class":477},"svObZ","query",[467,480,481],{"class":473},"()\n",[467,483,485,487,490],{"class":469,"line":484},2,[467,486,474],{"class":473},[467,488,489],{"class":477},"insert",[467,491,481],{"class":473},[467,493,495,497,500],{"class":469,"line":494},3,[467,496,474],{"class":473},[467,498,499],{"class":477},"update",[467,501,481],{"class":473},[467,503,505,507,510],{"class":469,"line":504},4,[467,506,474],{"class":473},[467,508,509],{"class":477},"delete",[467,511,481],{"class":473},[363,513,514],{},"這時候，你的程式碼並沒有在意底層實際使用的是：",[378,516,517,520,523,526],{},[381,518,519],{},"PostgreSQL",[381,521,522],{},"MySQL",[381,524,525],{},"SQLite",[381,527,528],{},"Supabase",[363,530,531],{},"你只在乎「我可以查詢、寫入、更新、刪除」。",[363,533,534,535,538],{},"這一層 ",[370,536,537],{},"database API","，就是一個典型的 abstraction layer。\n它把底層的 SQL driver、連線管理、語法差異全部藏起來。",[394,540],{},[452,542,544],{"id":543},"作業系統-api-也是抽象層","作業系統 API 也是抽象層",[363,546,547],{},"像這樣的呼叫：",[417,549,551],{"className":461,"code":550,"language":463,"meta":426,"style":426},"File.open()\n",[424,552,553],{"__ignoreMap":426},[467,554,555,558,561],{"class":469,"line":470},[467,556,557],{"class":473},"File.",[467,559,560],{"class":477},"open",[467,562,481],{"class":473},[363,564,565],{},"在不同平台底下，實際執行的可能是：",[378,567,568,571,574],{},[381,569,570],{},"Windows 的檔案系統",[381,572,573],{},"Linux 的檔案系統",[381,575,576],{},"macOS 的檔案系統",[363,578,579,580,373],{},"但對你來說，這些差異並不存在。\n你只知道：",[370,581,582],{},"我可以開檔案",[363,584,585],{},"這正是抽象層存在的價值。",[394,587],{},[358,589,591],{"id":590},"adapter-是什麼","Adapter 是什麼？",[363,593,594],{},"如果說抽象層是在「畫規格」，那 adapter 就是：",[403,596,597],{},[363,598,599],{},[370,600,601],{},"真正把抽象層對應到某一個具體系統的實作者",[363,603,604],{},"換句話說，adapter 的工作是：",[403,606,607],{},[363,608,609],{},[370,610,611],{},"把 A 的介面，轉成 B 能理解的介面",[363,613,614,615,373],{},"這也是為什麼 adapter 本身就是一個經典的設計模式：\n",[370,616,617],{},"Adapter Pattern",[394,619],{},[452,621,623],{"id":622},"一個簡單的-python-概念例子","一個簡單的 Python 概念例子",[363,625,626],{},"假設你定義了一個抽象的儲存介面：",[417,628,632],{"className":629,"code":630,"language":631,"meta":426,"style":426},"language-py shiki shiki-themes github-dark","class Storage:\n    def save(file):\n        pass\n","py",[424,633,634,646,657],{"__ignoreMap":426},[467,635,636,640,643],{"class":469,"line":470},[467,637,639],{"class":638},"snl16","class",[467,641,642],{"class":477}," Storage",[467,644,645],{"class":473},":\n",[467,647,648,651,654],{"class":469,"line":484},[467,649,650],{"class":638},"    def",[467,652,653],{"class":477}," save",[467,655,656],{"class":473},"(file):\n",[467,658,659],{"class":469,"line":494},[467,660,661],{"class":638},"        pass\n",[363,663,664],{},"但你實際上可能有兩種儲存系統：",[378,666,667,670],{},[381,668,669],{},"本機檔案系統",[381,671,672],{},"AWS S3",[363,674,675],{},"這時候你不會改 abstraction layer，而是寫不同的 adapter：",[417,677,679],{"className":629,"code":678,"language":631,"meta":426,"style":426},"class LocalAdapter(Storage):\n    def save(file):\n        writeFile(file)\n\nclass S3Adapter(Storage):\n    def save(file):\n        s3.putObject(file)\n",[424,680,681,697,705,717,723,737,746],{"__ignoreMap":426},[467,682,683,685,688,691,694],{"class":469,"line":470},[467,684,639],{"class":638},[467,686,687],{"class":477}," LocalAdapter",[467,689,690],{"class":473},"(",[467,692,693],{"class":477},"Storage",[467,695,696],{"class":473},"):\n",[467,698,699,701,703],{"class":469,"line":484},[467,700,650],{"class":638},[467,702,653],{"class":477},[467,704,656],{"class":473},[467,706,707,710,714],{"class":469,"line":494},[467,708,709],{"class":473},"        writeFile(",[467,711,713],{"class":712},"s9osk","file",[467,715,716],{"class":473},")\n",[467,718,719],{"class":469,"line":504},[467,720,722],{"emptyLinePlaceholder":721},true,"\n",[467,724,726,728,731,733,735],{"class":469,"line":725},5,[467,727,639],{"class":638},[467,729,730],{"class":477}," S3Adapter",[467,732,690],{"class":473},[467,734,693],{"class":477},[467,736,696],{"class":473},[467,738,740,742,744],{"class":469,"line":739},6,[467,741,650],{"class":638},[467,743,653],{"class":477},[467,745,656],{"class":473},[467,747,749,752,754],{"class":469,"line":748},7,[467,750,751],{"class":473},"        s3.putObject(",[467,753,713],{"class":712},[467,755,716],{"class":473},[363,757,758],{},"抽象層不變\n更換的只有 adapter",[394,760],{},[358,762,764],{"id":763},"abstraction-layer-與-adapter-的關係","abstraction layer 與 adapter 的關係",[363,766,767],{},"這裡是整篇文章最重要的理解點。",[363,769,770,771,774],{},"抽象層與 adapter 並不是對立，而是",[370,772,773],{},"上下游關係","：",[417,776,779],{"className":777,"code":778,"language":422},[420],"Application Code\n      ↓\nAbstraction Layer（定義介面）\n      ↓\nAdapter（具體實作）\n      ↓\nReal System / Platform\n",[424,780,778],{"__ignoreMap":426},[363,782,783],{},"抽象層負責「統一世界觀」\nadapter 負責「適應現實世界」",[394,785],{},[358,787,789],{"id":788},"用硬體來比喻非常直覺","用硬體來比喻（非常直覺）",[363,791,792],{},"如果你覺得抽象概念太抽象，可以直接記這個：",[378,794,795,801],{},[381,796,797,800],{},[370,798,799],{},"Abstraction layer","：USB 標準",[381,802,803,806],{},[370,804,805],{},"Adapter","：USB-C → HDMI 轉接器",[363,808,809],{},"USB 規格定義了「我能傳資料、影像、電力」\n轉接器負責把這個能力，接到不同裝置上",[394,811],{},[358,813,815],{"id":814},"放回-nuxt-nitro-的脈絡中理解","放回 Nuxt / Nitro 的脈絡中理解",[363,817,818,819,373],{},"你最近在研究 Nitro，其實這正是一個",[370,820,821],{},"教科書等級的案例",[394,823],{},[452,825,827],{"id":826},"nitro-的-abstraction-layer","Nitro 的 abstraction layer",[363,829,830],{},"像這些 API：",[417,832,834],{"className":461,"code":833,"language":463,"meta":426,"style":426},"defineEventHandler()\nevent.node.req\nevent.node.res\n",[424,835,836,843,848],{"__ignoreMap":426},[467,837,838,841],{"class":469,"line":470},[467,839,840],{"class":477},"defineEventHandler",[467,842,481],{"class":473},[467,844,845],{"class":469,"line":484},[467,846,847],{"class":473},"event.node.req\n",[467,849,850],{"class":469,"line":494},[467,851,852],{"class":473},"event.node.res\n",[363,854,855,856,373],{},"它們讓你寫 server code 時，",[370,857,858],{},"不用關心執行環境",[363,860,861],{},"不管你最後跑在哪裡，你寫的程式碼都是一樣的。",[394,863],{},[452,865,867],{"id":866},"nitro-的-adapters","Nitro 的 adapters",[363,869,870],{},"Nitro 內部提供多種 adapter，例如：",[378,872,873,876,879,882],{},[381,874,875],{},"Node server adapter",[381,877,878],{},"Vercel adapter",[381,880,881],{},"Cloudflare Workers adapter",[381,883,884],{},"Bun adapter",[363,886,887],{},"這些 adapter 的責任是：",[403,889,890],{},[363,891,892],{},"把 Nitro 的 server 抽象，轉成各平台能執行的形式",[363,894,895],{},"也因此你可以做到「程式碼不改，部署環境隨意換」。",[394,897],{},[358,899,900],{"id":900},"最後總結",[363,902,903],{},"如果要用最精準的工程語言來說：",[403,905,906],{},[363,907,908,911],{},[370,909,910],{},"Abstraction layer 是設計概念（interface）",[370,912,913],{},"Adapter 是實作元件（implementation bridge）",[363,915,916],{},"或更白話一點：",[378,918,919,925],{},[381,920,921,922],{},"抽象層告訴你：",[370,923,924],{},"這個系統「能做什麼」",[381,926,927,928],{},"適配器負責處理：",[370,929,930],{},"這件事「在這個平台怎麼做」",[363,932,933],{},"一旦你把這個角色分清楚，很多架構上的選擇就會變得非常自然。",[935,936,937],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":426,"searchDepth":484,"depth":484,"links":939},[940,941,942,946,949,950,951,955],{"id":360,"depth":484,"text":361},{"id":398,"depth":484,"text":398},{"id":434,"depth":484,"text":435,"children":943},[944,945],{"id":454,"depth":494,"text":455},{"id":543,"depth":494,"text":544},{"id":590,"depth":484,"text":591,"children":947},[948],{"id":622,"depth":494,"text":623},{"id":763,"depth":484,"text":764},{"id":788,"depth":484,"text":789},{"id":814,"depth":484,"text":815,"children":952},[953,954],{"id":826,"depth":494,"text":827},{"id":866,"depth":494,"text":867},{"id":900,"depth":484,"text":900},"Abstraction layer 與 Adapter 常一起出現卻容易混淆，本文從系統架構與設計模式角度，搭配 Nuxt / Nitro 實例，帶你理解兩者真正的角色分工。","md",null,{"tags":960,"category":203,"date":966},[961,962,963,964,128,965],"architecture","design-pattern","abstraction","adapter","nitro","2026-02-11",{"title":134,"description":956},"BXNW2WIlzqmbYyy-Sgb40hOy53EnzVOicBrtd2Rtwc4",[970,972],{"title":131,"path":127,"stem":132,"description":971,"children":-1},"掌握 Nuxt.js 框架的各項功能，打造高效、流暢且具備視覺魅力的現代化 Web 應用。",{"title":138,"path":139,"stem":140,"description":973,"children":-1},"了解 Nuxt 4 框架的核心目錄與檔案規劃，掌握專案結構的設計理念，提升開發效率與架構清晰度。",1776690842562]