iT邦幫忙

2025 iThome 鐵人賽

DAY 13
0
Software Development

Clean Architecture 無瑕的程式碼:國中生阿吉的暑期閱讀筆記系列 第 13

Day 13:CCP 共同封閉,一起變動的放一起 (給我們看海盜船!!)

  • 分享至 

  • xImage
  •  

今日主題:

程式設計有時候很像玩樂高。
大家通常看到的是一艘拼好的「樂高海盜船」,
而不是每一個小零件是怎麼拼起來的。

可是要蓋出穩固的船,還是得知道一些「放零件的規則」。
時常需要兼顧兩邊不同的要求。
今天繼續來學習 CCP 共同封閉原則吧:
那些會因著相同理由、在相同時間發生變化的類別搜集到相同的元件之中。

有點不了解 CCP 跟 REP,都是「放在一起」,卻有不同的理由。

原則 重點 範例 浮點數修改的例子
REP共同重複使用原則 同一份定義放一起,避免重複 PI 常數、單位換算表 PI = 3.14159:圓面積、圓周長都用到,所以要集中定義,不要每個地方各自寫一份
CCP共同封閉原則 會常常一起修改的功能放一起 加法 + 乘法演算法 當系統要從「只能算整數」→「也能算小數(浮點數)」時,加法和乘法的程式通常要同時修改,所以要放在同一個模組裡

範例故事:

現在傳遞訊息已經都不是單向的,所以文章留言功能特別重要。這就是海盜船容易被看見的地方。
但同時也要考慮輸入,會產生資安上的問題。
後端的程式可以進行保護,但也可以使用簡單的做法繞過,
今天新增了留言功能:

  1. 使用 utterances 讓單篇文章留言放 github issue。
  2. 同一篇文章放同一個 issue

https://ithelp.ithome.com.tw/upload/images/20250927/20107703nm8rgHfqkT.png

在程式中的應用是什麼?

CCP 舉例:

// math.js
function add(a, b) {
  return parseInt(a) + parseInt(b);
}

function multiply(a, b) {
  return parseInt(a) * parseInt(b);
}

console.log(add(2, 3));       // 5
console.log(multiply(2, 3));  // 6
console.log(add(2.5, 3.5));   // ❌ 只能算整數,結果錯誤

留言功能實作:

<template>
  <section class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
    <div class="bg-white rounded-lg shadow-sm border p-6">
      <h2 class="text-2xl font-bold text-gray-900 mb-4">留言討論 (使用 GitHub Issues)</h2>
      <div ref="container" id="utterances-container"></div>
    </div>
  </section>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'

const props = defineProps<{
  repo?: string
  issueTerm?: string
  theme?: string
  articleTitle?: string
  currentPath?: string
}>()

const container = ref<HTMLElement | null>(null)

const repo = props.repo ?? 'xxx'
const issueTerm = props.issueTerm ?? 'pathname'
const theme = props.theme ?? 'dark-blue'

let scriptEl: HTMLScriptElement | null = null
let previousTitle: string | undefined

function createUtterances() {
  if (!container.value) return
  // remove existing children
  container.value.innerHTML = ''

  // If issue-term is `title`, utterances reads document.title; only override when explicitly requested
  if (issueTerm === 'title' && props.articleTitle) {
    previousTitle = document.title
    document.title = props.articleTitle
  }

  scriptEl = document.createElement('script')
  scriptEl.setAttribute('src', 'https://utteranc.es/client.js')
  scriptEl.setAttribute('repo', repo)
  scriptEl.setAttribute('issue-term', issueTerm)
  scriptEl.setAttribute('theme', theme)
  scriptEl.setAttribute('crossorigin', 'anonymous')
  scriptEl.setAttribute('async', 'true')

  container.value.appendChild(scriptEl)
}

function removeUtterances() {
  if (container.value) {
    container.value.innerHTML = ''
  }
  if (previousTitle !== undefined) {
    document.title = previousTitle
    previousTitle = undefined
  }
  scriptEl = null
}

onMounted(() => {
  createUtterances()
})

onBeforeUnmount(() => {
  removeUtterances()
})

// re-create when title changes (useful for SPA navigation)
// re-create when title or currentPath changes (SPA navigation)
watch(
  () => [props.articleTitle, props.currentPath],
  () => {
    removeUtterances()
    createUtterances()
  },
)
</script>

<style scoped>
</style>

小結與一個思考問題:

  • 在設計程式時,我除了「結構」以外,還應該考慮什麼?
  • AI 能不能幫忙思考「超越結構」的設計?

上一篇
Day 12:元件內聚性的三個原則(AI constructions 也有設計準則嗎)
下一篇
Day14 : CRP 共同重用:功能不要綁手綁腳,沒用到就不要
系列文
Clean Architecture 無瑕的程式碼:國中生阿吉的暑期閱讀筆記18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言