iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0

今日主題:

I (ISP):介面隔離原則

今天有一個考模擬考的功能
班長 = OPS(大介面,擁有所有科目的模擬考卷)。
數學小老師、英文小老師、自然小老師 = U1Ops / U2Ops / U3Ops(小介面)。
考卷內容 = 各科的操作方法(op1 / op2 / op3)。
班長手上有「全科模擬考卷」大集合,但他不會自己做,而是把卷子分發給各科小老師。

所以
數學小老師只要處理數學卷(不用管英文或自然)。
英文小老師只要處理英文卷。
自然小老師只要處理自然卷。


在製作畫面的時候也有一樣的情形。
我發現「文章管理」這件事太複雜了,所以關於文章的功能放在一起畫面變很長。
所以我把它拆成兩部分:

  • 新增文章
  • 管理文章(搜尋、修改、刪除)

雖然都是「文章」相關,但每個頁面只需要自己用得到的功能。
所以拆開來,各自服務需要的人(管理者或作者)。

範例故事:

今天,我成功把鐵人賽的第一篇文章放到部落格(歡呼!)
但在做的時候,發現還有好多地方需要改進:
我做了一個 AI 幫忙生文章的功能。(還在想怎麼整理 AI 提示)
我需要一個「預覽」按鈕,先看看文章長怎樣。
文章裡需要可以放程式碼的區塊(用 highlight.js、marked 來幫忙)。
就像蓋房子時,先把基礎做好,之後才會知道牆壁要不要加強、窗戶要不要改。

結果長這樣
https://ithelp.ithome.com.tw/upload/images/20250923/20107703L0ZhnXlBPI.png

在程式中的應用是什麼?

來處理前端啦!
我將 AI 產制的內容跟編輯分開,然後在另一個步驟看是不是要套用。
但以後想要擴增更多關於 AI 不同 Prompt 的功能,例如格式化、給靈感、或是產生特定內容

<!-- AI 協助面板 -->
                <div
                  :class="[
                    'rounded-lg border-2 border-blue-100 bg-gradient-to-br from-blue-50 to-indigo-50 transition-all duration-300 ease-in-out overflow-hidden',
                    {
                      'p-4 max-h-96 opacity-100': aiPanel.show,
                      'p-0 max-h-0 opacity-0': !aiPanel.show,
                    },
                  ]"
                >
                  <h4 class="text-sm font-semibold text-indigo-700 mb-3 flex items-center">
                    🤖 AI 寫作協助
                  </h4>

                  <div class="flex flex-col sm:flex-row gap-2 mb-3">
                    <input
                      type="text"
                      v-model="aiPanel.prompt"
                      placeholder="輸入您的需求,例如:改善這篇文章的結構"
                      @keyup.enter="handleAiAssist"
                      class="flex-1 px-3 py-2 border border-gray-300 rounded-md text-sm focus:border-indigo-400 focus:ring-2 focus:ring-indigo-200 focus:outline-none"
                    />
                    <button
                      type="button"
                      @click="handleAiAssist"
                      :disabled="!aiPanel.prompt.trim() || aiPanel.loading"
                      class="px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center whitespace-nowrap"
                    >
                      <span v-if="aiPanel.loading" class="loading-spinner mr-2"></span>
                      {{ aiPanel.loading ? '生成中...' : '生成內容' }}
                    </button>
                  </div>

                  <div
                    v-if="aiPanel.result"
                    class="bg-white p-3 rounded-md border border-blue-200 mb-3 max-h-32 overflow-y-auto text-gray-700 text-sm leading-relaxed prose prose-sm max-w-none"
                    v-html="renderedAiResult"
                  ></div>

                  <div v-if="aiPanel.result" class="flex flex-wrap gap-2">
                    <button
                      type="button"
                      @click="applyAiResult"
                      class="px-3 py-1 bg-green-600 text-white text-xs font-medium rounded hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2"
                    >
                      套用到內容
                    </button>
                    <button
                      type="button"
                      @click="appendAiResult"
                      class="px-3 py-1 bg-gray-600 text-white text-xs font-medium rounded hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2"
                    >
                      附加到內容
                    </button>
                    <button
                      type="button"
                      @click="clearAiResult"
                      class="px-3 py-1 bg-gray-600 text-white text-xs font-medium rounded hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2"
                    >
                      清除結果
                    </button>
                  </div>
                </div>

小結與一個思考問題:

「架構」是一種把事情分得清楚的方式。
它不只用在程式,也用在團隊合作。

想想看:
架構是一開始就把所有功能就想好嗎?
如何再慢慢擴展的過程中去拼湊架構,並為後面的功能增加彈性呢?


上一篇
Day8:LSP 里氏替換 ( 人不能,但 AI 可以換腦袋)
系列文
Clean Architecture 無瑕的程式碼:國中生阿吉的暑期閱讀筆記9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言