以C/C++語法淺談六大設計原則(一)——依賴倒置原則(Dependence Inversion Principle)
一. 前言
眾所周知,在軟體開發過程中,我們的六大設計原則與二十三種設計模式可以說是我們開發的思想精髓。然而,網上或者書本大多數的資料都是以java、python等其他語言語法進行介紹與闡述,很少有以C/C++的語法進行深入介紹。鑑於此,本人以淺薄的見識對這些精妙的思想做以總結,方便我們在今後的工作、學習中進行查閱參考。本篇以設計六大原則之一的“依賴倒置原則進行講起”。
二.依賴倒置原則
1. 定義
高層模組不應該依賴於底層模組,而應該依賴於抽象。抽象不應依賴於細節,細節應依賴於抽象。
2. 解決的問題
類A直接依賴類B,假如要將類A改為依賴類C,則必須通過修改類A的程式碼來達成。這種場景下,類A一般是高層模組,負責複雜的業務邏輯;類B和類C是低層模組,負責基本的原子操作;假如修改類A,會給程式帶來不必要的風險。因此我們需要將依賴的方向進行重新規劃,像下面這樣:
我們將介面與實現相分離,應用與細節相分離,介面層提供我們業務層所需要的介面方法,實現層對介面的具體方法進行實現,高層業務邏輯不關心介面實現的具體細節,它只對介面進行呼叫,從而降低了類之間的耦合性,增加了程式碼的可讀性,降低了後續維護的成本。
3.例項
我們瞭解了依賴倒置解決問題的具體方法,下面讓我們以C/C++的程式設計視角來看看在具體的專案中我們該如何實現。
我們以經典的媽媽給我講故事來看程式碼的具體實現:
首先我們定義一本故事書類,像這樣:
#include <iostream> using namespace std; class Book { public: Book(){} ~Book(){} public: const std::string GetBookText() { return "once upon a time......"; //很久很久以前...... } };
然後我們的媽媽類隆重登場,像這樣:
class Monther
{
public:
Monther(){}
~Monther(){}
public:
void readBook(Book& book)
{
std::cout << book.GetBookText() << std::endl;
}
};
然後我們的媽媽開始給我們講睡前故事,像這樣:
int main(int argc, char *argv[]) { Book book; Monther* monther = new Monther(); if(monther != nullptr) { monther->readBook(book); //媽媽給我講故事,我乖乖睡覺覺....... } delete monther; monther = NULL; return 0; }
到此,媽媽故事講完了,我也乖乖睡覺了,可是,可是,,,,突然有一天,我不想聽故事了,我想聽新聞,想聽廣播,還想聽…阿歐,媽媽遇到這樣的小孩也算是“前世修來的福”,可我們是孝順的孩子呀,我們可以這樣去設計我們的程式碼邏輯,注意了,真正的依賴倒置設計登場了,注意,注意,注意!!!
首先,我們抽象出一個所有讀物的基類父介面,像這樣:
class IReadContent
{
public:
IReadContent(){}
virtual ~IReadContent(){} //解構函式定義為virtual型別,保證派生類繼承後析構時析構完全
public:
virtual const std::string GetContent() const = 0; //獲取讀物的具體內容
}
然後,我想聽故事、想聽新聞、還想聽…嗯,,,,,讓故事書、報紙,,,,繼承這個讀物類,像這樣:
//《童話鎮》 /*美劇,挺好看的一部通話故事劇,感興趣可以去看看,,,,*/
class StoryBook:public IReadContent //故事書類
{
public:
virtual const std::string GetContent() const
{
return "很久很久以前,白雪公主與小矮人在魔法森林裡智鬥巫後......";
}
};
//報紙類
class NewsPager:public IReadContent
{
virtual const std::string GetContent() const
{
return "報紙上說,白雪公主與小矮人在童話鎮幸福的生活著......";
}
};
我們的媽媽又一次隆重登場了,阿歐,為什麼要說“又”?這次的媽媽可是很厲害的,不信你看:
class Monther
{
public:
void read(IReadContent& readContent)
{
std::cout<< readContent.GetContent() << std::endl;
}
};
又到媽媽開始講故事的時刻了,噢不,媽媽啥都能講嘍,且看下面分解:
int main(int argc, char *argv[])
{
Monther* monther = new Monther(); //定義一個厲害的媽媽
if(monther)
{
StoryBook storyBook; //我想聽故事
monther->read(storyBook); //給你講故事
NewsPager newsPager; //我想聽新聞
monther->read(newsPager); //給你說新聞
//... //我想聽...
//... //給你說...
//...... //我想聽....
//....... //你咋不上天.......
}
delete monther;
monther = NULL;
return 0;
}
至此,媽媽故事講完了,我開始講依賴倒置的故事了,嗯,媽媽是頂級的業務邏輯層(類Monther),介面層當然是我們的中間樞紐讀物類介面(類IReadContent),細節實現層當人不讓是我們的幾個細節實現類(StoryBook、NewsPager 、等等),在回過頭看看我們的定義:**“高層模組不應該依賴於底層模組,而應該依賴於抽象。抽象不應依賴於細節,細節應依賴於抽象。”**要是沒有理解,建議從頭再聽一次媽媽講故事,要是還沒懂,嗯,來找我吧,我慢慢跟你講媽媽講故事:“很久很久以前…”
三.總結
善始善終吧,簡單做個總結。
1.優點:
說明 | 簡述 |
---|---|
減少類之間的耦合 | 鬆耦合 |
提高系統的穩定性 | 穩定性 |
提高程式碼的可讀性 | 可讀性 |
… | … |
2.本質
通過 抽象 即 介面或者抽象類, 使 各個類 和 模組實現彼此獨立, 實現模組間 鬆耦合;
四.後續
程式的靈魂是思想,程式的思想精髓是設計原則與設計模式,後續會不斷以C/C++的語法視角對設計原則與設計模式進行闡述。由於本人水平有限,文中有不足之處希望大家能及時指正。 後面有時間我會繼續更新有關程式設計方面的知識,若有更好的想法和需求及時與我取得聯絡,相互學習,共同進步。