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,之後參考這裡看怎麼改。

沒進,只對 A,不過這是我第一次 R1 破蛋……2013 年掛蛋,2011 年也是,其他年份沒參加。

一整個亂……= =

考慮過從最遠古的祖先直接建表,但想想覺得應該不行。就變成往回推的判斷:

  1. 若 Q 是奇數,則 impossible。
  2. Q / P = x (x 為整數) = 2 ^ n,則 ans = n
  3. Q' = Q / 2 直到 Q' < P(記錄除的次數 n),P' = P - Q',recursive 檢查 P'/Q' 是否可能出現。是則 ans = n,否則 impossible。

既然有 code 可以檢討還是檢討一下好了。

  1. 看看那精美的 scanf(),又一次 C++ format input/output 不熟。
  2. 邏輯上有方向但細節沒想清楚,像 Q 一直除 2 的時候原本沒先檢查是不是能整除,原本也沒處理處理特殊值 1。
  3. 大測資一開始沒用 long long int,然後就 segementation fault 了。

屬於 Creational pattern。

確保 class 只有一個 instance,並且給它 global 的存取點。

可以做到延後產生 instance,也就是真正使用到時才 create instance。如果用 global variable,依據不同語言及實作的特性可能在程式一開始就產生 instance。

常用來管理 shared resource。

做法

  • 將 constructor、copy constructor、destructor、assignment operator 宣告為 private 確保外面無法產生第二個 instance 及 destory instance。
  • 使用 static function 讓外界取得唯一的 instance。

C++ 實作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Singleton
{
public:
static Singleton* GetSingleton();

private:
Singleton() { /* implement */ };
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
};

Singleton* Singleton::GetSingleton()
{
static Singleton* pSingleton = new Singleton();
return pSingleton;
}

外面要取得 instance 時 call Singleton::GetSingleton()。這邊直接用 C++ 的 static local variable 在 function 第一次 call 時會 initialize 之後不會再 initialize 的特性,而它的 lifetime 會持續到程式結束。

有另一種做法是 GetSingleton() 不 return pointer,而 return reference。

這個實作沒有 thread-safe,有多個 thread 會 call GetSingleton() 就 GG 了。要 thread-safe 可以用 double-checked locking。

Ref