程式碼復用在軟體開發中分為兩個層次:一是架構層面的「設計復用」(跨專案重用模組),二是模組內部的「實作復用」。本文著重於後者——在開發單一模組時,如何透過提煉基礎函式、像搭積木般組合複雜功能,從而大幅提升可讀性與可維護性。
假設雙向鏈表(DLL)模組已有 dll_push_tail()(尾端插入)與 dll_pop_head()(頭端移除)兩個基礎函式。若需實作「合併兩個鏈表」的 dll_merge(),初學者可能直接複製貼上節點操作邏輯:
void dll_merge(dll_t *_p_dest, dll_t *_p_src)
{
dll_node_t *p_node = _p_src->head_;
while (p_node != 0) {
if (_p_dest->tail_ == 0) {
_p_dest->head_ = _p_dest->tail_ = p_node;
_p_dest->next_ = _p_dest->prev_ = 0; // 注意:此處原始碼有誤,應為 p_node->next_...
} else {
dll_node_t *p_tail = _p_dest->tail_;
p_tail->next_ = _p_dest; // 同樣邏輯錯誤
_p_dest->prev_ = p_tail;
_p_dest->next_ = 0;
_p_dest->tail_ = _p_dest;
}
_p_dest->count_++;
p_node = p_node->next_;
}
_p_src->count_ = 0;
_p_src->head_ = _p_src->tail_ = 0;
}
此寫法功能雖正確,但缺點明顯:
void dll_merge(dll_t *_p_dest, dll_t *_p_src)
{
dll_node_t *p_node = dll_pop_head(_p_src);
while (p_node != 0) {
dll_push_tail(_p_dest, p_node);
p_node = dll_pop_head(_p_src);
}
}
優點一目了然:
dll_push_tail/dll_pop_head,修改一處處處生效。有人擔心函式呼叫帶來額外開銷。現代處理器對函式呼叫優化極佳,開銷幾乎可忽略。若極度在意,可將基礎函式宣告為 inline,編譯器將直接展開程式碼,兼得「零開銷」與「高可維護性」:
inline void dll_push_tail(dll_t *, dll_node_t *);
inline dll_node_t *dll_pop_head(dll_t *);
核心原則:先提煉正交的基礎操作,再以組合方式構建上層功能。這不僅是程式碼復用,更是軟體架構「高內聚、低耦合」在微觀層面的體現。
本文出自 “至簡李雲” 博客,請務必保留此出處:https://yunli.blog.51cto.com/831344/263932