所遇不良設計(二)

  軟件設計就比如造房子。當一個軟件bug重重,擴展很困難時,還不如推到了,再從新作一個。在博客上,看到陌陌的勁舞手遊,由於在設計上不到位,致使整個手遊從新開發; 同時負責這個遊戲的項目經理也隨之離職。java

1 文件的層疊

  如今咱們在用eclipse開發軟件,在切換文件的時候很麻煩; 由於一個系統模塊的文件分佈到不一樣的文件目錄裏面去,就像珍寶,用層層的布裹着,你須要一層層的打開,才能知其廬山真面目。如下是用tree工具打印的目錄樹:linux

  ├── project
  │   ├── include
  │   │   ├── module1
  │   │   │   └── submod1
  │   │   ├── module2
  │   │   └── module3
  │   └── src
  │       ├── module1
  │       ├── module2
  │       └── module3
View Code

  這是我用tree打印的工程文件目錄,在這個工程.h和.cpp文件用include和src來分開。若是你要開發一個系統模塊,你須要在include的dir一、dir二、dir3和src的dir一、dir二、dir3裏面分別新建.h和.cpp文件,由於一個模塊又分爲了幾個子模塊。若是你使用一種可視化開發工具中的project explorer來瀏覽文件,都要把頭切換暈了; 要是可能的話module1下面可能還有submodule1文件夾。我以爲系統的模塊的層級結構並非特別須要用文件目錄來表現,並且這樣子也讓Makefile寫起來很麻煩; 可能有人會說能夠不須要寫,自動生成的,用automake。可是當要寫一些跨平臺的工程的時候,不只僅在linux下面,還包括windows以及mac,我更加傾向於用CMake。曾經我下載過redis的源碼,這是一個用C語言開發的NOSQL數據庫,其全部的.c、.h文件都放到了src目錄下,簡單極了,切換文件很方便; 並且其就只有一個Makefile文件。 在這裏,我並非批評那些在一個工程裏面放有目錄的人,我是但願儘可能能減小目錄,儘可能把頭文件和源文件放到一塊兒; 由於咱們在開發項目的時候,同時要兼顧頭文件和源文件。咱們能夠這樣子: 程序員

  ├── project
  │   ├── mod1
  │   │   ├── submod1.cpp
  │   │   ├── submod1.h
  │   │   ├── submod2.cpp
  │   │   └── submod2.h
  │   ├── mod2
  │   └── mod3
View Code

2 命名的規範

  我見過好多搞C/C++的人,比較討厭Java。首先Java隱藏了指針了,搞得這些同胞們,對人生失去了樂趣; 其次Java的效率問題,以爲始終沒有C/C++高; 再者以爲搞Java有點腦殘,太簡單,垃圾什麼的都不用管,有點亂扔垃圾的意思,不文明。可是我要說的時,Java有許多好的設計模式。在文件命名方面,Java作得比較好。java文件名必需要和裏面的類必須同名,我以爲C++也應該保持這樣的方式,雖然編譯器沒有強制你這樣作,可是頗有必要,這樣子經過文件名稱就能看到裏面裝的是什麼類。其次Java用到了包,在Java編程思想裏面包名和你的網絡名稱同樣,這樣便於網絡傳輸,不會出現包的衝突,由於網絡地址是惟一的。C++裏面有namespace,用namespace封裝本身的類庫,能夠防止本身的類庫,和第三方的庫衝突,不過namespace的名稱必須是標識符。 我見過的工程裏面,每一個程序員都有本身的編程規範,公司的編程規範沒有很好的去執行。首先,我以爲好多公司的編程規範不夠詳細,模棱兩可; 其次好多開發人員可能以前在其餘公司呆過,保留了上一家公司的編程習慣。若是公司可以肯定了好的編碼規範,你們仍是願意遵照的。這裏我比較推薦google的C/C++編程規範,網上都有電子文檔的。還有就是用腳本語言檢測程序按期檢查編寫的代碼,是否有不符合規定編碼的規範,這些都須要項目經理去認真的執行的。redis

3 宏的臃腫

3.1 宏的好處

  宏的替換是無與倫比,沒有其餘能夠替代的。我看到宏在好多地方合理有效的利用,其能有效的減小繁瑣的重複的代碼、解決跨平臺系統系統API不兼容的問題(經過系統的宏定義,來判斷是什麼操做系統,從而來調用相應的系統API,這些事情都在編譯的時候就完成了)數據庫

3.1.1 拋出異常

  爲了調試代碼,我要拋出異常,異常的內容包括文件名、行號、錯誤碼:編程

  throw new Exception(FILE, LINE, error);
View Code

  每次我都要加入__FILE__、__LINE__ 比較囉嗦, 使用宏更加方便:windows

  #define THROW_EXCEPTION(error) \
      throw new Exception(__FILE__, __LINE__, error)
View Code

  這裏不能用函數來替代的,要是那樣,_FILE__, _LINE_就顯示的是所用函數的文件和行,形成異常的錯誤提示有誤設計模式

3.1.2 解決系統的跨平臺問題。

1 #ifdef _WIN32
2      xxxx
3 #elif _LINUX
4      xxxx
5 6 #else
7      xxxx
8  #endif
View Code

  Poco庫是一個優秀的C++庫,跨平臺。其結構也很清晰,能夠去了解,裏面有不少這樣設計的。數組

3.1.3 定義靜態的數組

  int a[10],可能a的數組長度常常發生變化,並且咱們常用10這個常量。咱們能夠這樣作 :網絡

  #define LEN 10
  int a[LEN];
View Code

   當咱們之後要改變長度時,咱們只須要改變LEN這個宏的值就好了,防止大量的替換。

3.2 宏的壞處

  可是宏在編譯的時候要替換代碼,會生成不少重複的代碼。若是你的宏要是很長,會很糟糕。有人可能說宏很快,我以爲爲了追求那點速度,而違背代碼的簡約設計,是沒有說服力的。並且宏也帶來調試的不方便(在宏裏面下斷點無效)。在代碼中儘可能減小宏的使用比較好。大多時候,咱們能夠用函數來代替宏,這樣可以複用,即便宏很短。

3.2.1 使用帶有const類型的常量

  當咱們定義常量的時候而且常量不是在編譯的時候使用,可使用帶const的類型變量聲明宏,例如const int len = 10。由於這樣便於咱們肯定常量的類型。可能宏定義整形的時候,默認就是整形。要是宏定義一個小於255的數字,依舊使用整型,若是是一個浮點型,其默認是單精度,除非你把小數點加長,讓float不能識別,這時候編譯器纔將其當作double了。其實用define肯定常量,讓常量的類型產生了歧義,讓類型不夠明瞭。

3.2.2 使用工廠模式來經過名字獲取對象

  在C++裏面沒有反射機制(即經過類名來建立類),用宏是很容易作到的。以下: //根據名字來定義一個類:

 1 //根據名字來定義一個類:
 2 #define DEF_CLASS(class_name) \
 3      class class_name##Mgr {\
 4      public:\
 5          static class_name##Mgr* CreateClass() {\
 6          return new class_name##Mgr;\
 7      }\
 8          ....\
 9      }
10 
11 //建立類
12 #define CREATE_CLASS(class_name) \
13      class_name##Mgr::CreateClass()
View Code

  以上使用##宏來鏈接類名,根據名字定義一個以Mgr結尾的類,以及建立對象。要實現這樣的方式,咱們只能用宏。其實咱們能夠其餘的方法,即利用多態的特性來模擬這種特性。

class Base {
public:
    ....
};

class Derive:public Base{
public:
    ....
};

class Factory {
public:
   //註冊各個類
   void RegisterClass(const string& classname, Base* pBase) {
        classes[classname] = pBase;
   }
   //建立
   Base* CreateClass(const string& classname) {
        if find
            return classes[classname];
        retur NULL;
   }
   ....
private:
   hash_map<std::string, Base*> classes;
}
View Code

  工廠模式能夠根據類名來取出對象來,我以爲已經夠用了。雖然實際上沒有根據類名來自由的建立類,你還得手動的去建立各個類,咱們只是在作存和取的工做。工廠模式通常被用來總領整個框架,就像是寫做文的提綱似的。 使用宏不夠好,同時也可能形成代碼難以閱讀; 應當儘可能避免宏。

相關文章
相關標籤/搜索