UML class diagram 只是個概觀,不會說明所有細節(例如如何實作),可以為需要建立的 class 進行 modeling。

用一張圖解釋:

繼承

1
2
3
4
class Parent
class Child

Child -up-|> Parent

實作(implement)

1
2
3
4
interface Interface
class Concrete

Concrete .up.|> Interface

class 間的關係

抽象上來看 class 之間的關係,程式語言裡不見得有對應的語法,但是釐清抽象上的關係有助寫 code。只要對系統來說是合理的,class 間的關係可能因為系統的演進而改變。

關聯強度:composition > aggregation > association

Association

class 間有關係但關聯性較弱。

1
2
3
class Foo
class Bar
Foo -right-> Bar

class Foo 知道 class Bar

Aggregation

class 間是 has a 的關係。class A 包含 class B,但 B 不是 A 的一部分。

main object 不負責 composed object 的 create 及 destroy,composed object 可以獨立於 main object 之外。例如車子跟輪胎間的關係(Car has a Tire),輪胎可以獨立於車子之外(可以從車子上拆下來)。

UML 以空心菱形表示:

1
Car o-right- Tire

Composition

class 間是 own 的關係。(碎念:own 跟 has 根本沒辦法用中文區分…)

main object own composed object.

composed object 是 main object 的一部分(a part of),composed object 不會獨立存在於 main object 之外。main object 負責 composed object 的 create 及 destroy,main object destroy 時 composed object 也會 destroy。例如生物跟細胞間的關係(Animal owns Cell)。

UML 以實心菱形表示:

1
2
3
4
class Animal
class Cell

Animal *-right- Cell

composition 跟 aggregation 最大的不同在於 composed object 的生命週期是否與 main object 有關。

Dependency

class 間是依賴關係時,UML 以虛線箭頭表示:

1
2
3
4
5
6
class Animal
class Water
class Air

Animal .right.> Water
Animal .left.> Air

這個原則跟何時該使用繼承有關:derived class 必須能替代 base class。

使用繼承時必須確保 base class 的所有特性及 method 對 derived class 仍成立,反過來說,derived class 必須有 base class 所有特性。一個 derived class 的 object 是一個(is-a)base class 的 object,原本對 base class 的 object 所做的所有操作可以直接換成對 derived class 的 object 操作。

C++ 的 public 繼承在意義上即是 LSP 所說的繼承觀念。

繼承的替代方案

使用繼承一般是希望擴充原有 class,但如果套用繼承時發現會違反 LSP,有什麼替代方案呢?

class 應該只負責一件事、只有一個改變的理由,class 聚焦於實作該責任。避免一個 class 有多重責任,或者一個責任分散在多個 class 中。SRP 的主要目的是增加 class 的 cohesion(內聚力)。

OO 中會以 class 為單位,但可以提升到 process level。舉例來說,將多個 process 啟動與結束的控制分散在各個 process 以及 watch dog,就讓「控制 process 的啟動與結束」這個責任分散在多個地方。這會導致較難理解控制流程、不知道某個時間點是誰在控制,修改時也容易出 bug。

一個 class 可以負責一個「大」責任。運用 SRP 應該會讓系統中的 class 比較少但比較大,因為會將功能性集中在負責該功能的 class。在思考一個 class 應該負責什麼時,用較抽象的方式去想會比較好,想這 class 要做什麼?它的名稱顯示它該負責什麼?某件事究竟關不關它的事?

我覺得區分 class 的責任蠻困難的,取決於設計者怎麼想、怎麼看待一個 class 以及其想法的合理性。

SRP 分析

分析一個 class 是否符合 SRP。把 class 跟 method 名稱套到以下句子,用人類語言看看通不通順。

The [class] [method] itself.
The [class] [method] [arg] itself.
該 [class] [method] 它自己
該 [class] 自己 [method]

想起來順表示該 method 屬於這個 class、符合 SRP,反之則表示這 method 應該移到其他地方。

分析時要注意參數可能在 construct 已先傳入,不一定是 method 的 argument。

名稱就說明了它的意思──不要重複。

這也是概念上的原則。不僅限於不重複相同的程式碼,也包括不要重複相同的程式碼、相同的功能(例如多個軟體間不重複相同的功能)等等,確保一件事情、一項資訊只存在一個地方。

遵守這個原則的好處是當一件事情需要修改的時候,只需要修改一個地方,不會因為需要改很多地方而漏掉、造成問題。

DRY 也跟如何好好分解系統有關──如何將每項資訊、功能、程式碼放在單一且合理的地方。

Software entities such as class, modules, functions should be open for extension, but closed for modification.

直接英翻中就是「對擴展開放,對修改關閉。」

換句話說,允許擴展但不允許修改原有的 code。在現有程式運作得好好、通過測試的狀況下,應該以擴展的方式新增系統功能,而非修改原有的 code。OCP 著重於軟體彈性,遵守這原則能在增加新功能時確保原本行為不會被更動,減少在原本運作良好的部分產生 bug 的風險。不過遵循 OCP 可能會引入新的抽象層、增加 code 的複雜度,所以並不是整個系統所有地方都該遵守,而是找出最有可能改變的地方才使用 OCP,沒必要的地方使用也是種浪費。

OCP 是設計層次上的原則。

舉個例子:較 high level 的 class 應該以 interface 使用較 low level 的 class,而非直接使用 low level 的 class。如此需要支援其他種 low level 實作時,便能直接實作 interface 並修改產生 instance 的地方,即可做到「不修改原本 high level 的 code,而能擴充 low level 實作」。

另外像瀏覽器的 plugin、Linux kernel 的 module(即使 C 語言不是所謂的物件導向語言,依然能以物件導向的概念撰寫)同樣都運用了 OCP。

原本想說既然在 Windows 上開發,用 Visual Studio 好了,但打開網站看到價格,呃,我還是繼續用 Eclipse 跟 Qt Creator 吧!謎版?找謎版的時間我都可以處理好了…

Install Windows SDK

安裝 Windows 7 的。

Microsoft Windows SDK for Windows 7 and .NET Framework 4

Troubleshooting

裝 Windows SDK 失敗,像這篇的狀況。移掉 Microsoft Visual C++ 2010 redistributable packages 後再裝 Windows SDK 就可以了。

compile 時遇到 error C2059: syntax error : 'constant'patch

Eclipse

Install CDT Visual C++ Support

在 Eclipse 裝 CDT Visual C++ Support,才有 Visual C++ tool chain。我的 Eclipse 是 Juno。

CDT site:http://download.eclipse.org/tools/cdt/releases/juno

Configuration

Project property

C/C++ Build -> Tool Chain Editor 的 toolchain 設為 Microsoft Visual C++。

C/C++ Build -> Environment 增加 PATH C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin,這樣才找得到 Visual C++ compiler。

C/C++ General -> Paths and Symbols -> Includes -> GNU C++

Eclipse Configuration

Qt Creator

因為想到要有 GUI 介面,所以需要 Qt + Windows SDK,但現在 Eclipse 跟 Qt 的整合不太好,改用 Qt Creator + Windows SDK。

直接裝 Qt 5.3.1 for Windows 32-bit (VS 2010, OpenGL, 537 MB)

Kits

如果已經先裝其他版本的 Qt,應該可以在選項裡加 Kit:

Qt Creator Windows SDK Kits

pro setting

INCLUDEPATH 要加 Windows SDK 的路徑,如 Eclipse Configuration 圖中的路徑。

Troubleshooting

compile 時遇到 LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt 的錯誤。

Solution:http://qt-project.org/wiki/Category:Tools::msvc

應將 member data 宣告為 private,以 public member function 存取 member data。如此可透過 member function 做細微的 access control,例如以只有 get function 沒有 set function 實作 read-only 的性質。

將 member data 宣告為 private 也提升它的封裝性。一個元件的封裝性跟其內容改變時需修改的 code 量成反比,需修改的 code 越多表示封裝性越低。例如修改一 member data 的名稱時,需要檢查所有 code?還是繼承架構中的 code?還是該 class 的 code?

要注意在 class 提供外界使用並可供繼承時(如 framework、library 的 class),protected 不比 public 來得更有封裝性,兩者幾乎不相上下。雖然 protected member data 的使用範圍僅限於繼承體系,但由於公開給他人使用,使用該 member 的 code 數量跟直接 public 給他人使用沒什麼區別。(就是都很多啦!)

Ref

  • 《Effective C++》item 22 Declare data members private

前置作業

安裝 Node.js

1
2
3
4
$ git clone https://github.com/hexojs/hexo
$ cd hexo
$ npm install
$ git submodule update --init

npm install 應該是為了把需要的 node module 裝起來。

修改後直接 run bin/hexo 即可。

改以 updated 排序 post

http://goo.gl/63S6ui 的,可從 _config.yml 設定 post 以 date 或 updated 排序。如果 post 沒有設 updated,updated 時間會等於 date。

https://github.com/cjwind/Hexx/commit/f72a82107b4f325a4dfe23641aac78533a499bae
https://github.com/cjwind/Hexx/commit/d115baf9e2d516684d637d79d22f0177129daa0b

耍蠢所以變成兩個 commit

Ref

簡單記錄一下。

我把 node_modules/scaffolds/source/themes/_config.ymlpackage.json 放到 bitbucket 的 private git repository,另一台電腦裝 node.js 跟 hexo,clone repository 下來就可以了。

原本順利弄完也就好了,我就手賤的做了 npm update -g 更新 hexo,然後 generate 就爛了。後來約莫是 hexo init .npm install,然後 merge 一些改過的 theme 檔案跟 config,才總算好了。

技術 blog 沒有搜尋挺麻煩的,儘管有設 tag,但還是搜尋最方便。之前在 Octopress 用的 Tapir 不支援中文,看起來沒什麼解,只好另尋新歡(?)。找到 Swiftype 這套,除了基本搜尋功能外,Swiftype 還提供調整搜尋結果、統計分析等功能。

註冊、輸入 URL,它處理完後到 INSTALL 頁面 copy source code 到 theme 中相應 call search_form() 的地方。每個 theme 的位置不太一樣,nut 在 layout/_widget/search.ejs,landscape 在 layout/_partial/header.ejs

發現一個問題:在 overlay 的顯示方式下,搜尋結果的頁面太長,scroll bar 無法捲到最下面。想改成結果直接顯示在頁面,不用 overlay,之後參考這裡看怎麼改。