作者:程杰 前言 成為 詩(shī)人 后 可能 不需要 刻意 地 按照 某種 模式 去 創(chuàng)作, 但 成為 詩(shī)人 前 他們 一定 是 認(rèn)真 地 研究 過 成百上千 的 唐詩(shī) 宋詞、 古今 名句。
第 1 章 代碼無(wú)錯(cuò)就是優(yōu)?—— 簡(jiǎn)單工廠模式
1.5 活字印刷,面向?qū)ο?nbsp;> 位置 584
“第一, 要 改, 只需 更改 要 改之 字, 此為 可維護(hù); 第二, 這些 字 并非 用完 這次 就 無(wú)用, 完全可以 在后 來(lái)的 印刷 中 重復(fù) 使用, 此 乃 可復(fù)用; 第三, 此 詩(shī) 若要 加 字, 只需 另 刻字 加入 即可, 這是 可擴(kuò)展; 第四, 字 的 排列 其實(shí) 可能 是 豎排 可能 是 橫排, 此時(shí) 只需 將 活字 移動(dòng) 就可 做到 滿足 排列 需求, 此 是 靈活性好?!?nbsp;
1.10 簡(jiǎn)單工廠模式 > 位置 671
簡(jiǎn)單工廠模式, 也就是說, 到底 要 實(shí)例 化 誰(shuí), 將來(lái) 會(huì)不會(huì) 增加 實(shí)例 化 的 對(duì)象, 比如 增加 開 根 運(yùn)算, 這是 很容易 變化 的 地方, 應(yīng)該 考慮 用 一個(gè) 單獨(dú) 的 類 來(lái)做 這個(gè) 創(chuàng)造 實(shí)例 的 過程, 這就 是 工廠(備注:先用父類聲明對(duì)象,再看情況決定用哪個(gè)子類實(shí)例化對(duì)象)。
1.11 UML 類圖 > 位置 689 UML 類 圖 圖示 樣 例
注意 前面 的 符號(hào),’+' 表示 public,’–' 表示 private,’#' 表示 protected。 繼承 關(guān)系 用 空心 三角形 + 實(shí)線 來(lái) 表示。 實(shí)現(xiàn) 接口 用 空心 三角形 + 虛線 來(lái) 表示。
當(dāng) 一個(gè) 類’ 知道’ 另一個(gè) 類 時(shí)(備注:類里面有另一個(gè)類的對(duì)象), 可以 用 關(guān)聯(lián)( association)。 關(guān)聯(lián) 關(guān)系 用 實(shí)線 箭頭 來(lái) 表示。 聚合 表示 一種 弱 的’ 擁有’ 關(guān)系(備注:一個(gè)類中有另一個(gè)類的對(duì)象集合), 體現(xiàn) 的 是 A 對(duì)象 可以 包含 B 對(duì)象, 但 B 對(duì)象 不是 A 對(duì)象 的 一部分。聚合 關(guān)系 用 空心 的 菱形 + 實(shí)線 箭頭 來(lái) 表示?!?nbsp; 合成( Composition, 也有 翻譯 成’ 組合’ 的) 是一 種 強(qiáng)的’ 擁有’ 關(guān)系, 體現(xiàn) 了 嚴(yán)格 的 部分 和 整體 的 關(guān)系, 部分 和 整體 的 生命 周期 一樣。(備注:整體類初始化時(shí)同時(shí)構(gòu)造部分類的對(duì)象作為屬性) 。合成 關(guān)系 用 實(shí)心 的 菱形 + 實(shí)線 箭頭 來(lái) 表示。 另外, 你會(huì) 注意到 合成 關(guān)系 的 連線 兩端 還有 一個(gè) 數(shù)字’ 1′ 和 數(shù)字’ 2’, 這 被稱為 基數(shù)。 表明 這 一端 的 類 可以 有幾個(gè) 實(shí)例, 很 顯然, 一個(gè) 鳥 應(yīng)該 有兩 只 翅膀。 如果 一個(gè) 類 可能 有無(wú) 數(shù)個(gè) 實(shí)例, 則 就用’ n’ 來(lái) 表示。 關(guān)聯(lián) 關(guān)系、 聚合 關(guān)系 也可以 有 基數(shù) 的。
依賴 關(guān)系( Dependency)(備注:構(gòu)造函數(shù)以依賴的對(duì)象作為參數(shù)), 用 虛線 箭頭 來(lái) 表示。
第 2 章 商場(chǎng)促銷 —— 策略模式
2.4 策略模式 > 位置 777 策略模式( Strategy)。 策略 模式 定義 了 算法 家族, 分別 封裝 起來(lái), 讓 它們 之間 可以 互相 替換, 此 模式 讓 算法 的 變化, 不會(huì) 影響 到 使用 算法 的 客戶。
2.7 策略模式解析 > 位置 821
策略 模式 是一 種 定義 一系列 算法 的 方法, 從 概念上 來(lái)看, 所有這些 算法 完成 的 都是 相同 的 工作, 只是 實(shí)現(xiàn) 不同, 它 可以 以 相同 的 方式 調(diào)用 所有 的 算法, 減少 了 各種 算法 類 與 使用 算法 類 之間 的 耦合 [DPE]。 另外 一個(gè) 策略 模式 的 優(yōu)點(diǎn) 是 簡(jiǎn)化 了 單元 測(cè)試, 因?yàn)?每個(gè) 算法 都有 自己的 類, 可以 通過 自己的 接口 單獨(dú) 測(cè)試 [DPE]。
策略 模式 封裝了變化: 當(dāng) 不同 的 行為 堆砌 在 一個(gè) 類 中 時(shí), 就很 難 避免 使用 條件 語(yǔ)句 來(lái) 選擇 合適 的 行為。 將 這些 行為 封裝 在 一個(gè) 個(gè) 獨(dú)立 的 Strategy 類 中, 可以 在使 用 這些 行 為的 類 中 消除 條件 語(yǔ)句 [DP]。
策略 模式 就是 用來(lái) 封裝 算法 的, 但在 實(shí)踐中, 我們 發(fā)現(xiàn) 可以 用 它來(lái) 封裝 幾乎 任何 類型 的 規(guī)則, 只要 在 分析 過程中 聽到 需要 在不同時(shí)間應(yīng)用不同的業(yè)務(wù)規(guī)則, 就可以 考慮 使用 策略 模式 處理 這種 變化 的 可能性 [DPE]”。
第 3 章 拍攝 UFO—— 單一職責(zé)原則
3.4 單一職責(zé)原則 > 位置 879
單一職責(zé)原則, 意思 就是說, 功能 要 單一? 哈, 可以 簡(jiǎn)單 地 這么 理解, 它的 準(zhǔn)確 解釋 是, 就 一個(gè) 類 而言, 應(yīng)該 僅有 一個(gè) 引起 它 變化 的 原因 [ASD]。
3.5 方塊游戲的設(shè)計(jì) > 位置 903 如果 一個(gè) 類 承擔(dān) 的 職責(zé) 過多, 就 等于 把這 些 職責(zé) 耦合 在一起, 一個(gè) 職責(zé) 的 變化 可能 會(huì) 削弱 或者 抑制 這個(gè) 類 完成 其他 職責(zé) 的 能力。 這種 耦合 會(huì) 導(dǎo)致 脆弱 的 設(shè)計(jì), 當(dāng) 變化 發(fā)生 時(shí), 設(shè)計(jì) 會(huì) 遭受 到 意想不到 的 破壞 [ASD]。
第 4 章 考研求職兩不誤 —— 開放 – 封閉原則
4.1 考研失敗 > 位置 958 一個(gè) 國(guó)家, 兩種制度, 這 在政治上, 是 偉大 的 發(fā)明 哦。 在 軟件 設(shè)計(jì) 模式 中, 這種 不能 修改, 但可以 擴(kuò)展 的 思想 也是 最重要的 一種 設(shè)計(jì) 原則, 它 就是 開放 – 封閉 原則( The Open- Closeed Principle, 簡(jiǎn)稱 OCP) 或 叫開 – 閉 原則?!?nbsp;
4.2 開放 – 封閉原則 > 位置 962 這個(gè) 原則 其實(shí) 是有 兩個(gè) 特征, 一個(gè) 是說’ 對(duì)于 擴(kuò)展 是 開放 的( Open for extension)’, 另一個(gè) 是說’ 對(duì)于 更改 是 封閉 的( Closed for modification)'[ASD]?!?nbsp;
4.3 何時(shí)應(yīng)對(duì)變化 > 位置 994 在 我們 最初 編寫 代碼 時(shí), 假設(shè) 變化 不會(huì) 發(fā)生。 當(dāng) 變化 發(fā)生 時(shí), 我們 就 創(chuàng)建 抽象 來(lái) 隔離 以后 發(fā)生 的 同類 變化 [ASD]。
第 5 章 會(huì)修電腦不會(huì)修收音機(jī)?—— 依賴倒轉(zhuǎn)原則
5.3 依賴倒轉(zhuǎn)原則 > 位置 1083 依賴 倒轉(zhuǎn) 原則, 原話 解釋 是 抽象 不應(yīng)該 依賴 細(xì)節(jié), 細(xì)節(jié) 應(yīng)該 依賴于 抽象, 這 話 繞口, 說白 了, 就是 要 針對(duì) 接口 編程, 不要 對(duì) 實(shí)現(xiàn) 編程。
5.4 里氏代換原則 > 位置 1105 子類 型 必須 能夠 替換 掉 它們 的 父 類型 [ASD]。 由于 有 里氏代換原則, 才使 得 開放 – 封閉 成為 了 可能。 由于 子 類型 的 可替換 性 才使 得 使用 父 類 類型 的 模塊 在 無(wú)需 修改 的 情況下 就可以 擴(kuò)展。
再回 過頭 來(lái)看 依賴倒轉(zhuǎn)原則, 高層 模塊 不應(yīng)該 依賴 低層 模塊, 兩個(gè) 都應(yīng) 該 依賴 抽象。 依賴 倒轉(zhuǎn) 其實(shí) 就是 誰(shuí)也 不要 依靠 誰(shuí), 除了 約定 的 接口。
5.5 修收音機(jī) > 位置 1131 依賴 倒轉(zhuǎn) 其實(shí) 可以 說是 面向?qū)ο?/strong>設(shè)計(jì) 的 標(biāo)志, 用 哪種 語(yǔ)言 來(lái) 編寫 程序 不重要, 如果 編寫 時(shí) 考慮 的 都是 如何 針對(duì) 抽象 編程 而 不是 針對(duì) 細(xì)節(jié) 編程, 即 程序 中 所有 的 依賴 關(guān)系 都是 終止 于 抽象 類 或者 接口, 那就 是 面向 對(duì)象 的 設(shè)計(jì), 反之 那就 是 過程 化 的 設(shè)計(jì) 了 [ASD]?!?nbsp;
第 6 章 穿什么有這么重要?—— 裝飾模式
6.4 裝飾模式 > 位置 1229 裝飾模式(Decorator),動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé),就增加功能來(lái)說,裝飾模式比生成子類更為靈活。[DP]
裝飾 模式( Decorator) 結(jié)構(gòu)圖:
6.6 裝飾模式總結(jié) > 位置 1281 裝飾模式 是 為 已有 功能 動(dòng)態(tài) 地 添加 更多 功能 的 一種 方式。 把 每個(gè) 要 裝飾 的 功能 放在 單獨(dú) 的 類 中, 并 讓 這個(gè) 類 包裝 它 所要 裝飾 的 對(duì)象, 因此, 當(dāng) 需要 執(zhí)行 特殊 行為 時(shí), 客戶 代碼 就可以 在 運(yùn)行時(shí) 根據(jù) 需要 有選擇 地、 按 順序 地 使用 裝飾 功能 包裝 對(duì)象 了 [DP]。
6.6 裝飾模式總結(jié) > 位置 1289 裝飾 模式 的 優(yōu)點(diǎn) 我總 結(jié)下 來(lái)就 是, 把 類 中的 裝飾 功能 從 類 中 搬移 去除, 這樣 可以 簡(jiǎn)化 原 有的 類。 更大 的 好處 就是 有效地 把 類 的 核心 職責(zé) 和 裝飾 功能 區(qū)分 開了。 而且 可以 去除 相關(guān) 類 中 重復(fù) 的 裝飾 邏輯。”
第 7 章 為別人做嫁衣 —— 代理模式
7.5 代理模式 > 位置 1378 代理模式(Proxy),為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。[DP]
代理 模式( Proxy) 結(jié)構(gòu)圖 :
7.6 代理模式應(yīng)用 > 位置 1394 代理 模式 都用 在 一些 什么 場(chǎng)合 呢? 一般來(lái)說 分為 幾種, 第一, 遠(yuǎn)程代理, 也就是 為 一個(gè) 對(duì)象 在 不同 的 地址 空間 提供 局部 代表。 這樣 可以 隱藏 一個(gè) 對(duì)象 存在 于 不同 地址 空間 的 事實(shí) [DP]。
WebService 在. NET 中的 應(yīng)用 : 在 應(yīng)用 程序 的 項(xiàng)目 中 加入 一個(gè) Web 引用, 引用 一個(gè) WebService, 此時(shí) 會(huì)在 項(xiàng)目 中 生成 一個(gè) WebReference 的 文件夾 和 一些 文件, 其實(shí) 它們 就是 代理, 這就 使得 客戶 端 程序 調(diào)用 代理 就可以 解決 遠(yuǎn)程 訪問 的 問題。
第二 種 應(yīng)用 是 虛擬代理, 是 根據(jù) 需要 創(chuàng)建 開銷 很大 的 對(duì)象。 通過 它來(lái) 存放 實(shí)例 化 需要 很長(zhǎng) 時(shí)間 的 真實(shí) 對(duì)象 [DP]。 這樣 就可以 達(dá)到 性能 的 最優(yōu)化, 比如說 你 打開 一個(gè) 很大 的 HTML 網(wǎng)頁(yè) 時(shí), 里面 可能 有很 多的 文字 和 圖片, 但 你 還是 可以 很快 打開 它, 此時(shí) 你 所 看到 的 是 所有 的 文字, 但 圖片 卻是 一張 一張 地下 載 后才 能看 到。 那些 未 打開 的 圖片 框, 就是 通過 虛擬 代理 來(lái) 替代 了 真實(shí) 的 圖片, 此時(shí) 代理 存儲(chǔ) 了 真實(shí) 圖片 的 路徑 和 尺寸。
第三 種 應(yīng)用 是 安全代理, 用來(lái) 控制 真實(shí) 對(duì)象 訪問 時(shí) 的 權(quán)限 [DP]。 一般 用于 對(duì)象 應(yīng)該 有 不同 的 訪問 權(quán)限 的 時(shí)候。
第 四種 是 智能指引, 是指 當(dāng) 調(diào)用 真實(shí) 的 對(duì)象 時(shí), 代理 處理 另外 一些 事 [DP]。 如 計(jì)算 真實(shí) 對(duì)象 的 引用 次數(shù), 這樣 當(dāng) 該 對(duì)象 沒有 引用 時(shí), 可以 自動(dòng) 釋放 它; 或當(dāng) 第一次 引用 一個(gè) 持久 對(duì)象 時(shí), 將它 裝入 內(nèi)存; 或在 訪問 一個(gè) 實(shí)際 對(duì)象 前, 檢查 是否 已經(jīng) 鎖定 它, 以 確保 其他 對(duì)象 不能 改變 它。 它們 都是 通過 代理 在 訪問 一個(gè) 對(duì)象 時(shí) 附加 一些 內(nèi)務(wù) 處理。
代理 模式 其實(shí) 就是 在 訪問 對(duì)象 時(shí) 引入 一定程度 的 間接性, 因?yàn)?這種 間接 性, 可以 附加 多種 用途。
第 8 章 雷鋒依然在人間 —— 工廠方法模式
8.4 簡(jiǎn)單工廠 vs. 工廠方法 > 位置 1472 簡(jiǎn)單工廠 模式 的 最大 優(yōu)點(diǎn) 在于 工廠 類 中 包含 了 必要 的 邏輯 判斷, 根據(jù) 客戶 端 的 選擇 條件 動(dòng)態(tài) 實(shí)例 化 相關(guān) 的 類, 對(duì)于 客戶 端來(lái) 說, 去 除了 與 具體 產(chǎn)品 的 依賴。
工廠方法模式(Factory Method),定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類。工廠方法使一個(gè)類的實(shí)例化延遲到其子類。[DP] 工廠 方法 模式( Factory Method) 結(jié)構(gòu)圖:
把工廠類抽象出一個(gè)接口, 這個(gè) 接口 只有 一個(gè) 方法, 就是 創(chuàng)建 抽象 產(chǎn)品 的 工廠 方法。 然后, 所 有的 要 生產(chǎn) 具體 類 的 工廠, 就去 實(shí)現(xiàn) 這個(gè) 接口, 這樣, 一個(gè) 簡(jiǎn)單 工廠 模式 的 工廠 類, 變成 了 一個(gè) 工廠 抽象 接口 和 多個(gè) 具體 生成 對(duì)象 的 工廠。
工廠方法 把 簡(jiǎn)單 工廠 的 內(nèi)部 邏輯 判斷 移到 了 客戶 端 代碼 來(lái) 進(jìn)行。 你 想要 加 功能, 本來(lái) 是 改 工廠 類 的, 而 現(xiàn)在 是 修改 客戶 端!”
8.5 雷鋒工廠 > 位置 1530 工廠 方法 克服 了 簡(jiǎn)單 工廠 違背 開放 – 封閉 原則 的 缺點(diǎn), 又 保持 了 封裝 對(duì)象 創(chuàng)建 過程 的 優(yōu)點(diǎn)。
它們 都是 集中 封裝 了 對(duì)象 的 創(chuàng)建, 使得 要 更換 對(duì)象 時(shí), 不需 要做 大的 改動(dòng) 就可 實(shí)現(xiàn), 降低 了 客戶 程序 與 產(chǎn)品 對(duì)象 的 耦合。 工廠 方法 模式 是 簡(jiǎn)單 工廠 模式 的 進(jìn)一步 抽象 和 推廣。 由于 使 用了 多 態(tài) 性, 工廠 方法 模式 保持 了 簡(jiǎn)單 工廠 模式 的 優(yōu)點(diǎn), 而且 克服 了 它的 缺點(diǎn)。 但 缺點(diǎn) 是 由于 每 加 一個(gè) 產(chǎn)品, 就 需要 加 一個(gè) 產(chǎn)品 工廠 的 類, 增加 了 額外 的 開發(fā) 量。
第 9 章 簡(jiǎn)歷復(fù)印 —— 原型模式
9.3 原型模式 > 位置 1598 原型模式(Prototype),用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過拷貝這些原型創(chuàng)建新的對(duì)象。[DP]
原型 模式( Prototype) 結(jié)構(gòu)圖 :
原型 模式 其實(shí) 就是 從 一個(gè) 對(duì)象 再創(chuàng) 建 另外 一個(gè) 可 定制 的 對(duì)象, 而且 不需 知道 任何 創(chuàng)建 的 細(xì)節(jié)。
因?yàn)?nbsp;克隆 實(shí)在 是 太 常用 了, 所以. NET 在 System 命名 空間 中 提供 了 ICloneable 接口, 其中 就是 唯一 的 一個(gè) 方法 Clone(), 這樣 你就 只需 要 實(shí)現(xiàn) 這個(gè) 接口 就可以 完成 原型 模式 了。
9.5 淺復(fù)制與深復(fù)制 > 位置 1622 MemberwiseClone() 方法 是 這樣, 如果 字段 是 值 類型 的, 則 對(duì) 該 字段 執(zhí)行 逐 位 復(fù)制, 如果 字段 是 引用 類型, 則 復(fù)制 引用 但不 復(fù)制 引用 的 對(duì)象; 因此, 原始 對(duì)象 及其 復(fù)本 引用 同一 對(duì)象。
9.5 淺復(fù)制與深復(fù)制 > 位置 1641 淺復(fù)制, 被 復(fù)制 對(duì)象 的 所有 變量 都 含有 與 原來(lái) 的 對(duì)象 相同 的 值, 而 所有 的 對(duì)其 他 對(duì)象 的 引用 都 仍然 指向 原來(lái) 的 對(duì)象。 深復(fù)制 把 引用 對(duì)象 的 變量 指向 復(fù)制 過 的 新 對(duì)象, 而 不是 原 有的 被 引用 的 對(duì)象。 深 復(fù)制 要 深入 到 多少 層, 需要 事先 就 考慮 好, 而且 要 當(dāng)心 出現(xiàn) 循環(huán) 引用 的 問題, 需要 小心 處理, 這里 比較 復(fù)雜, 可以 慢慢 研究。
9.6 簡(jiǎn)歷的深復(fù)制實(shí)現(xiàn) > 位置 1656 比如說, 數(shù)據(jù) 集 對(duì)象 DataSet, 它 就有 Clone() 方法 和 Copy() 方法, Clone() 方法 用來(lái) 復(fù)制 DataSet 的 結(jié)構(gòu), 但不 復(fù)制 DataSet 的 數(shù)據(jù), 實(shí)現(xiàn) 了 原型 模式 的 淺 復(fù)制。 Copy() 方法 不但 復(fù)制 結(jié)構(gòu), 也 復(fù)制 數(shù)據(jù), 其實(shí) 就是 實(shí)現(xiàn) 了 原型 模式 的 深 復(fù)制。
第 10 章 考題抄錯(cuò)會(huì)做也白搭 —— 模板方法模式
10.3 提煉代碼 > 位置 1749 當(dāng) 我們 要 完成 在某 一 細(xì)節(jié) 層次 一致 的 一個(gè) 過程 或 一系列 步驟, 但 其 個(gè)別 步驟 在 更 詳細(xì) 的 層次 上 的 實(shí)現(xiàn) 可能 不 同時(shí), 我們 通??紤]用 模板方法模式 來(lái) 處理。
10.4 模板方法模式 > 位置 1763 模板方法模式,定義一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。[DP]
模板 方法 模式( TemplateMethod) 結(jié)構(gòu)圖 :
模板 方法 模式 是 通過 把 不變 行為 搬 移到 超 類, 去除 子類 中的 重復(fù) 代碼 來(lái) 體現(xiàn) 它的 優(yōu)勢(shì)。 當(dāng) 不 變的 和 可變 的 行為 在 方法 的 子類 實(shí)現(xiàn) 中 混合 在一起 的 時(shí)候, 不變 的 行為 就會(huì) 在 子類 中 重復(fù) 出現(xiàn)。 我們 通過 模板 方法 模式 把這 些 行為 搬移 到 單一 的 地方, 這樣 就 幫助 子類 擺脫 重復(fù) 的 不變 行為 的 糾纏。
第 11 章 無(wú)熟人難辦事?—— 迪米特法則
11.3 迪米特法則 > 位置 1845 迪米特法則(LoD) 也叫 最少 知識(shí) 原則。[J& DP] 迪米特法則(LoD),如果兩個(gè)類不必彼此直接通信,那么這兩個(gè)類就不應(yīng)當(dāng)發(fā)生直接的相互作用。如果其中一個(gè)類需要調(diào)用另一個(gè)類的某一個(gè)方法的話,可以通過第三者轉(zhuǎn)發(fā)這個(gè)調(diào)用。[J&DP]
迪 米 特 法則 首先 強(qiáng)調(diào) 的 前提 是在 類 的 結(jié)構(gòu)設(shè)計(jì) 上, 每一個(gè) 類 都應(yīng)當(dāng) 盡量降低成員的訪問權(quán)限 [J& DP], 也就是說, 一個(gè) 類 包裝 好 自己的 private 狀態(tài), 不需要 讓 別的 類 知道 的 字段 或 行為 就不 要 公開。
迪 米 特 法則 其 根本思想, 是 強(qiáng) 調(diào)了 類 之 間的 松耦合。
第 12 章 牛市股票還會(huì)虧錢?—— 外觀模式
12.1 牛市股票還會(huì)虧錢? > 位置 1890 外觀模式, 又叫門面模式。
12.4 外觀模式 > 位置 1909 外觀模式(Facade),為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,此模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。[DP]
外觀 模式( Facade) 結(jié)構(gòu)圖 :
對(duì)于 面向 對(duì)象 有 一定 基礎(chǔ) 的 朋友, 即使 沒有 聽說 過 外觀 模式, 也 完全 有可 能在 很多 時(shí)候 使用 它, 因?yàn)?它 完美 地 體現(xiàn) 了 依賴倒轉(zhuǎn) 原則 和 迪米特法則 的 思想, 所以 是非 常常 用的 模式 之一。
12.5 何時(shí)使用外觀模式 > 位置 1921 那 外觀 模式 在什么時(shí)候使用 最好 呢? 這要 分 三個(gè) 階段 來(lái)說, 首先, 在 設(shè)計(jì)初期階段, 應(yīng)該 要有 意識(shí) 的 將 不同 的 兩個(gè) 層 分離, 比如 經(jīng)典 的 三層 架構(gòu), 就 需要 考慮 在 數(shù)據(jù) 訪問 層 和 業(yè)務(wù) 邏輯 層、 業(yè)務(wù) 邏輯 層 和 表示 層 的 層 與 層 之間 建立 外觀 Facade, 這樣 可以 為 復(fù)雜 的 子系統(tǒng) 提供 一個(gè) 簡(jiǎn)單 的 接口, 使得 耦合 大大 降低。 其次, 在開發(fā)階段, 子系統(tǒng) 往往 因?yàn)?不斷 的 重 構(gòu) 演化 而 變得 越來(lái)越 復(fù)雜, 大多數(shù) 的 模式 使用 時(shí) 也都 會(huì) 產(chǎn)生 很多 很 小的 類, 這本 是 好事, 但也 給 外部 調(diào)用 它們 的 用戶 程序 帶來(lái) 了 使 用上 的 困難, 增加 外觀 Facade 可以 提供 一個(gè) 簡(jiǎn)單 的 接口, 減少 它們 之間 的 依賴。 第三, 在 維護(hù) 一個(gè) 遺留 的 大型 系統(tǒng) 時(shí), 可能 這個(gè) 系統(tǒng) 已經(jīng) 非常 難以 維護(hù) 和 擴(kuò)展 了, 但 因?yàn)?它 包含 非常重 要的 功能, 新的 需求 開發(fā) 必須 要 依賴于 它。 此時(shí) 用 外觀 模式 Facade 也是 非常 合適 的。 你 可 以為 新 系統(tǒng) 開發(fā) 一個(gè) 外觀 Facade 類, 來(lái) 提供 設(shè)計(jì) 粗糙 或 高度 復(fù)雜 的 遺留 代碼 的 比較 清晰 簡(jiǎn)單 的 接口, 讓 新 系統(tǒng) 與 Facade 對(duì)象 交互, Facade 與 遺留 代碼 交互 所有 復(fù)雜 的 工作。[R2P]
第 13 章 好菜每回味不同 —— 建造者模式
13.4 建造者模式 > 位置 2003 建造者(Builder)模式, 又叫 生成器模式,將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。[DP]
13.4 建造者模式 > 位置 2029 建造者 模式 中 一個(gè) 很重 要的 類, 指揮者( Director), 用 它來(lái) 控制 建造 過程, 也 用 它來(lái) 隔離 用戶 與 建造 過程 的 關(guān)聯(lián)。
13.5 建造者模式解析 > 位置 2045 建造者 模式( Builder) 結(jié)構(gòu)圖 :
建造者模式 主要 是 用于 創(chuàng)建 一些 復(fù)雜 的 對(duì)象, 這些 對(duì)象 內(nèi)部 構(gòu)建 間的 建造 順序 通常 是 穩(wěn)定 的, 但對(duì) 象 內(nèi)部 的 構(gòu)建 通常 面臨 著 復(fù)雜 的 變化。
第 14 章 老板回來(lái),我不知道 —— 觀察者模式
14.5 觀察者模式 > 位置 2167 觀察者模式 又叫 做 發(fā)布 – 訂閱(Publish/ Subscribe)模式。
觀察者 模式( Observer) 結(jié)構(gòu)圖 :
Subject 類, 可翻譯 為 主題 或 抽象 通知者, 一般用 一個(gè) 抽象 類 或者 一個(gè) 接口 實(shí)現(xiàn)。 它 把 所有 對(duì) 觀察者 對(duì)象 的 引用 保存 在 一個(gè) 聚集 里, 每個(gè) 主題 都可以 有 任何 數(shù)量 的 觀察者。 抽象 主題 提供 一個(gè) 接口, 可以 增加 和 刪除 觀察者 對(duì)象。
14.5 觀察者模式 > 位置 2178
Observer 類, 抽象 觀察者, 為所 有的 具體 觀察者 定義 一個(gè) 接口, 在 得到 主題 的 通知 時(shí) 更新 自己。 這個(gè) 接口 叫做 更新 接口。 抽象 觀察者 一般用 一個(gè) 抽象 類 或者 一個(gè) 接口 實(shí)現(xiàn)。 更新 接口 通常 包含 一個(gè) Update () 方法, 這個(gè) 方法 叫做 更新 方法。
14.6 觀察者模式特點(diǎn) > 位置 2210
當(dāng) 一個(gè) 對(duì)象 的 改變 需要 同時(shí) 改變 其他 對(duì)象 , 而且 它不 知道 具體 有多 少 對(duì)象 有待 改變 時(shí), 應(yīng)該 考慮 使用 觀察者 模式。
觀察者 模式 所做 的 工作 其實(shí) 就是 在 解除耦合。 讓 耦合 的 雙方 都 依賴于抽象, 而 不是 依賴于 具體。 從而 使得 各自 的 變化 都不 會(huì) 影響 另 一邊 的 變化。 這 實(shí)在 是 依賴倒轉(zhuǎn) 原則 的 最佳 體現(xiàn) 呀。
現(xiàn)實(shí) 編程 中, 具體 的 觀察者 完全 有可能 是 風(fēng)馬牛 不相 及 的 類, 但 它們 都 需要 根據(jù) 通知者 的 通知 來(lái) 做出 Update() 的 操作, 所以 讓 它們 都 實(shí)現(xiàn) 下面 這樣 的 一個(gè) 接口 就可以 實(shí)現(xiàn) 這個(gè) 想法 了。 interface Observer { void Update(); }
14.9 事件委托說明 > 位置 2258
委托 就是 一種 引用 方法 的 類型。 一旦 為 委托 分配 了 方法, 委托 將 與 該 方法 具有 完全 相同 的 行為。 委托 方法 的 使用 可以 像 其他 任何 方法 一樣, 具有 參數(shù) 和 返回 值。 委托 可以 看作 是對(duì) 函數(shù) 的 抽象, 是 函數(shù) 的’ 類’, 委托 的 實(shí)例 將 代表 一個(gè) 具體 的 函數(shù)。
delegate void EventHandler (); 可以 理解 為 聲明 了 一個(gè) 特殊 的’ 類’。 而’ public event EventHandler Update;’ 可以 理解 為 聲明 了 一個(gè)’ 類’ 的 變量。具體地說, 應(yīng)該 是 聲明 了 一個(gè) 事件 委托 變量 叫’ 更新’。
一個(gè) 委托 可以 搭載 多個(gè) 方法, 所有 方法 被 依次 喚起。 更重 要的 是, 它可 以使 得 委托 對(duì)象 所 搭載 的 方法 并不 需要 屬于 同一個(gè) 類。
第 15 章 就不能不換 DB 嗎?—— 抽象工廠模式
15.2 最基本的數(shù)據(jù)訪問程序 > 位置 2334
工廠方法模式 是 定義 一個(gè) 用于 創(chuàng)建 對(duì)象 的 接口, 讓 子類 決定 實(shí)例 化 哪一個(gè) 類。
15.4 用了抽象工廠模式的數(shù)據(jù)訪問程序 > 位置 2395
涉及 到 多個(gè)產(chǎn)品系列 的 問題, 有一個(gè) 專門 的 工廠 模式 叫 抽象工廠模式。
15.5 抽象工廠模式 > 位置 2398 抽象工廠模式(Abstract Factory),提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無(wú)需指定它們具體的類。[DP] 抽象 工廠 模式( Abstract Factory) 結(jié)構(gòu)圖 :
15.8 用反射 + 抽象工廠的數(shù)據(jù)訪問程序 > 位置 2446 本來(lái) 依賴注入 是 需要 專門 的 IoC 容器 提供, 比如 Spring. NET, 顯然 當(dāng)前 這個(gè) 程序 不需要 這么 麻煩, 你 只 需要 再 了解 一個(gè) 簡(jiǎn)單 的. NET 技術(shù)’ 反射’ 就可以 了。
反射技術(shù) 格式 : Assembly.Load (“程序集名稱”).Createlnstance (“命名空間。類名稱”);
15.9 用反射 + 配置文件實(shí)現(xiàn)數(shù)據(jù)訪問程序 > 位置 2486 所有 在用 簡(jiǎn)單 工廠 的 地方, 都可以 考慮 用反射 技術(shù) 來(lái) 去除 switch 或 if, 解除分支判斷 帶來(lái) 的 耦合。
第 16 章 無(wú)盡加班何時(shí)休 —— 狀態(tài)模式
16.5 狀態(tài)模式 > 位置 2577 狀態(tài)模式 主要 解決 的 是 當(dāng) 控制 一個(gè) 對(duì)象 狀態(tài) 轉(zhuǎn)換 的 條件 表達(dá)式 過于 復(fù)雜 時(shí) 的 情況。 把 狀態(tài) 的 判斷 邏輯 轉(zhuǎn)移 到 表示 不同 狀態(tài) 的 一系列 類 當(dāng)中, 可以 把 復(fù)雜 的 判斷 邏輯 簡(jiǎn)化。
狀態(tài) 模式( State) 結(jié)構(gòu)圖 :
16.6 狀態(tài)模式好處與用處 > 位置 2588
狀態(tài) 模式 的 好處 是將 與 特定 狀態(tài) 相關(guān) 的 行為 局部化, 并且 將不 同 狀態(tài) 的 行為 分割 開來(lái) [DP]。 是不是 就是 將 特定 的 狀態(tài) 相關(guān) 的 行為 都 放入 一個(gè) 對(duì)象 中, 由于 所有 與 狀態(tài) 相關(guān) 的 代碼 都存 在于 某個(gè) ConcreteState 中, 所以 通過 定義 新的 子類 可以 很容易 地 增加 新的 狀態(tài) 和 轉(zhuǎn)換 [DP]。 說白 了, 這樣做 的 目的 就是 為了 消除 龐大 的 條件 分支 語(yǔ)句。
當(dāng) 一個(gè) 對(duì)象 的 行為 取決于 它的 狀態(tài), 并且 它 必須 在 運(yùn)行 時(shí)刻 根據(jù) 狀態(tài) 改變 它的 行為 時(shí), 就可以 考慮 使用 狀態(tài) 模式 了。 另外 如果 業(yè)務(wù) 需求 某項(xiàng) 業(yè)務(wù) 有多 個(gè) 狀態(tài), 通常 都是 一些 枚舉 常量, 狀態(tài) 的 變化 都是 依靠 大量 的 多分 支 判斷 語(yǔ)句 來(lái) 實(shí)現(xiàn), 此時(shí) 應(yīng)該 考慮 將 每一種 業(yè)務(wù) 狀態(tài) 定義 為 一個(gè) State 的 子類。
第 17 章 在 NBA 我需要翻譯 —— 適配器模式
17.2 適配器模式 > 位置 2651
適配器模式(Adapter),將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。[DP]
系統(tǒng) 的 數(shù)據(jù) 和 行為 都 正確, 但 接口 不符 時(shí), 我們 應(yīng)該 考慮 用 適配器, 目的 是 使 控制 范圍 之外 的 一個(gè) 原有 對(duì)象 與 某個(gè) 接口 匹配。 適配器 模式 主要 應(yīng)用于 希望 復(fù) 用 一些 現(xiàn)存 的 類, 但是 接口 又與 復(fù) 用 環(huán)境 要求 不一致 的 情況, 比如 在 需要 對(duì) 早期 代碼 復(fù) 用 一些 功能 等 應(yīng)用 上 很有 實(shí)際 價(jià)值。
適配器 模式( Adapter) 結(jié)構(gòu)圖 :
17.3 何時(shí)使用適配器模式 > 位置 2687
通常 是在 軟件 開發(fā) 后期 或 維護(hù) 期 再考慮 使用 那有 沒有 設(shè)計(jì) 之初 就 需要 考慮 用 適配器 模式 的 時(shí)候? 當(dāng)然 有, 比如 公司 設(shè)計(jì) 一 系統(tǒng) 時(shí) 考慮 使用 第三方 開發(fā) 組件, 而這 個(gè) 組件 的 接口 與我 們 自己的 系統(tǒng) 接口 是 不 相同 的, 而 我們 也 完全 沒有 必要 為了 迎合 它 而 改動(dòng) 自己的 接口, 此時(shí) 盡管 是在 開發(fā) 的 設(shè)計(jì) 階段, 也是 可以 考慮 用 適配器 模式 來(lái) 解決 接口 不同 的 問題。
第 18 章 如果再回到從前 —— 備忘錄模式
18.3 備忘錄模式 > 位置 2771
備忘錄(Memento):在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣以后就可將該對(duì)象恢復(fù)到原先保存的狀態(tài)。[DP]
備忘錄 模式( Memento) 結(jié)構(gòu)圖 :
18.4 備忘錄模式基本代碼 > 位置 2787
是把 要 保存 的 細(xì)節(jié) 給 封 裝在 了 Memento 中了, 哪 一天 要 更改 保存 的 細(xì)節(jié) 也不 用 影響 客戶 端 了。
Memento 模式 比較 適用于 功能 比較 復(fù)雜 的, 但 需要 維護(hù) 或 記錄 屬性 歷史 的 類, 或者 需要 保存 的 屬性 只是 眾多 屬性 中的 一 小部分 時(shí), 如果 在某 個(gè) 系統(tǒng) 中 使用 命令 模式 時(shí), 需要 實(shí)現(xiàn) 命令 的 撤銷 功能, 那么 命令 模式 可以 使用 備忘錄 模式 來(lái) 存儲(chǔ) 可撤銷 操作 的 狀態(tài) [DP]。
有時(shí) 一些 對(duì)象 的 內(nèi)部 信息 必須 保存 在 對(duì)象 以外 的 地方, 但是 必須 要由 對(duì)象 自己 讀取, 這時(shí), 使用 備忘錄 可以 把 復(fù)雜 的 對(duì)象 內(nèi)部 信息 對(duì)其 他的 對(duì)象 屏蔽 起來(lái) [DP], 從而 可以 恰當(dāng) 地保 持 封裝 的 邊界。
第 19 章 分公司 = 一部門 —— 組合模式
19.2 組合模式 > 位置 2844 組合模式(Composite),將對(duì)象組合成樹形結(jié)構(gòu)以表示’部分 – 整體’的層次結(jié)構(gòu)。組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。[DP] 組合 模式( Composite) 結(jié)構(gòu)圖:
19.4 何時(shí)使用組合模式 > 位置 2866 當(dāng)你 發(fā)現(xiàn) 需求 中 是 體現(xiàn) 部分 與 整體 層次 的 結(jié)構(gòu) 時(shí), 以及 你 希望 用戶 可以 忽略 組合 對(duì)象 與 單個(gè) 對(duì)象 的 不同, 統(tǒng)一 地 使用 組合 結(jié)構(gòu) 中的 所有 對(duì)象 時(shí), 就應(yīng) 該 考慮 用 組合 模式 了。
19.6 組合模式好處 > 位置 2923 組合 模式 讓 客戶 可以 一致 地 使用 組合 結(jié)構(gòu) 和 單個(gè) 對(duì)象。
第 20 章 想走?可以!先買票 —— 迭代器模式
20.2 迭代器模式 > 位置 2972 迭代器模式(Iterator),提供一種方法順序訪問一個(gè)聚合對(duì)象中各個(gè)元素,而又不暴露該對(duì)象的內(nèi)部表示。[DP]
當(dāng)你 需要 訪問 一個(gè) 聚集 對(duì)象, 而且 不管 這些 對(duì)象 是什么 都 需要 遍歷 的 時(shí)候, 你就 應(yīng)該 考慮 用 迭代 器 模式。 你 需要 對(duì) 聚集 有多 種 方式 遍歷 時(shí), 可以 考慮 用 迭代 器 模式。
迭代 器 模式 為 遍歷 不同 的 聚集 結(jié)構(gòu) 提供 如 開始、 下一個(gè)、 是否 結(jié)束、 當(dāng)前 哪 一項(xiàng) 等 統(tǒng)一 的 接口。
不過 現(xiàn)今 來(lái)看 迭代 器 模式 實(shí)用 價(jià)值 遠(yuǎn) 不如 學(xué)習(xí) 價(jià)值 大 了, MartinFlower 甚至 在 自己的 網(wǎng) 站上 提出 撤銷 此 模式。 因?yàn)?現(xiàn)在 高級(jí) 編程 語(yǔ)言 如 C#、 JAVA 等 本身 已經(jīng) 把這 個(gè) 模式 做 在 語(yǔ)言 中了。
哈, foreach in ,另外 還有 像 IEnumerable 接口 也是 為 迭代 器 模式 而 準(zhǔn)備 的。
20.3 迭代器實(shí)現(xiàn) > 位置 2987 迭代 器 模式( Iterator) 結(jié)構(gòu)圖:
20.4 .NET 的迭代器實(shí)現(xiàn) > 位置 3009 IEumerator 支持 對(duì) 非 泛 型 集合 的 簡(jiǎn)單 迭代 接口。
IEnumerable 公開 枚舉 數(shù), 該 枚舉 數(shù) 支持 在 非 泛 型 集合 上進(jìn) 行 簡(jiǎn)單 迭代。
你會(huì) 發(fā)現(xiàn), 這 兩個(gè) 接口, 特別是 IEumerator 要比 我們 剛才 寫的 抽象 類 Iterator 要 簡(jiǎn)潔, 但可 實(shí)現(xiàn) 的 功能 卻 一點(diǎn) 不少, 這 其實(shí) 也 是對(duì) GoF 的 設(shè)計(jì) 改良 的 結(jié)果。
foreach in 就是 實(shí)現(xiàn) 這 兩個(gè) 接口 來(lái) 實(shí)際 循環(huán) 遍歷: IEnumerator<string> e = a.GetEnumerator(); while(e.MoveNext()) { Console.WriteLine(“{0} 請(qǐng)買車票 !”, e.Current); }
迭代 器( Iterator) 模式 就是 分離 了 集合 對(duì)象 的 遍歷 行為, 抽象 出 一個(gè) 迭代 器 類 來(lái) 負(fù)責(zé), 這樣 既可以 做到 不 暴露 集合 的 內(nèi)部 結(jié)構(gòu), 又可 讓 外部 代碼 透明 地 訪問 集合 內(nèi)部 的 數(shù)據(jù)。
第 21 章 有些類也需計(jì)劃生育 —— 單例模式 21.4 單例模式 > 位置 3103 單例模式(Singleton),保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。[DP] 單 例 模式( Singleton) 結(jié)構(gòu)圖 :
21.4 單例模式 > 位置 3109 “我怎 么 感覺 單 例 有點(diǎn) 像 一個(gè) 實(shí)用類 的 靜態(tài) 方法, 比如. Net 框架 里 的 Math 類, 有很 多數(shù) 學(xué) 計(jì)算 方法, 這 兩者 有 什么 區(qū)別 呢?” “你說 得 沒錯(cuò), 它們 之 間的 確 很 類似, 實(shí)用 類 通常 也會(huì) 采用 私有化 的 構(gòu)造 方法 來(lái) 避免 其 有 實(shí)例。 但它 們 還是 有很 多 不同 的, 比如 實(shí)用 類 不保 存 狀態(tài), 僅 提供 一些 靜態(tài) 方法 或 靜態(tài) 屬性 讓你 使用, 而 單例類 是有 狀態(tài) 的。 實(shí)用 類 不能 用于 繼承 多 態(tài), 而 單 例 雖然 實(shí)例 唯一, 卻是 可以 有 子類 來(lái) 繼承。 實(shí)用 類 只不過是 一些 方法 屬性 的 集合, 而 單 例 卻是 有著 唯一 的 對(duì)象 實(shí)例。 在 運(yùn)用 中 還得 仔細(xì) 分析 再作 決定 用 哪一種 方式。”
21.5 多線程時(shí)的單例 > 位置 3115 多 線程 的 程序 中, 多個(gè) 線程 同時(shí), 注意 是 同時(shí) 訪問 Singleton 類, 調(diào)用 GetInstance() 方法, 會(huì)有 可能 造成 創(chuàng)建 多個(gè) 實(shí)例 的。 可以 給 進(jìn)程 一把 鎖 來(lái) 處理。 這里 需要 解釋 一下 lock 語(yǔ)句 的 涵義, lock 是 確保 當(dāng) 一個(gè) 線程 位于 代碼 的 臨界 區(qū)時(shí), 另一個(gè) 線程 不進(jìn) 入 臨界 區(qū)。 如果 其他 線程 試圖 進(jìn)入 鎖定 的 代碼, 則 它將 一直 等待( 即被 阻止), 直到 該 對(duì)象 被 釋放。
21.6 雙重鎖定 > 位置 3126 不用 讓 線程 每次 都 加鎖, 而 只是 在 實(shí)例 未被 創(chuàng)建 的 時(shí)候 再加 鎖 處理。 同時(shí) 也能 保證 多 線程 的 安全。 這種 做法 被稱為 Double- Check Locking( 雙重 鎖定)。
21.7 靜態(tài)初始化 > 位置 3136 其實(shí) 在 實(shí)際 應(yīng)用 當(dāng)中, C# 與 公共 語(yǔ)言 運(yùn)行 庫(kù) 也 提供 了 一種’ 靜態(tài)初始化' 方法, 這種 方法 不需要 開發(fā) 人員 顯 式 地 編寫 線程 安全 代碼, 即可 解決 多 線程 環(huán)境 下 它是 不安全 的 問題。[MSDN] 談不上 更好, 只不過 實(shí)現(xiàn) 更簡(jiǎn)單。 我們 來(lái)看 代碼。 由于 這種 靜態(tài) 初始化 的 方式 是在 自己 被 加載 時(shí) 就 將 自己 實(shí)例 化, 所以 被 形象 地 稱之為 餓漢式單例類, 原先 的 單 例 模式 處理 方式 是 要在 第一次 被 引用 時(shí), 才會(huì) 將 自己 實(shí)例 化, 所以 就被 稱為 懶漢式單例類。[ J& DP] 由于 餓漢 式, 即 靜態(tài) 初始化 的 方式, 它是 類 一 加載 就 實(shí)例 化 的 對(duì)象, 所以 要 提前 占用 系統(tǒng) 資源。 然而 懶漢 式, 又會(huì) 面臨 著 多 線程 訪問 的 安全性 問題, 需要 做 雙重 鎖定 這樣 的 處理 才可 以 保證 安全。 所以 到底 使用 哪一種 方式, 取決于 實(shí)際 的 需求。 從 C# 語(yǔ)言 角度 來(lái)講, 餓漢 式 的 單 例 類 已經(jīng) 足夠 滿足 我們 的 需求 了。
第 22 章 手機(jī)軟件何時(shí)統(tǒng)一 —— 橋接模式 22.2 緊耦合的程序演化 > 位置 3237 在 面向 對(duì)象 設(shè)計(jì) 中, 我們 還有 一個(gè) 很重 要的 設(shè)計(jì) 原則, 那就 是 合成 / 聚合復(fù)用原則。 即 優(yōu)先 使用 對(duì)象 合成 / 聚合, 而 不是 類 繼承 [DP]。
22.3 合成 / 聚合復(fù)用原則 > 位置 3239 合成( Composition, 也有 翻譯 成 組合) 和 聚合( Aggregation) 都是 關(guān)聯(lián) 的 特殊 種類。 聚合 表示 一種 弱 的’ 擁有’ 關(guān)系, 體現(xiàn) 的 是 A 對(duì)象 可以 包含 B 對(duì)象, 但 B 對(duì)象 不是 A 對(duì)象 的 一部分; 合成 則是 一種 強(qiáng)的’ 擁有’ 關(guān)系, 體現(xiàn) 了 嚴(yán)格 的 部分 和 整體 的 關(guān)系, 部分 和 整體 的 生命 周期 一樣 [DPE]。 合成 / 聚合 復(fù) 用 原則 的 好處 是, 優(yōu)先 使用 對(duì)象 的 合成 / 聚合 將有 助于 你 保持 每個(gè) 類 被 封裝, 并被 集中 在 單個(gè) 任務(wù) 上。 這樣 類 和 類 繼承 層次 會(huì) 保持 較小 規(guī)模, 并且 不太 可能 增長(zhǎng) 為 不可 控制 的 龐然大物 [DP]。 手機(jī) 品牌 包含 有手 機(jī) 軟件, 但 軟件 并不是 品牌 的 一部分, 所以 它們 之間 是 聚合 關(guān)系。 結(jié)構(gòu)圖(下一節(jié)用到):
22.4 松耦合的程序 > 位置 3289 兩個(gè) 抽象 類 之間 有 什么, 像 什么? 有一個(gè) 聚合 線, 哈, 像 一座 橋?!?“好, 說得 好, 這個(gè) 設(shè)計(jì) 模式 就 叫做’ 橋 接 模式’。 抽象與它的實(shí)現(xiàn)分離, 這 并不 是說, 讓 抽象 類 與其 派生 類 分離, 因?yàn)?這 沒有 任何 意義。 實(shí)現(xiàn) 指的 是 抽象 類 和 它的 派生 類 用來(lái) 實(shí)現(xiàn) 自己的 對(duì)象 [DPE]。 就 剛才 的 例子 而言, 就是 讓’ 手機(jī)’ 既可以 按照 品牌 來(lái) 分類, 也可以 按照 功能 來(lái) 分類?!?nbsp;
22.5 橋接模式 > 位置 3296 由于 實(shí)現(xiàn) 的 方式 有 多種, 橋 接 模式 的 核心 意圖 就是 把這 些 實(shí)現(xiàn)獨(dú)立出來(lái), 讓 它們 各自 地 變化。 這就 使得 每種 實(shí)現(xiàn) 的 變化 不會(huì) 影響 其他 實(shí)現(xiàn), 從而 達(dá)到 應(yīng)對(duì) 變化 的 目的。
22.6 橋接模式基本代碼 > 位置 3299 橋 接 模式( Bridge) 結(jié)構(gòu)圖 :
22.6 橋接模式基本代碼 > 位置 3320 在 發(fā)現(xiàn) 我們 需要 多角度去分類實(shí)現(xiàn)對(duì)象, 而 只用 繼承 會(huì) 造成 大量 的 類 增加, 不能 滿足 開放 – 封閉 原則 時(shí), 就 應(yīng)該 要 考慮 用 橋 接 模式 了。
第 23 章 烤羊肉串引來(lái)的思考 —— 命令模式 23.6 命令模式 > 位置 3416 命令模式(Command),將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可撤銷的操作。[DP] 命令 模式( Command) 結(jié)構(gòu)圖 :
23.7 命令模式作用 > 位置 3435 命令 模式 的 優(yōu)點(diǎn): 第一, 它 能 較 容易 地 設(shè)計(jì) 一個(gè) 命令 隊(duì)列; 第二, 在 需要 的 情況下, 可以 較 容 易地 將 命令 記入 日志; 第三, 允許 接收 請(qǐng)求 的 一方 決定 是否 要 否決 請(qǐng)求。 第四, 可以 容易 地 實(shí)現(xiàn) 對(duì) 請(qǐng)求 的 撤銷 和 重做; 第五, 由于 加進(jìn) 新的 具體 命令 類 不 影響 其 他的 類, 因此 增加 新的 具體 命令 類 很容易。 其實(shí) 還有 最 關(guān)鍵 的 優(yōu)點(diǎn) 就是 命令 模式 把 請(qǐng)求 一個(gè) 操作 的 對(duì)象 與 知道 怎么 執(zhí)行 一個(gè) 操作 的 對(duì)象 分割 開。 敏捷開發(fā)原則 告訴 我們, 不要 為 代碼 添加 基于 猜測(cè) 的、 實(shí)際 不需 要的 功能。 如果不 清楚 一個(gè) 系統(tǒng) 是否 需要 命令 模式, 一般 就不 要 著急 去 實(shí)現(xiàn) 它, 事實(shí)上, 在 需要 的 時(shí)候 通 過重構(gòu) 實(shí)現(xiàn) 這個(gè) 模式 并不 困難, 只有 在 真正 需要 如 撤銷 / 恢復(fù) 操作 等 功能 時(shí), 把 原來(lái) 的 代碼 重 構(gòu) 為 命令 模式 才有 意義。[R2P]
第 24 章 加薪非要老總批?—— 職責(zé)鏈模式 24.3 職責(zé)鏈模式 > 位置 3500 職責(zé)鏈模式(Chain of Responsibility):使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系。將這個(gè)對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理它為止。[DP] 這里 發(fā)出 這個(gè) 請(qǐng)求 的 客戶 端 并不 知道 這 當(dāng)中 的 哪一個(gè) 對(duì)象 最終 處理 這個(gè) 請(qǐng)求, 這樣 系統(tǒng) 的 更改 可 以在 不 影響 客戶 端 的 情況下 動(dòng)態(tài) 地 重新 組織 和 分配 責(zé)任。 職責(zé) 鏈 模式( Chain of Responsibility) 結(jié)構(gòu)圖 :
24.4 職責(zé)鏈的好處 > 位置 3515 接收者 和 發(fā)送者 都沒 有 對(duì)方 的 明確 信息, 且 鏈 中的 對(duì)象 自己 也 并不 知道 鏈 的 結(jié)構(gòu)。 結(jié)果是 職責(zé) 鏈 可簡(jiǎn)化 對(duì)象 的 相互 連接, 它們 僅 需 保持 一個(gè) 指向 其 后繼者 的 引用, 而 不需 保持 它 所有 的 候選 接受者 的 引用 [DP]。 這也 就 大大 降低 了 耦 合度 了。
第 25 章 世界需要和平 —— 中介者模式 25.1 世界需要和平! > 位置 3552 中介者模式 又 叫做 調(diào)停者模式。 盡管 將 一個(gè) 系統(tǒng) 分割 成 許多 對(duì)象 通常 可以 增加 其 可 復(fù) 用性, 但是 對(duì)象 間 相互 連接 的 激增 又會(huì) 降低 其 可 復(fù) 用性 了。 是因?yàn)?大量 的 連接 使得 一個(gè) 對(duì)象 不可 能在 沒有 其他 對(duì)象 的 支持下 工作, 系統(tǒng) 表現(xiàn) 為 一個(gè) 不可分割 的 整體, 所以, 對(duì) 系統(tǒng) 的 行為 進(jìn)行 任何 較大 的 改動(dòng) 就 十分困難 了。
25.1 世界需要和平! > 位置 3574 通過 中介 者 對(duì)象, 可以 將 系統(tǒng) 的 網(wǎng)狀 結(jié)構(gòu) 變成 以 中介 者 為 中心 的 星形結(jié)構(gòu), 使得 系統(tǒng) 的 結(jié)構(gòu) 不會(huì) 因?yàn)?新 對(duì)象 的 引入 造成 大量 的 修改 工作。
25.2 中介者模式 > 位置 3582 中介者模式(Mediator),用一個(gè)中介對(duì)象來(lái)封裝一系列的對(duì)象交互。中介者使各對(duì)象不需要顯式地相互引用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。[DP] 中介 者 模式( Mediator) 結(jié)構(gòu)圖 :
25.4 中介者模式優(yōu)缺點(diǎn) > 位置 3634 中介 者 模式 很容易 在 系統(tǒng) 中 應(yīng)用, 也 很容易 在 系統(tǒng) 中 誤用。 當(dāng) 系統(tǒng) 出現(xiàn) 了’ 多對(duì) 多’ 交互 復(fù)雜 的 對(duì)象 群 時(shí), 不要 急于 使用 中介 者 模式, 而要 先 反思 你的 系統(tǒng) 在 設(shè)計(jì) 上 是不是 合理。 中介 者 模式 的 優(yōu)點(diǎn) 來(lái)自 集中控制, 其 缺點(diǎn) 也 是它, 使用 時(shí) 是要 考慮 清楚 。
25.4 中介者模式優(yōu)缺點(diǎn) > 位置 3658 中介 者 模式 一般應(yīng)用于 一組 對(duì)象 以 定義 良好 但是 復(fù)雜 的 方式 進(jìn)行 通信 的 場(chǎng)合, 以及 想定 制 一個(gè) 分布 在 多個(gè) 類 中的 行為, 而又 不想 生成 太多 的 子類 的 場(chǎng)合。
第 26 章 項(xiàng)目多也別傻做 —— 享元模式 26.2 享元模式 > 位置 3703 享元模式(Flyweight),運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。[DP]
26.4 內(nèi)部狀態(tài)與外部狀態(tài) > 位置 3742 在 享 元 對(duì)象 內(nèi)部 并且 不會(huì) 隨 環(huán)境 改變 而 改變 的 共享 部分, 可以 稱 為是 享 元 對(duì)象 的 內(nèi)部 狀態(tài), 而 隨 環(huán)境 改變 而 改變 的、 不可以 共享 的 狀態(tài) 就是 外部 狀態(tài) 了。 事實(shí)上, 享 元 模式 可以避免 大量 非常 相似 類 的 開銷。 在 程序設(shè)計(jì) 中, 有時(shí) 需要 生成 大量 細(xì) 粒度 的 類 實(shí)例 來(lái) 表示 數(shù)據(jù)。 如果 能 發(fā)現(xiàn) 這些 實(shí)例 除了 幾個(gè) 參數(shù) 外 基本上 都是 相同 的, 有時(shí) 就能 夠受 大幅度 地 減少 需要 實(shí)例 化 的 類 的 數(shù)量。 如果 能把 那些 參數(shù) 移到 類 實(shí)例 的 外面, 在 方法 調(diào)用 時(shí) 將它 們 傳遞 進(jìn)來(lái), 就可以 通過 共享 大幅度 地 減少 單個(gè) 實(shí)例 的 數(shù)目。
26.5 享元模式應(yīng)用 > 位置 3780 如果 一個(gè) 應(yīng)用 程序 使用 了 大量的對(duì)象, 而 大量 的 這些 對(duì)象 造成了 很大 的 存儲(chǔ) 開銷 時(shí) 就應(yīng) 該 考慮 使用; 還有 就是 對(duì)象 的 大多數(shù) 狀態(tài) 可以 外部 狀態(tài), 如果 刪除 對(duì)象 的 外部 狀態(tài), 那么 可以 用 相對(duì) 較少 的 共享 對(duì)象 取代 很多 組 對(duì)象, 此時(shí) 可以 考慮 使用 享 元 模式。
26.5 享元模式應(yīng)用 > 位置 3802 使用 享 元 模式 需要 維護(hù) 一個(gè) 記錄 了 系統(tǒng) 已有 的 所有 享 元 的 列表, 而這 本身 需要 耗費(fèi) 資源, 另外 享 元 模式 使得 系統(tǒng) 更加 復(fù)雜。 為了 使對(duì) 象 可以 共享, 需要 將 一些 狀態(tài) 外部 化, 這使 得 程序 的 邏輯 復(fù)雜化。 因此, 應(yīng)當(dāng) 在 有 足夠多的對(duì)象 實(shí)例 可供 共享 時(shí) 才 值得 使用 享 元 模式。
第 27 章 其實(shí)你不懂老板的心 —— 解釋器模式 27.2 解釋器模式 > 位置 3834 解釋器模式(interpreter),給定一個(gè)語(yǔ)言,定義它的文法的一種表示,并定義一個(gè)解釋器,這個(gè)解釋器使用該表示來(lái)解釋語(yǔ)言中的句子。[DP] 解釋器 模式 需要 解決 的 是, 如果 一種 特定 類型 的 問題 發(fā)生 的 頻率 足夠 高, 那么 可能 就 值得 將 該 問題 的 各個(gè) 實(shí)例 表述 為 一個(gè) 簡(jiǎn)單 語(yǔ)言 中的 句子。 這樣 就可以 構(gòu)建 一個(gè) 解釋器, 該 解釋器 通過 解釋 這些 句子 來(lái) 解決 該 問題。 所謂 的 解釋器 模式, 正則表達(dá)式 就是 它的 一種 應(yīng)用, 解釋器 為 正 則 表達(dá)式 定義 了 一個(gè) 文法, 如何 表示 一個(gè) 特 定的 正 則 表達(dá)式, 以及 如何 解釋 這個(gè) 正 則 表達(dá)式。 解釋器 模式( interpreter) 結(jié)構(gòu)圖:
27.3 解釋器模式好處 > 位置 3875 當(dāng) 有一個(gè) 語(yǔ)言 需要 解釋執(zhí)行, 并且 你 可將 該 語(yǔ)言 中的 句子 表示 為 一個(gè) 抽象 語(yǔ)法樹 時(shí), 可使用 解釋器 模式。 用了 解釋器 模式, 就 意味著 可以 很容易 地 改變 和 擴(kuò)展 文法, 因?yàn)?該 模式 使用類來(lái)表示文法規(guī)則, 你 可使用 繼承 來(lái) 改變 或 擴(kuò)展 該文 法。 也比 較 容易 實(shí)現(xiàn) 文法, 因?yàn)?定義 抽象 語(yǔ)法樹 中 各個(gè) 節(jié)點(diǎn) 的 類 的 實(shí)現(xiàn) 大體 類似, 這些 類 都 易于 直接 編寫 [DP]。 解釋器 模式 也有 不足 的, 解釋器 模式 為 文法 中的 每一 條規(guī) 則 至少 定義 了 一個(gè) 類, 因此 包含 許多 規(guī)則 的 文法 可能 難以 管理 和 維護(hù)。 建議 當(dāng) 文法 非常 復(fù)雜 時(shí), 使用 其他 的 技術(shù) 如 語(yǔ)法 分析 程序 或 編譯器 生成 器 來(lái) 處理 [DP]
第 28 章 男人和女人 —— 訪問者模式 28.5 訪問者模式 > 位置 4062 訪問者模式(Visitor),表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。[DP] 訪問者 模式( Visitor) 結(jié)構(gòu)圖 : 在這里, Element 就是 我們 的’ 人’ 類, 而 ConcreteElementA 和 ConcreteElementB 就是’ 男人’ 和’ 女人’, Visitor 就是 我們 寫的’ 狀態(tài)’ 類, 具體 的 ConcreteVisitor 就是 那些’ 成功’、’ 失敗’、’ 戀愛’ 等等 狀態(tài)。 至于 ObjectStructure 就是’ 對(duì)象 結(jié)構(gòu)’ 類 了。
28.5 訪問者模式 > 位置 4071 訪問者 模式 適用于 數(shù)據(jù) 結(jié)構(gòu) 相對(duì) 穩(wěn)定 的 系統(tǒng),它 把 數(shù)據(jù) 結(jié)構(gòu) 和 作用于 結(jié)構(gòu)上 的 操作 之間 的 耦合 解脫 開, 使得 操作 集合 可以 相對(duì) 自由 地 演化。 訪問者 模式 的 目的 是要 把 處理 從 數(shù)據(jù) 結(jié)構(gòu) 分離 出來(lái)。 很多 系統(tǒng) 可以 按照 算法 和數(shù) 據(jù) 結(jié)構(gòu) 分開, 如果 這樣 的 系統(tǒng) 有 比較 穩(wěn)定 的 數(shù)據(jù) 結(jié)構(gòu), 又有 易于 變化 的 算法 的 話, 使用 訪問者 模式 就是 比較 合適 的, 因?yàn)?訪問者 模式 使得 算法 操作 的 增加 變得 容易。 反之, 如果 這樣 的 系統(tǒng) 的 數(shù)據(jù) 結(jié)構(gòu) 對(duì)象 易于 變化, 經(jīng)常 要有 新的 數(shù)據(jù) 對(duì)象 增加 進(jìn)來(lái), 就不 適合 使用 訪問者 模式。 訪問者 模式 的 優(yōu)點(diǎn) 就是 增加 新的 操作 很容易, 因?yàn)?增加 新的 操作 就 意味著 增加 一個(gè) 新的 訪問者。 訪問者 模式 將 有關(guān) 的 行為 集中 到 一個(gè) 訪問者 對(duì)象 中。 訪問者 的 缺點(diǎn) 其實(shí) 也就是 使 增加 新的 數(shù)據(jù) 結(jié)構(gòu) 變得 困難 了。 所以 GoF 四人 中的 一個(gè) 作者 就 說過:’ 大多 時(shí)候 你 并不 需要 訪問者 模式, 但當(dāng) 一旦 你 需要 訪問者 模式 時(shí), 那就 是真 的 需要 它 了。’ 事實(shí)上, 我們 很難 找到 數(shù)據(jù) 結(jié)構(gòu) 不變化 的 情況, 所以 用 訪問者 模式 的 機(jī)會(huì) 也就 不太 多了。 這也 就是 為什么 你 談到 男人 女人 對(duì)比 時(shí) 我很 高興 和你 討論 的 原因, 因?yàn)?人類 性別 這樣 的 數(shù)據(jù) 結(jié)構(gòu) 是 不會(huì) 變化 的。
第 29 章 OOTV 杯超級(jí)模式大賽 —— 模式總結(jié) 29.3 超模大賽開幕式 > 位置 4233 根據(jù) 模式 的 特點(diǎn), 設(shè)置 了 三個(gè) 類別, 分別 是 創(chuàng)建型模式、 結(jié)構(gòu)型模式 和 行為型模式, 但 由于 有 11 位 選擇 了 行為 型 模式, 人數(shù) 過多, 所以 行為 型 模式 又 分 為了 兩 組。 分組 情況:
29.4 創(chuàng)建型模式比賽 > 位置 4247 第一 組 創(chuàng)建 型 選手, 1 號(hào) 選手, 抽象 工廠 小姐, 她的 口號(hào) 是 提供 一個(gè) 創(chuàng)建 一系列 或 相關(guān) 依賴 對(duì)象 的 接口, 而無(wú) 需 指定 它們 具體 的 類。[DP] 1 號(hào) 選手 抽象工廠( Abstract Factory):
2 號(hào) 選手, 建造者 小姐, 她的 口號(hào) 是將 一個(gè) 復(fù)雜 對(duì)象 的 構(gòu)建 與 它的 表示 分離, 使得 同樣 的 構(gòu)建 過程 可以 創(chuàng)建 不同 的 表示。[DP] 2 號(hào) 選手 建造者( Bulider) :
3 號(hào) 選手 工廠 方法 小姐 向我 們 走來(lái), 她 聲稱 定義 一個(gè) 用于 創(chuàng)建 對(duì)象 的 接口, 讓 子類 決定 實(shí)例 化 哪一個(gè) 類, 工廠 模式 使 一個(gè) 類 的 實(shí)例 化 延 遲到 其 子類。[DP] 3 號(hào) 選手 工廠方法( Factory Method):
4 號(hào) 選手 是 原型 小姐, 她的 意圖 是 用 原型 實(shí)例 指定 創(chuàng)建 對(duì)象 的 種類, 并且 通過 拷貝 這些 原型 創(chuàng)建 新的 對(duì)象。[DP] 4 號(hào) 選手 原型( Prototype):
5 號(hào) 選手 出場(chǎng), 單 例 小姐, 她 提倡 簡(jiǎn)捷 就是 美, 保證 一個(gè) 類 僅有 一個(gè) 實(shí)例, 并提 供 一個(gè) 訪問 它的 全局 訪問 點(diǎn)。[DP] 5 號(hào) 選手 單例( Singleton):
29.4 創(chuàng)建型模式比賽 > 位置 4280 創(chuàng)建 型 模式 隱藏 了 這些 類 的 實(shí)例 是 如何 被 創(chuàng)建 和 放在 一起, 整個(gè) 系統(tǒng) 關(guān)于 這些 對(duì)象 所 知道 的 是由 抽象 類 所 定義 的 接口。 這樣, 創(chuàng)建 型 模式 在 創(chuàng)建 了 什么、 誰(shuí) 創(chuàng)建 它、 它是 怎么 被 創(chuàng)建 的, 以及 何時(shí) 創(chuàng)建 這些 方面 提供 了 很大 的 靈活性 [DP]。 內(nèi)聚性 描述 的 是一 個(gè)例 程 內(nèi)部 組成部分 之間 相互 聯(lián)系 的 緊密 程度。 而 耦合 性 描述 的 是一 個(gè)例 程 與其 他 例程 之間 聯(lián)系 的 緊密 程度。 軟件 開發(fā) 的 目標(biāo) 應(yīng)該 是 創(chuàng)建 這樣 的 例程: 內(nèi)部 完整, 也就是 高內(nèi)聚, 而 與其 他 例程 之間 的 聯(lián)系 則是 小巧、 直接、 可見、 靈活 的, 這 就是 松耦合 [ DPE]。
29.4 創(chuàng)建型模式比賽 > 位置 4306 通常 設(shè)計(jì) 應(yīng) 該是 從 工廠 方法 開始, 當(dāng) 設(shè)計(jì)者 發(fā)現(xiàn) 需要 更大 的 靈活性 時(shí), 設(shè)計(jì) 便會(huì) 向 其他 創(chuàng)建 型 模式 演化。 當(dāng) 設(shè)計(jì)者 在 設(shè)計(jì) 標(biāo)準(zhǔn) 之間 進(jìn)行 權(quán)衡 的 時(shí)候, 了解 多個(gè) 創(chuàng)建 型 模式 可以 給 設(shè)計(jì)者 更多 的 選擇 余地。
29.5 結(jié)構(gòu)型模式比賽 > 位置 4341 第二 組, 也就是 結(jié)構(gòu)型 模式 組 6 號(hào) 選手, 適配器 小姐, 她的 口號(hào) 是將 一個(gè) 類 的 接口 轉(zhuǎn)換 成 客戶 希望 的 另外 一個(gè) 接口。 適配器 模式 使得 原本 由于 接口 不兼容 而 不能 一起 工作 的 那些 類 可以 一起 工作。[DP]
7 號(hào) 選手 叫 橋 接。 橋接 小姐 提倡 的 是將 抽象 部分 與 它的 實(shí)現(xiàn) 部分 分離, 使它 們 都可以 獨(dú)立 地 變化。
8 號(hào) 選手 向我 們 走來(lái), 組合 小姐, 一個(gè) 非常 美麗 的 姑娘, 她的 口號(hào) 是將 對(duì)象 組 合成 樹 形 結(jié)構(gòu) 以 表示’ 部分 – 整體’ 的 層次 結(jié)構(gòu), 組合 模式 使得 用戶 對(duì) 單個(gè) 對(duì)象 和 組合 對(duì)象 的 使用 具有 一致性。[DP]
9 號(hào) 選手, 裝飾 小姐, 她的 意圖 非常 簡(jiǎn)單, 就是 動(dòng)態(tài) 地 給 一個(gè) 對(duì)象 添加 一些 額外 的 職責(zé)。 就 增加 功能 來(lái)說, 裝飾 模式 相比 生成 子類 更加 靈活 [DP]。
10 號(hào) 選手 出現(xiàn) 了, 外觀 小姐, 她的 形象 如 她的 名字 一樣 的 棒, 她說 為 子系統(tǒng) 中的 一組 接口 提供 一個(gè) 一致 的 界面, 外觀 模式 定義 了 一個(gè) 高層 接口, 這個(gè) 接口 使得 這一 子系統(tǒng) 更加 容易 使用。[DP]
11 號(hào) 選手 是 享元 小姐, 她的 參賽 宣言 為 運(yùn)用 共享 技術(shù) 有效地 支持 大量 細(xì) 粒度 的 對(duì)象。[DP]
12 號(hào) 選手, 代理 小姐 向我 們 走來(lái), 她 聲稱 為 其他 對(duì)象 提供 一種 代理 以 控制 對(duì)這 個(gè) 對(duì)象 的 訪問。[DP]
29.5 結(jié)構(gòu)型模式比賽 > 位置 4434 “哦, 各位 來(lái)賓, 觀眾 朋友們, 第二 場(chǎng) 結(jié)構(gòu) 型 模式 的 比賽 真是 相當(dāng) 精彩, 各位 選手 也都 實(shí)力 相當(dāng), 難分 伯仲, 現(xiàn)在 出現(xiàn) 了’ 橋接’、’ 適配器’、’ 外觀’ 的 比分 均為 兩分 的 相同 情況。 根據(jù) 比賽規(guī)則, 她們 三位 需要 站上 PK 臺(tái), 進(jìn)行 PK。 三位 有請(qǐng)?!?/p> “下面 請(qǐng) 三位 各自 說 一說 你 比 其他 兩位 優(yōu)秀 的 地方。 適配器 小姐 先來(lái)?!?/p> 適配器 說:” 我 主要 是 為了 解決 兩個(gè) 已有 接口 之間 不匹配 的 問題, 我不 需要 考慮 這些 接口 是 怎樣 實(shí)現(xiàn) 的, 也不 考慮 它們 各自 可能 會(huì) 如何 演化。 我的 這種 方式 不需 要對(duì) 兩個(gè) 獨(dú)立 設(shè)計(jì) 的 類 中 任一 個(gè) 進(jìn)行 重新 設(shè)計(jì), 就 能夠使 它們 協(xié)同 工作。[DP]” “非常好, 下面 有請(qǐng) 橋接 小姐。” “我 覺得 我和 適配器 小姐 具有 一些 共同 的 特征, 就是 給 另一 對(duì)象 提供 一定程度 的 間接 性, 這樣 可以 有利于 系統(tǒng) 的 靈活性。 但 正 所謂 未雨綢繆, 我們 不能 等到 問題 發(fā)生了, 再去 考慮 解決問題, 而是 更應(yīng)該 在 設(shè)計(jì) 之初 就 想好 應(yīng)該 如何 做 來(lái) 避免 問題 的 發(fā)生, 我 通常 是在 設(shè)計(jì) 之初, 就 對(duì) 抽象 接口 與 它的 實(shí)現(xiàn) 部分 進(jìn)行 橋 接, 讓 抽象 與 實(shí)現(xiàn) 兩者 可以 獨(dú)立 演化。 顯然, 我的 優(yōu)勢(shì) 更 明顯。[ DP]” “OK, 說 得很 棒, 外觀 小姐, 您有 什么 觀點(diǎn)?” “首先 我 剛 聽完 兩位 小姐 的 發(fā)言, 我 個(gè)人 覺得 她們 各自 有 各自 的 優(yōu)點(diǎn), 并不 能說 設(shè)計(jì) 之初 就 一定 比 設(shè)計(jì) 之后 的 彌補(bǔ) 要好, 事實(shí)上, 在 現(xiàn)實(shí) 中, 早已 設(shè)計(jì) 好的 兩個(gè) 類, 過后 需要 它們 統(tǒng)一 接口, 整 合為 一 的 事例 也 比比皆是。 因此 橋 接和 適配器 是 被用 于 軟件 生命 周期 的 不同 階段, 針對(duì) 的 是不同 的 問題, 談不上 孰 優(yōu) 孰 劣。 然后, 對(duì)于 我 來(lái)說, 和 適配器 還有 些 近似, 都是 對(duì)現(xiàn) 存 系統(tǒng) 的 封裝, 有 人說 我 其實(shí) 就是 另外 一組 對(duì)象 的 適配器, 這種 說法 是 不準(zhǔn)確 的, 因?yàn)?外觀 定義 的 是一 個(gè) 新的 接口, 而 適配器 則是 復(fù) 用 一個(gè) 原有 的 接口, 適配器 是 使 兩個(gè) 已有 的 接口 協(xié)同 工作, 而外 觀 則是 為 現(xiàn)存 系統(tǒng) 提供 一個(gè) 更為 方便 的 訪問 接口。 如果 硬要 說 我是 適配, 那么 適配器 是 用來(lái) 適配 對(duì)象 的, 而我 則是 用來(lái) 適配 整個(gè) 子系統(tǒng) 的。 也就是說, 我所 針對(duì) 的 對(duì)象 的 粒度 更大。[ DP]”
29.6 行為型模式一組比賽 > 位置 4471 第三 組, 也就是 行為型 模式 一組 13 號(hào) 選手, 觀察者 小姐 入場(chǎng), 它的 口號(hào) 是 定義 對(duì)象 間的 一種 一對(duì) 多的 依賴 關(guān)系, 當(dāng) 一個(gè) 對(duì)象 的 狀態(tài) 發(fā)生 改變 時(shí), 所有 依賴于 它的 對(duì)象 都得 到 通知 并被 自動(dòng) 更新。[DP]
14 號(hào) 選手, 模板方法 小姐, 她 提倡 定義 一個(gè) 操作 的 算法 骨架, 而將 一些 步驟 延遲 到 子類 中, 模板 方法 使得 子類 可以 不改 變 一個(gè) 算法 的 結(jié)構(gòu) 即可 重 定義 該 算法 的 某些 特定 步驟。[DP]
15 號(hào) 選手 是 命令 小姐, 它 覺得 應(yīng)該 將 一個(gè) 請(qǐng)求 封裝 為 一個(gè) 對(duì)象, 從 而使 你 可用 不同 的 請(qǐng)求 對(duì) 客戶 進(jìn)行 參數(shù) 化; 可以 對(duì) 請(qǐng)求 排隊(duì) 或 記錄 請(qǐng)求 日志, 以及 支持 可撤銷 的 操作。[DP]
16 號(hào) 是 狀態(tài) 小姐, 她說 允許 一個(gè) 對(duì)象 在 其內(nèi) 部 狀態(tài) 改變 時(shí) 改變 它的 行為, 讓 對(duì)象 看起來(lái) 似乎 修改 了 它的 類。[DP]
17 號(hào) 選手, 職責(zé)鏈 小姐, 她 一直 認(rèn)為 使 多個(gè) 對(duì)象 都有 機(jī)會(huì) 處理 請(qǐng)求, 從而 避免 請(qǐng)求 的 發(fā)送者 和 接收者 之間 的 耦合 關(guān)系。 將 這些 對(duì)象 連成 一條 鏈, 并 沿著 這條 鏈 傳遞 該 請(qǐng)求, 直到 有一個(gè) 對(duì)象 處理 它 為止。[DP]
29.7 行為型模式二組比賽 > 位置 4563 18 號(hào) 選手, 解釋器 小姐, 它 聲稱 給定 一個(gè) 語(yǔ)言, 定義 它的 文法 的 一種 表示, 并 定義 一個(gè) 解釋器, 這個(gè) 解釋器 使用 該 表示 來(lái) 解釋 語(yǔ)言 中的 句子。[DP]
19 號(hào) 選手 是 中介者 小姐, 她說 她是 用 一個(gè) 中介 對(duì)象 來(lái) 封裝 一系列 的 對(duì)象 交互。 中介 者 使 各 對(duì)像 不需要 顯 式 地 相互 引用, 從而 使其 耦合 松散, 而且 可以 獨(dú)立 地 改變 它們 之間 的 交互。[DP]
20 號(hào) 小姐 向我 們 走來(lái), 訪問者 小姐, 她 表示 一個(gè) 作用于 某 對(duì)象 結(jié)構(gòu) 中的 各 元素 的 操作。 它 使 你 可以 在 不 改變 各 元素 的 類 的 前提 下定義 作用于 這些 元素 的 新 操作。[DP]
21 號(hào) 小姐 是 策略, 一個(gè) 可愛 的 姑娘, 她的 意圖 是 定義 一系列 的 算法, 把 它們 一個(gè) 個(gè) 封裝 起來(lái), 并且 使 它們 可 相互 替換。 本 模式 使得 算法 可 獨(dú)立 于 使用 它的 客戶 而 變化。[DP]
22 號(hào) 選手, 備忘錄 小姐, 她說 在 不破 壞 封裝 性的 前提下, 捕獲 一個(gè) 對(duì)象 的 內(nèi)部 狀態(tài), 并在 該 對(duì)象 之外 保存 這個(gè) 狀態(tài)。 這樣 以后 就 可將 該 對(duì)象 恢復(fù) 到 原先 保存 的 狀態(tài)。[DP]
選手, 23 號(hào), 迭代器 小姐, 她說, 提供 一種 方法 順序 訪問 一個(gè) 聚合 對(duì)象 中 各個(gè) 元素, 而又 不需 暴露 該 對(duì)象 的 內(nèi)部 表示。[DP]
29.8 決賽 > 位置 4647 好的, 現(xiàn)在 我們 比賽 已經(jīng) 進(jìn)入 了 最高潮, 23 位 選手, 經(jīng)過 激烈 的 比拼, 現(xiàn)在 選出 了 五位 選手 將 站在 PK 臺(tái)上, 來(lái) 決定 今天 冠 亞 季軍 的 歸屬。 她們 分別 是…… 工廠 方法 小姐、 外觀 小姐、 觀察者 小姐、 策略 小姐 和 觀眾 朋友 選出 的 可愛 的 適配器 小姐。
29.8 決賽 > 位置 4720 面向 對(duì)象 設(shè)計(jì) 模式 體現(xiàn) 的 就是 抽象 的 思想, 類 是什么, 類 是對(duì) 對(duì)象 的 抽象, 抽象類 呢, 其實(shí) 就 是對(duì) 類 的 抽象, 那 接口 呢, 說白 了 就是 對(duì) 行為 的 抽象。
附錄 A 培訓(xùn)實(shí)習(xí)生 —— 面向?qū)ο蠡A(chǔ) A.7 繼承 > 位置 4895 子類 從 它的 父 類 中 繼承 的 成員 有方法、 域、 屬性、 事件、 索引 指示器, 但對(duì) 于 構(gòu)造 方法, 有 一些 特殊, 它不 能被 繼承, 只能 被 調(diào)用。 對(duì)于 調(diào)用 父 類 的 成員, 可 以用 base 關(guān)鍵字。
A.8 多態(tài) > 位置 4935 多 態(tài) 表示 不同 的 對(duì)象 可以 執(zhí)行 相同 的 動(dòng)作, 但要 通過 它們 自己的 實(shí)現(xiàn) 代碼 來(lái) 執(zhí)行。
A.8 多態(tài) > 位置 4940 這 里面 有 幾點(diǎn) 注意, 第一, 子類 以 父類 的 身份 出現(xiàn), 第二、 子類 在 工作 時(shí) 以 自己的 方式 來(lái) 實(shí)現(xiàn), 第三、 子類 以 父 類 的 身份 出現(xiàn) 時(shí), 子類 特有 的 屬性 和 方法 不可以 使用。
A.8 多態(tài) > 位置 4960 多 態(tài) 的 原理 是 當(dāng) 方法 被 調(diào)用 時(shí), 無(wú)論 對(duì)象 是否 被 轉(zhuǎn)換 為 其父 類, 都 只有 位于 對(duì)象 繼承 鏈 最末端 的 方法 實(shí)現(xiàn) 會(huì)被 調(diào)用。 也就是說, 虛 方法 是 按照 其 運(yùn)行時(shí) 類型 而非 編譯 時(shí) 類型 進(jìn)行 動(dòng)態(tài) 綁 定調(diào) 用的。[AMNFP]
A.10 抽象類 > 位置 4991 我們 完全可以 考慮 把 實(shí)例 化 沒有 任何 意義 的 父 類, 改成 抽象 類, 同樣 的, 對(duì)于 Animal 類 的 getShoutSound 方法, 其實(shí) 方法 體 沒有 任何 意義, 所以 可以 將 virtual 修飾 符 改為 abstract, 使之 成為 抽象 方法。 C# 允許 把 類 和 方法 聲明 為 abstract, 即 抽象 類 和 抽象 方法。 抽象類 需要 注意 幾點(diǎn): 第一, 抽象 類 不能 實(shí)例 化; 第二, 抽象 方法 是 必須 被子 類 重寫 的 方法,其實(shí) 抽象 方法 可以 被 看成 是 沒有 實(shí)現(xiàn) 體 的 虛 方法; 第三, 如 果類 中 包含 抽象 方法, 那么 類 就必須 定義 為 抽象 類, 不論 是否 還 包含 其他 一般 方法。
A.11 接口 > 位置 5019 接口 是把 隱式 公共 方法 和 屬性 組合 起來(lái), 以 封裝 特定 功能 的 一個(gè) 集合。 一旦 類 實(shí)現(xiàn) 了 接口, 類 就可以 支持 接口 所指 定的 所有 屬性 和 成員。 聲明 接口 在 語(yǔ) 法上 與 聲明 抽象 類 完全 相同, 但不 允許 提供 接口 中 任何 成員 的 執(zhí)行 方式。 所以 接口 不能 實(shí)例 化, 不能 有 構(gòu)造 方法 和 字段; 不能 有 修飾 符, 比如 public、 private 等; 不能 聲明 虛擬 的 或 靜態(tài) 的 等。 還有 實(shí)現(xiàn) 接口 的 類 就必須 要 實(shí)現(xiàn) 接口 中的 所有 方法 和 屬性。
A.11 接口 > 位置 5040 抽象 類 可以 給出 一些 成員 的 實(shí)現(xiàn), 接口 卻不 包含 成員 的 實(shí)現(xiàn), 抽象 類 的 抽象 成員 可被 子類 部分 實(shí)現(xiàn), 接口 的 成員 需要 實(shí)現(xiàn) 類 完全 實(shí)現(xiàn), 一個(gè) 類 只能 繼承 一個(gè) 抽象 類, 但可 實(shí)現(xiàn) 多個(gè) 接口 等等。 但這 些 都是 從 兩者 的 形態(tài) 上去 區(qū)分 的。 我 覺得 還有 三點(diǎn) 是 能 幫助 我們 去 區(qū)分 抽象 類 和 接口 的。 第一, 類 是對(duì) 對(duì)象 的 抽象; 抽象 類 是對(duì) 類 的 抽象; 接口 是對(duì) 行為 的 抽象。 接口 是對(duì) 類 的 局部( 行為) 進(jìn)行 的 抽象, 而 抽象 類 是對(duì) 類 整體( 字段、 屬性、 方法) 的 抽象。 如果 只 關(guān)注 行為 抽象, 那么 也可以 認(rèn)為 接口 就是 抽象 類。 第二, 如果 行為 跨越 不 同類 的 對(duì)象, 可使用 接口; 對(duì)于 一些 相 似的 類 對(duì)象, 用 繼承 抽象 類。 第三, 從 設(shè)計(jì) 角度 講, 抽象 類 是 從 子類 中 發(fā)現(xiàn) 了 公共 的 東西, 泛 化 出 父 類, 然后 子類 繼承 父 類, 而 接口 是 根本 不知 子類 的 存在, 方法 如何 實(shí)現(xiàn) 還不 確認(rèn), 預(yù)先 定義。 抽象 類 是 自 底 而上 抽象 出來(lái) 的, 而 接口 則是 自 頂 向下 設(shè)計(jì) 出來(lái) 的。
A.14 委托與事件 > 位置 5133 委托 是對(duì) 函數(shù) 的 封裝, 可以 當(dāng)作 給 方法 的 特征 指定 一個(gè) 名稱。 而 事件 則是 委托 的 一種 特殊 形式, 當(dāng) 發(fā)生 有意義 的 事情 時(shí), 事件 對(duì)象 處理 通知 過程 [PC#]。 事件 其實(shí) 就是 設(shè)計(jì) 模式 中 觀察者模式 在. NET 中的 一種 實(shí)現(xiàn) 方式。
|
|