青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Javen-Studio 咖啡小屋

http://javenstudio.org - C++ Java 分布式 搜索引擎
Naven's Research Laboratory - Thinking of Life, Imagination of Future

  C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
  24 隨筆 :: 57 文章 :: 170 評(píng)論 :: 4 Trackbacks

侯捷《C++/OOP/GP/DP》講座心得

????????????????? ?????????????????????????????????????????????????????????????????????????????????????????????? ——— 作者: naven

?

??? 很高興侯捷老師又來(lái)公司了,給我們上了四天非常生動(dòng)的技術(shù)講座,受益匪淺,現(xiàn)在我簡(jiǎn)要介紹一下我的學(xué)習(xí)心得,與大家分享。這次講座主要集中在《 C++/OOP/GP/DP 》主題,針對(duì)有一些編程基礎(chǔ)的工程師,對(duì)一些常用的代碼和設(shè)計(jì)做了非常通俗易懂的剖析,非常有幫助。當(dāng)然更深入的理解還需要結(jié)合多種技術(shù)名著來(lái)學(xué)習(xí),我結(jié)合我的理解以及自己的學(xué)習(xí)和開發(fā)的經(jīng)驗(yàn)介紹一下 C++/OO/Template 以及 Design Pattern 的理會(huì),考慮到講座的性質(zhì),我并不直述本次講座的內(nèi)容,歡迎批評(píng)指正 J

?

??? 侯捷老師的講座基本是講述他多年來(lái)在 C++ 領(lǐng)域的研究成果,基本大部分都可以在他的書籍和網(wǎng)站上能讀到,但是考慮到最近幾年軟件技術(shù)的蓬勃發(fā)展,如 Design Pattern 的更廣泛應(yīng)用,又有許多心得,基本上是較為泛的基礎(chǔ)的層面,并結(jié)合實(shí)際代碼和應(yīng)用,對(duì)實(shí)際項(xiàng)目開發(fā)非常有益。下面我逐個(gè)主題泛泛地講一遍。

?

??? 面向?qū)ο笾械暮铣桑?/span> Composition )和繼承( Inheritance )關(guān)系

?

??? 通常擴(kuò)展一個(gè)類的功能主要有兩種方式,一種是大家很熟悉的繼承( inheritance ),另一種就是合成( composition ),很多初學(xué) OO (面向?qū)ο螅┎⒂幸恍┙?jīng)驗(yàn)都很容易搞混這個(gè)的區(qū)別,其實(shí)很簡(jiǎn)單,繼承是解決 Is-a 的問(wèn)題,而合成是解決 Has-a 的問(wèn)題。比如說(shuō)小鳥有兩個(gè)翅膀,就是合成,而鳥是一種飛禽,就是繼承了,設(shè)計(jì)一個(gè)“小鳥”的類,它繼承自”飛禽”,就具有“飛”的特性,但要用合成的方法“包含”一個(gè)“翅膀”的類才具有真正“飛”的功能。

??? 別看這兩個(gè)定義很簡(jiǎn)單,其實(shí)很多人都犯過(guò)錯(cuò)誤,包括 Java 類庫(kù)的設(shè)計(jì)者,他們就把 Properties 直接“繼承”自 Hashtable 了,這里其實(shí)應(yīng)該用“合成”。

?

??? 講到合成,就應(yīng)該說(shuō)說(shuō)聚合( Aggregation ),它是描述整體和局部的關(guān)系,合成其實(shí)是一種“強(qiáng)烈”的聚合,它與局部具有相同的生命周期,“容納”局部的“對(duì)象”,而聚合只是“容納”局部的一個(gè)“指針”。比如說(shuō),人和腦袋就是合成,而汽車與發(fā)動(dòng)機(jī)就是聚合,改裝汽車可以任意替換更好的發(fā)動(dòng)機(jī),而人的腦袋就不行(目前是這樣:)

??? 聚合在 UML 中是以空心棱形的箭頭表示,合成是以實(shí)心棱形的箭頭表示。

?

??? 還有一種關(guān)系叫委托( Delegation ),委托是一種讓合成( composition )變得像繼承( inheritance )的復(fù)用能力一樣強(qiáng)大的方式。( a way of making composition as powerful for reuse as inheritance [Lie86, JZ91] )在委托中,兩個(gè)對(duì)象在處理一個(gè)請(qǐng)求的時(shí)候發(fā)生關(guān)聯(lián):一個(gè)接收的對(duì)象委派操作給它的委托對(duì)象。這跟子類( subclass )延遲請(qǐng)求( deferring requests )給它的父類( parent class )來(lái)實(shí)現(xiàn)類似。但是在繼承里,一個(gè)被繼承的操作( inherited operation )通過(guò) this 成員變量能夠經(jīng)常引用到那個(gè)接收的對(duì)象。為了在委托里達(dá)到同樣的效果,接受者傳遞它自己給它的委托者,以便被委托的操作能夠引用到這個(gè)接收者。

?

??? 再說(shuō)一下繼承( Inheritance ),它是將基類( base-class )所有一切(包括 private )都繼承下來(lái),所以假如你想實(shí)現(xiàn)一個(gè)新的類,只想繼承一部分,就用合成( Composition )別用繼承。或者更進(jìn)一步來(lái)講,如果你想改造一個(gè)類,想改造一些接口( interface ),也建議用合成,通過(guò)轉(zhuǎn)調(diào)內(nèi)部對(duì)象的方法實(shí)現(xiàn),別用虛函數(shù)( virtual function )。這是非常符合最基本的 OCP 設(shè)計(jì)原則( Open-Closed Principle ,開閉原則)的方式了。

?

??? 類的構(gòu)造( Constructor )和析構(gòu)( Destructor

?

??? 類的構(gòu)造和析構(gòu)是最基礎(chǔ)的知識(shí)了,任何一個(gè)類的對(duì)象產(chǎn)生和銷毀都必須有這兩個(gè)步驟,但是它們是如何工作的,編譯器是如何制造缺省的 ctor dtor 的,估計(jì)少有人關(guān)注了。

??? 一個(gè)類的對(duì)象的產(chǎn)生,會(huì)依次從它最里面的類開始構(gòu)造,同一個(gè)類會(huì)跟據(jù)內(nèi)部類成員定義的順序依次構(gòu)造。類對(duì)象的銷毀的過(guò)程則相反。基類的構(gòu)造器會(huì)在用戶定義的 ctor 之前調(diào)用,基類的析構(gòu)則是在用戶定義的 dtor 之后進(jìn)行。熟悉這些過(guò)程,非常有利于設(shè)計(jì)出優(yōu)秀的類庫(kù),也不容易出現(xiàn)內(nèi)存泄露和資源耗盡等問(wèn)題。下面舉個(gè)例子更容易理解:

?

??? class A { public: A(); ~A(); };

??? class B { public: B(); ~B(); };

??? class C { public: C(); ~C(); };

??? class D : public A, B {

??????? public: D() { init(); } ~D() { release(); }

??????? private: void init(); void release(); C c;

??? };

?

??? 上面的定義中 D 類的 ctor 構(gòu)造過(guò)程如下:

??? A::A();

??? B::B();

??? c.C::C();

??? D::init();

?

??? D 類的 dtor 析構(gòu)過(guò)程如下:

??? D::release();

??? c.C::~C();

??? B::~B();

??? A::~A();

?

??? 更復(fù)雜的繼承關(guān)系以及多重繼承的構(gòu)造和析構(gòu)過(guò)程類似,有興趣的人可以寫程序測(cè)試:)

?

??? 還有一個(gè)問(wèn)題,編譯器會(huì)在什么時(shí)候自動(dòng)產(chǎn)生 ctor dtor 的呢,又是如何產(chǎn)生的呢

??? 其實(shí)很簡(jiǎn)單,當(dāng)你沒(méi)有寫缺省構(gòu)造函數(shù)( default constructor )和缺省析構(gòu)函數(shù)( default destructor )的時(shí)候,編譯器就會(huì)給你自動(dòng)生成一個(gè),換句話說(shuō),任何類都有構(gòu)造函數(shù)和析構(gòu)函數(shù),雖然有時(shí)候什么都不做,還有復(fù)制構(gòu)造函數(shù)( copy ctor )也會(huì)自動(dòng)生成。但是如何產(chǎn)生會(huì)跟你的類的成員有關(guān)。如果成員都是原生類型,還有如果類成員也全部為原生類型, ctor 將只會(huì)跟普通變量定義的初始化一樣,給一個(gè)初值, dtor 則什么都不做, copy ctor 則會(huì)使用內(nèi)存復(fù)制( memcpy )的方式復(fù)制對(duì)象。如果成員包含一個(gè)或多個(gè)類成員,而且至少有一個(gè)類成員定義有缺省構(gòu)造方法,則產(chǎn)生的 ctor 會(huì)依次調(diào)用每個(gè)成員的 ctor dtor copy-ctor 產(chǎn)生方法類似。(詳見(jiàn)《 Inside the C++ Object Model 》)

?

??? 多態(tài)( Polymorphism )和虛函數(shù)( Virtual function

?

??? 多態(tài)是面向?qū)ο蟮幕咎匦裕?/span> C++ 里是通過(guò) virtual 關(guān)鍵詞來(lái)提供的,它是通過(guò)在類對(duì)象里加入 vtbl 虛函數(shù)表來(lái)實(shí)現(xiàn)的,這一點(diǎn)相信大部分程序員都很清楚,不過(guò)怎么做到多態(tài)功能估計(jì)了解的不多了。要詳細(xì)了解,還請(qǐng)閱讀《 Inside the C++ Object Model 》一書,下面簡(jiǎn)單介紹一下原理。

?

??? 一般編譯都會(huì)給包含有 virtual function 的類頭部(有的編譯也會(huì)放到底部,比如 VC )增加一個(gè)成員 vptr 指針,指向一個(gè) vtbl 虛函數(shù)表,為定長(zhǎng)數(shù)組,大小是所有帶 virtual 的函數(shù)數(shù)目再加 1 。虛函數(shù)指針從 vtbl[1] 開始,按照定義順序,指向特定的函數(shù)實(shí)現(xiàn)。如果子類定義了父類中帶 virtual 的函數(shù),則 vtbl 相應(yīng)的指針指向子類的函數(shù)實(shí)現(xiàn),否則就指向父類的實(shí)現(xiàn)。另外再說(shuō)明一點(diǎn),其中 vtbl[0] 是有別的用途,用來(lái)存放類型信息,做 dynamic_cast 用途。

??? 仍以上面的例子為例,如下的代碼編譯器是如何處理:

?

??? A *p = new D();???? // up-cast

??? p->vfunc1();??????? ?// 編譯器會(huì)轉(zhuǎn)化為如下代碼

(*(p->vptr))[n](p); // n 為編譯期確定的固定數(shù),即相應(yīng) virtual function

// 所在位置

?

??? 需要牢記一點(diǎn),總是讓 base class 擁有 virtual destructor 。因?yàn)楫?dāng)如下操作時(shí)

?

? ??delete p;

?

??? 如果 A B 的析構(gòu)函數(shù)不是虛函數(shù),則不會(huì)調(diào)用子類 D dtor ,就有可能造成內(nèi)存泄露或者資源沒(méi)有釋放等嚴(yán)重問(wèn)題。如果給 base class 加了 virtual dtor ,由于有多態(tài)的特性,就會(huì)自動(dòng)調(diào)用 subclass dtor ,接下來(lái)就會(huì)上面的介紹,依次調(diào)用各個(gè) base class dtor ,因而就沒(méi)有問(wèn)題了。

?

??? C++ template STL containers

?

??? C++ template 即模板技術(shù)是實(shí)現(xiàn)泛型編程技術(shù)的,能夠使得寫一份代碼可以應(yīng)用到類似用途的不同地方。模板技術(shù)其實(shí)原理比較簡(jiǎn)單,但是使用還是比較復(fù)雜的,看看 STL 源碼就知道了,如果還不相信,再看看 Boost 代碼好了,會(huì)把你搞得暈頭轉(zhuǎn)向。候捷老師把這個(gè)技術(shù)講解得非常清楚易懂,還具體分析了 STL 里各個(gè)大組件的運(yùn)作原理,我這里就不講述了,基本都是源碼的剖析,請(qǐng)閱讀候捷老師的《 STL 源碼剖析》一書。

?

??? 在講解 STL 中用模板如何實(shí)現(xiàn) function class (實(shí)現(xiàn)函數(shù)功能的類,在 stl_functions.h )中,有這樣一段代碼

?

template <class _Operation>

class binder1st

? : public unary_function<typename _Operation::second_argument_type,

????????????????????????? typename _Operation::result_type> {

protected:

? _Operation op;

? typename _Operation::first_argument_type value;

public:

? binder1st(const _Operation& __x,

??????????? const typename _Operation::first_argument_type& __y)

????? : op(__x), value(__y) {}

? typename _Operation::result_type

? operator()(const typename _Operation::second_argument_type& __x) const {

??? return op(value, __x);

? }

};

?

??? 有人提出上面 _Operation op; 為什么不定義為引用,如 _Operation &op; 呢。我的想法如下,因?yàn)闃?gòu)造方法為

? binder1st(const _Operation& __x, // 這里為 const 類型

??????????? const typename _Operation::first_argument_type& __y)

?

??? 傳入的參數(shù)為 const 類型,這時(shí)不應(yīng)在本調(diào)用方法(這里是構(gòu)造方法)之外使用引用或指針指向它,因?yàn)閹?/span> const T &t 的參數(shù)一般情況都視為臨時(shí)對(duì)象,很有可能是在方法調(diào)用的時(shí)候臨時(shí)產(chǎn)生的,比如說(shuō)自動(dòng)轉(zhuǎn)型產(chǎn)生的臨時(shí)對(duì)象都是 const T & 類型,它的生命周期都在此方法調(diào)用期間內(nèi),方法調(diào)用結(jié)束即被銷毀,所以就不能在方法外部用引用或指針之類指向它了。舉例來(lái)說(shuō),可能比較容易理解,比如大家常用的 string 類,假如有一個(gè)方法和調(diào)用如下:

?

??? void func(const string &s);

??? func("abcdfd");

?

??? 這個(gè)時(shí)候就會(huì)出現(xiàn)自動(dòng)轉(zhuǎn)型行為,編譯器會(huì)做如下處理

?

??? func(string("abcdfd"));

?

??? 即產(chǎn)生一個(gè)臨時(shí)的 string 對(duì)象,這個(gè)對(duì)象是以 const 類型傳入的。假如你的方法定義改成如下

?

??? void func(string &s);

?

??? 現(xiàn)在大部分編譯器嚴(yán)格的處理都會(huì)報(bào)錯(cuò),以前的 VC6 就不會(huì),但是好像最新的 VC2005 也報(bào)錯(cuò)了。

??? 這是其中一個(gè)原因,還有一個(gè)原因我認(rèn)為是 _Operation 類只是一個(gè) function class ,沒(méi)有成員,所以做復(fù)制構(gòu)造也不會(huì)有多大的開銷,基本不會(huì)影響效率。再加模板和 inline 方法的處理,編譯器經(jīng)過(guò)優(yōu)化,應(yīng)該都不會(huì)產(chǎn)生臨時(shí)對(duì)象了,所以也不必用引用了。不過(guò)我覺(jué)得最重要是上面第一個(gè)原因。

?

??? 內(nèi)存池和小對(duì)象分配器( memory pool, small object allocator

?

??? 候捷老師在內(nèi)存池方面也有很豐富的研究經(jīng)驗(yàn),他基本將目前主流的內(nèi)存池實(shí)作都剖析了一遍,介紹了它們各自的特點(diǎn),以及如何與上層框架的配合。內(nèi)存池是一個(gè)非常基礎(chǔ)也非常關(guān)鍵的底層庫(kù),一般大型的框架自己都帶有一個(gè)內(nèi)存池庫(kù),比如 STL MFC 等。即使在目前內(nèi)存比較便宜的今天,內(nèi)存資源也是最寶貴的系統(tǒng)資源之一,設(shè)計(jì)一個(gè)優(yōu)秀的內(nèi)存池對(duì)提高系統(tǒng)的效率和穩(wěn)定性都非常有幫助,尤其是設(shè)計(jì)專門針對(duì)小內(nèi)存對(duì)象(一般低于 128 字節(jié))的分配器非常重要,因?yàn)檫@樣對(duì)象分配和釋放非常頻繁,只用簡(jiǎn)單的 malloc() free() 來(lái)處理非常影響效率,不是一個(gè)優(yōu)秀的設(shè)計(jì)。下面我簡(jiǎn)要介紹一下目前主流內(nèi)存池設(shè)計(jì)的特點(diǎn),以及我自己的想法,另外再加一個(gè)候捷老師沒(méi)提到 ACE 中的內(nèi)存池管理器的設(shè)計(jì)特點(diǎn)。

?

??? SGI STL 中的內(nèi)存分配器( allocator

?

??? SGI STL allocator 應(yīng)該是目前設(shè)計(jì)最優(yōu)秀的 C++ 內(nèi)存分配器之一了,它的運(yùn)作原理候捷老師在《 STL 源碼剖析》里講解得非常清楚。基本思路是設(shè)計(jì)一個(gè) free_list[16] 數(shù)組,負(fù)責(zé)管理從 8 bytes 128 bytes 不同大小的內(nèi)存塊( chunk ),每一個(gè)內(nèi)存塊都由連續(xù)的固定大小( fixed size block )的很多 chunk 組成,并用指針鏈表串接起來(lái)。比如說(shuō)

?

??? free_list[3]->start_notuse->next_notuse->next_notuse->...->end_notuse;

?

??? 當(dāng)用戶要獲取此大小的內(nèi)存時(shí),就在 free_list 的鏈表找一個(gè)最近的 free chunk 回傳給用戶,同時(shí)將此 chunk free_list 里刪除,即把此 chunk 前后 chunk 指針鏈結(jié)起來(lái)。用戶使用完釋放的時(shí)候,則把此 chunk 放回到 free_list 中,應(yīng)該是放到最前面的 start_free 的位置。這樣經(jīng)過(guò)若干次 allocator deallocator 后, free_list 中的鏈表可能并不像初始的時(shí)候那么是 chunk 按內(nèi)存分布位置依次鏈接的。假如 free_list 中不夠時(shí), allocator 會(huì)自動(dòng)再分配一塊新的較大的內(nèi)存區(qū)塊來(lái)加入到 free_list 鏈表中。

??? 可以自動(dòng)管理多種不同大小內(nèi)存塊并可以自動(dòng)增長(zhǎng)的內(nèi)存池,這是 SGI STL 分配器設(shè)計(jì)的特點(diǎn)。

?

??? Loki 中的小對(duì)象分配器( small object allocator

?

??? Loki 的分配器與 SGI STL 的原理類似,不同之處是它管理 free_list 不是固定大小的數(shù)組,而是用一個(gè) vector 來(lái)實(shí)現(xiàn),因此可以用戶指定 fixed size block 的大小,不像 SGI STL 是固定最大 128 bytes 的。另外它管理 free chunks 的方式也不太一樣, Loki 是由一列記錄了 free block 位置等信息的 Chunk 類的鏈表來(lái)維護(hù)的, free blocks 則是分布在另外一個(gè)連續(xù)的大內(nèi)存區(qū)間中。而且 free Chunks 也可以根據(jù)使用情況自動(dòng)增長(zhǎng)和減少合適的數(shù)目,避免內(nèi)存分配得過(guò)多或者過(guò)少。

??? Loki 的分配器使用也不太一樣,可以直接調(diào)用,如下

?

??? SmallObjAllocator myAlloc(2048, 256); // 參數(shù) 1 chunk size

????????????????????????????????????????? // 參數(shù) 2 max fixed size block size

??? // 可以用于小于 256 bytes 的各種大小內(nèi)存的分配

??? void *p1 = (void*)myAlloc.Allocate(20);

??? void *p2 = (void*)myAlloc.Allocate(100);

??? void *p3 = (void*)myAlloc.Allocate(256);

??? void *p4 = (void*)myAlloc.Allocate(300); // 大于 256 將轉(zhuǎn)交給系統(tǒng)處理

??? myAlloc.Deallocate(p1,20);

??? myAlloc.Deallocate(p2,100);

??? myAlloc.Deallocate(p3,256);

??? myAlloc.Deallocate(p4,300);

?

??? MFC CPlex CPtrList (扮演 memory pool 角色)

?

??? CPlex 任務(wù)比較簡(jiǎn)單,只負(fù)責(zé)管理一大塊 memory 并串接起來(lái),用戶每次獲取都返回一大塊。分割由使用者(如 Collection classes CFixedAlloc )將這一大塊切割為一個(gè)個(gè)小的內(nèi)存塊。

??? CPtrList 則負(fù)責(zé)管理這些切割后的小內(nèi)存塊,這一點(diǎn)有點(diǎn)類似 Loki 中的 free Chunks ,不過(guò)要簡(jiǎn)單多了。

??? MFC 還有一個(gè)類叫 CFixedAlloc ,它是提供給應(yīng)用類來(lái)分配固定大小(根據(jù)具體應(yīng)用類的大小)的內(nèi)存分配器。通過(guò)在應(yīng)用類中定義 DECLARE_FIXED_ALLOC(Foo) IMPLEMENT_FIXED_ALLOC(Foo) 兩個(gè)宏來(lái)實(shí)現(xiàn)。

?

??? Boost object_pool

?

??? Boost 中的 object_pool 也是一個(gè)可以根據(jù)用戶具體應(yīng)用類的大小來(lái)分配內(nèi)存塊的,也是通過(guò)維護(hù)一個(gè) free nodes 的鏈表來(lái)管理的。可以自動(dòng)增加 nodes 塊,初始是 32 個(gè) nodes ,每次增加都以兩倍數(shù)向 system heap 要內(nèi)存塊。 object_pool 管理的內(nèi)存塊需要在其對(duì)象銷毀的時(shí)候才返還給 system heap

?

??? ACE 中的 ACE_Cached_Allocator ACE_Free_List

?

??? ACE 框架中也有一個(gè)可以維護(hù)固定大小的內(nèi)存塊的分配器,原理與上面講的內(nèi)存池都差不多。它是通過(guò)在 ACE_Cached_Allocator 中定義個(gè) Free_list 鏈表來(lái)管理一個(gè)連續(xù)的大內(nèi)存塊的,里面包含很多小的固定大小的未使用的區(qū)塊( free chunk ),同時(shí)還使用 ACE_unbounded_Set 維護(hù)一個(gè)已使用的 chuncks ,管理方式與上面講的內(nèi)存池類似。也可以指定 chunks 的數(shù)目,也可以自動(dòng)增長(zhǎng),定義大致如下所示:

?

template<class T>

class ACE_Cached_Allocator : public ACE_New_Allocator<T> {

public:

??? // Create a cached memory pool with @a n_chunks chunks

??? // each with sizeof (TYPE) size.

??? ACE_Cached_Allocator(SIZET n_chunks = ACE_DEFAULT_INIT_CHUNKS);

??? T* allocate();

??? void deallocate(T* p);

private:

??? // List of memory that we have allocated.

??? Fast_Unbounded_Set<char *> _allocated_chunks;

??? // Maintain a cached memory free list.

??? ACE_Cached_Free_List<ACE_Cached_Mem_Pool_Node<T> > _free_list;

};

?

??? 設(shè)計(jì)模式

?

??? 最后一個(gè)主題重點(diǎn)講講設(shè)計(jì)模式,設(shè)計(jì)模式現(xiàn)在已經(jīng)應(yīng)用很廣泛了,可以說(shuō)是無(wú)處不在。設(shè)計(jì)模式現(xiàn)在對(duì)程序員是非常的重要,甚至到了不懂設(shè)計(jì)模式就不算真正的程序員一樣。不過(guò)設(shè)計(jì)模式卻又是非常高階的理論,需要有多年的編程經(jīng)驗(yàn)才能真正領(lǐng)悟,所以學(xué)習(xí)起來(lái)非常頭痛。因?yàn)樗览矸浅:?jiǎn)單,但是卻非常抽象,候捷老師通過(guò)一大堆實(shí)際案例給我們逐個(gè)講述了幾個(gè)常用的模式的區(qū)別和用法。設(shè)計(jì)模式最經(jīng)典最權(quán)威當(dāng)屬著名的有字天書 GoF 的《 Design Patterns 》了,我結(jié)合自己學(xué)習(xí)和實(shí)踐的體會(huì)介紹一下幾個(gè)模式。

?

??? 結(jié)構(gòu)型模式之 Composite (合成模式)

?

??? GoF 的定義: Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects. 翻譯為中文大致意思是:將對(duì)象 (s) 組成為樹狀結(jié)構(gòu),用以表示“局部 - 整體”的層次體系,使得讓 clients 可以以一致的方式對(duì)待“單個(gè)對(duì)象”和“合成對(duì)象”。

?

??? 比較典型的例子就是文件系統(tǒng)中“文件”和“目錄”的關(guān)系,還有 Windows 窗口系統(tǒng)也是,在一個(gè)窗口中還可以開另一個(gè)窗口,多個(gè)窗口組合成的窗口還可以當(dāng)作一個(gè)窗口放入另一個(gè)窗口中,比如在 Word 中打開多個(gè)文檔就是這種情況。 Composite 模式的好處就是使得 clients 調(diào)用簡(jiǎn)單,可以用一致的接口處理單個(gè)對(duì)象或者多個(gè)單一對(duì)象組合成的對(duì)象。

?

??? 實(shí)例: Java swing library Component , Label , Container 就是 Composite 模式的應(yīng)用。其中 Label Container 都繼承自 Component ,但是 C ontainer 中只是一個(gè)存放 Component 的數(shù)組,所以 Container 中就可以放很多 Component ,比如 ScrollPane 就是繼承自 Container ,它可以放 Label ,還有 List , Scrollbar 等等,甚至還可以放一個(gè) ScrollPane ,所以就達(dá)到了 Composite 模式的效果,簡(jiǎn)化了 client 的使用。

?

??? 結(jié)構(gòu)型模式之 Decorator (裝飾模式)

?

??? GoF 的定義: Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. 翻譯為中文大致的意思是:以動(dòng)態(tài)的方式給一個(gè)對(duì)象添加一些額外的職責(zé),使得不必進(jìn)行 subclassing 就能擴(kuò)展功能。

?

??? Decorator 模式與 Composite 模式的區(qū)別就是它只內(nèi)含一個(gè) component object field ,而 Composite 則內(nèi)含一個(gè) collection of component field Decorator 負(fù)責(zé)將一個(gè)對(duì)象“裝飾”起來(lái),做一些“改造或者擴(kuò)展”,提供額外的功能,它只針對(duì)一個(gè) class 。而 Composite 是一組“類似”的對(duì)象及其容納它們的容器一視同仁,使得 client 更簡(jiǎn)單地處理單個(gè)對(duì)象和一組對(duì)象。它們目的不一樣。

?

實(shí)例: Java IO library BufferedReader , Reader 之間使用的就是 Decorator 模式,其中 BufferedReader 繼承自 Reader ,同時(shí)它內(nèi)部含有一個(gè) Reader 引用,它是通過(guò)另一個(gè) Reader 對(duì)象構(gòu)造而來(lái),因此就為 Reader 提供更多的功能,如帶緩沖的 Reader 。使用非常簡(jiǎn)單,只需要如此定義:

?

Reader in = new BufferedReader(new FileReader("test.txt"));

?

就為文件讀取增加了帶緩沖的 IO 功能,非常方便。還可以多個(gè) Decorator 的類組合使用,可以提供更強(qiáng)大的功能,多使用一下 Java IO library 就會(huì)體會(huì)到。

?

??? 行為模式之 Observer (觀察者模式)

?

??? GoF 的定義: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

翻譯為中文大致意思是:在 objects 之間定義一個(gè)“一對(duì)多”的依賴關(guān)系,使得當(dāng)這個(gè) object 改變狀態(tài)時(shí),所有依賴它的 objects 都能獲得通知并自動(dòng)更新。

?

??? Observer 是用于做“通知”用途的,就像“ publish-subscribe ”,它能夠做到注冊(cè)需要通知的對(duì)象,并自動(dòng)通知它們來(lái)更新,它們都是被動(dòng)地被通知,而不是主動(dòng)觀察。

?

??? 實(shí)例: MFC CView CDocument 之間就是一個(gè)觀察者模式, CView Observer 即觀察者, CDocument Observable 即被觀察者,當(dāng) CDocument 修改后會(huì)自動(dòng)通知所有的 CView 對(duì)象來(lái)自動(dòng)更新它們顯示的內(nèi)容,這一點(diǎn)可以用 Word 很容易試出來(lái)。還有最新的 Windows 圖形界面框架 WinForm 中的窗口之間消息傳遞等用的也是 Observer 模式,一個(gè)窗口發(fā)生改變時(shí)會(huì)自動(dòng)通知所有與它有關(guān)系的窗口,來(lái)自動(dòng)更新信息等,這一點(diǎn) Jeffrey Richter 可以作證 J

?

??? 行為模式之 Template Method (模板方法)

?

??? GoF 的定義: Define the skeleton of an algorithm in an operation, deferring somesteps to subclasses. Template Method lets subclasses redefine certain steps ofan algorithm without changing the algorithm's structure. 翻譯為中文大致意思是:定義一個(gè)算法的骨干,延緩其中某些步驟以便在 subclasses 中定義它們。 Template Method 使得 subclasses 在不改變算法的體系結(jié)構(gòu)的前提下得到重新定義算法內(nèi)的某些步驟。

?

??? Template Method 其實(shí)最常用了,在 C++ 里的應(yīng)用就是使用 virtual function 實(shí)現(xiàn)的,給一個(gè) base class 定義一個(gè) virtual 方法,但是不實(shí)現(xiàn),而是在它的 subclasses 中實(shí)現(xiàn)它,這就是 Template Method 。這個(gè)模式的好處顯而易見(jiàn),就是在你設(shè)計(jì) base class 的時(shí)候并不知道這個(gè)方法具體如何實(shí)現(xiàn),但是卻需要在 base class 里某個(gè)地方需要調(diào)用它以完成一個(gè)完整的算法,這時(shí)候就是需要用這個(gè)模式了。

?

??? 實(shí)例:例子太多了,到處都是。

?

??? 行為模式之 Strategy (策略模式)

?

??? GoF 的定義: Define a family of algorithms, encapsulate each one, and make theminterchangeable. Strategy lets the algorithm vary independently from client that use it. 翻譯為中文大致意思是:定義一族算法,把每個(gè)算法封裝起來(lái),并使它們可以相互替換。 Stategy 使得算法給 client 使用的時(shí)候變得完全獨(dú)立。

?

??? Strategy 模式完全符合 OCP Open-Closed Principle ,開閉原則),可以在不需要做 subclass 更不需要修改 base class 的情況下在 Runtime 的時(shí)候擴(kuò)展系統(tǒng)的功能,它不像 Template Method 需要 subclass 才能擴(kuò)展新的功能。

?

??? 實(shí)例: Strategy 典型的應(yīng)用是在薪資系統(tǒng)中,當(dāng)定義 Employee 類的時(shí)候,如果使用 Template Method 模式,就無(wú)法更改員工領(lǐng)薪資的方式等,比如員工晉升的時(shí)候。這時(shí)候就需要用 Strategy 模式,在 Employee 中定義一個(gè)指針指向具體的 PaymentMethod 對(duì)象,如果需要更改領(lǐng)薪資的方式的時(shí)候,只需要將它指向新的 PaymentMehtod 實(shí)現(xiàn)就可以了。

?

??? 結(jié)構(gòu)模式之 Adapter (適配器模式)

?

??? GoF 的定義: Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. 翻譯為中文大致意思是:將一個(gè) class 的接口轉(zhuǎn)換為另外一種 clients 所期望的接口,使得這些 classes 可以更好地協(xié)同工作起來(lái),而不至于因?yàn)閯e的不兼容的問(wèn)題所影響。

?

??? Adapter 模式屬于結(jié)構(gòu)型模式,需要有 Adaptee (被適配者)和 Adaptor (適配器)兩個(gè)對(duì)象。一般情況下,我們通過(guò)繼承( Inheritance )或者合成( Composition )的方式擴(kuò)展類的功能后,會(huì)產(chǎn)生很多接口形式不同的類,但是我們想用同樣的方式調(diào)用它們,又不想改造它們(否則違反 OCP 原則),怎么辦呢?這種情況下就需要用到 Adapter 模式了,這些被“改造”的類就叫做 Adaptee ,而我們就需要寫個(gè) Adaptor 類來(lái)轉(zhuǎn)調(diào)它們,把調(diào)用的接口改成統(tǒng)一的形式。

?

??? 實(shí)例: Java IO library 里的 InputStreamReader 就是一個(gè) Adapter ,它負(fù)責(zé)將 InputStream 對(duì)象轉(zhuǎn)換為 Reader 對(duì)象的接口形式,使得用戶可以像使用其它 Reader 一樣的方式來(lái)使用 InputStream 對(duì)象,比如:

?

InputStreamReader isr = new InputStreamReader(

new FileInputStream("test.txt"));

??? BufferedReader br = new BufferedReader(isr);

??? String line = br.readLine();

?

??? 這就做到了在不改造原來(lái)設(shè)計(jì)的類的接口的情況,擴(kuò)展了類的應(yīng)用范圍。一般情況下, Adapter 模式需要結(jié)合 Factory 模式和 Proxy 模式來(lái)使用,使得接口的訪問(wèn)更加一致性,更容易改造系統(tǒng)。

?

??? 結(jié)構(gòu)模式之 Facade (外觀模式)

?

??? GoF 的定義: Provide a unified interface to a set of interfaces in a subsystem.Facade defines a higher-level interface that makes the subsystem easier to use. 翻譯為中文大致意思是:為一個(gè)子系統(tǒng)的一批接口提供一個(gè)統(tǒng)一標(biāo)準(zhǔn)的接口, Facade 定義更高層次的接口,使得子系統(tǒng)更容易使用。

?

??? Facade 模式我感覺(jué)是一個(gè)更高層次的 Adapter ,它是用來(lái)理順系統(tǒng)之間的關(guān)系,降低系統(tǒng)間的耦合度的常用方法,其實(shí)我們可能在設(shè)計(jì)系統(tǒng)的時(shí)候就在不知不覺(jué)地應(yīng)用這個(gè)模式了。大部分將業(yè)務(wù)邏輯層和表示層分離的框架都是應(yīng)用 Facade 模式實(shí)現(xiàn)的,使得上層使用者完全不必理會(huì)底層的實(shí)現(xiàn),卻又有統(tǒng)一的使用界面。

?

??? 實(shí)例: J2EE EJB Session Bean 就是一種典型的 Facade 模式,即 Session Facade 。它完全將業(yè)務(wù)對(duì)象封裝起來(lái), EJB 客戶端訪問(wèn) Session Bean 來(lái)代替訪問(wèn)業(yè)務(wù)對(duì)象。這就大大簡(jiǎn)化了 EJB 的系統(tǒng)結(jié)構(gòu), Session Bean 就是相當(dāng)于一個(gè)外觀,也相當(dāng)于一個(gè)總管,把業(yè)務(wù)對(duì)象都管理起來(lái),不讓客戶端直接“接觸”到它們。

?

??? 《設(shè)計(jì)模式》一書中還有很多模式這里就不一一介紹了。其實(shí)我們大家都可以自己設(shè)計(jì)一種模式,但是肯定沒(méi)有 GoF 的那 23 個(gè)著名了。不過(guò)現(xiàn)在還有很多別的也很有名的模式,比如說(shuō) Wrapper 模式(相當(dāng)于 Decorator )、 DAO 模式( Data Access Object 模式, OR 映射系統(tǒng)里常用到)、 MVC 模式(著名的 Model-View-Control 架構(gòu)模式)等等。我的一個(gè)觀點(diǎn),只有大量地實(shí)踐,持續(xù)地學(xué)習(xí),就會(huì)不斷提升自己設(shè)計(jì)模式的層次,如果想靠一兩年的學(xué)習(xí)就想精通它,是不可能的任務(wù) J

?

??? 寫了這么多,終于寫完了,呵呵。寫完后,有兩點(diǎn)體會(huì): 1, 寫源碼剖析類的文章,就像是給代碼做翻譯,把代碼翻譯成圖片或文字。 2 ,寫 OO/DP 之類理論的文章,則相當(dāng)于創(chuàng)造,不同的人有不同的體會(huì),技術(shù)學(xué)習(xí)層面不同的理解也不同。還是那句話:理論需要從實(shí)踐中來(lái),多學(xué)習(xí)多實(shí)踐。歡迎指正!

?

最后我列幾本候捷老師推薦的書:

??? 1 C++ 程序員必備的書(我以為,即時(shí)你不看,也建議備上,充門面也好,爭(zhēng)吵也好都很用)

?????? a) C++ Programming Language Bjarne Stroustrup

?????? b) C++ Primer Stanley B Lippman

?????? c) Effective C++ Scott Meyers

?????? d) Design Patterns GoF

??? 2, 提高或?qū)W習(xí)的書

?????? a) Inside The C++ Object Model Stanley B Lippman

?????? b) Thinking in C++ Bruce Eckel

?????? c) More Effective C++ Scott Meyers

?????? d) STL 源碼剖析》侯捷

?????? e) Modern C++ Design Andrei Alexandrescu

?????? f) Small Memory Software - Patterns for memory management

?

?

?

-- 適合讀者: C++ 中高級(jí)程序員

-- 作者: naven 博客: http://www.shnenglu.com/javenstudio/ 20061228

posted on 2006-12-31 10:31 Javen-Studio 閱讀(4562) 評(píng)論(5)  編輯 收藏 引用

評(píng)論

# re: 侯捷《C++/OOP/GP/DP》講座心得[未登錄](méi) 2011-08-31 14:36 Chipset
《 C++ Programming Language 》 Bjarne Stroustrup OK
C++ Standard ISO/IEC14482 OK

其他的都是垃圾。  回復(fù)  更多評(píng)論
  

# re: 侯捷《C++/OOP/GP/DP》講座心得 2011-10-17 17:37 將盡快看看
就看看iop,i80pop8366  回復(fù)  更多評(píng)論
  

# re: 侯捷《C++/OOP/GP/DP》講座心得 2011-10-17 17:38 將盡快看看
889088i90-p[opp【【p ii9003734  回復(fù)  更多評(píng)論
  

# re: 侯捷《C++/OOP/GP/DP》講座心得 2013-05-07 10:16 dangerman
看了這么多UML的文章都沒(méi)明白聚合和組合的區(qū)別,都是互相抄,看了您的文章終于明白了,謝謝  回復(fù)  更多評(píng)論
  

# re: 侯捷《C++/OOP/GP/DP》講座心得 2013-05-07 11:17 溪流
學(xué)習(xí)了  回復(fù)  更多評(píng)論
  


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区三区欧美成人| 美女主播精品视频一二三四| 母乳一区在线观看| 亚洲午夜激情网站| 欧美不卡高清| 国内一区二区三区| 亚洲在线日韩| 亚洲国产精品成人综合色在线婷婷| 亚洲国产美女| 欧美电影免费观看| 99国产精品视频免费观看| 久久综合一区| 欧美一区二区视频97| 国产精品国产一区二区| 99ri日韩精品视频| 日韩一级免费观看| 欧美激情二区三区| 亚洲激情专区| 欧美成人嫩草网站| 久久精品二区三区| 亚洲精品影视在线观看| 久久www成人_看片免费不卡| 国产精品高清在线| 午夜视频在线观看一区二区| 日韩一区二区久久| 国产精品久久久久aaaa樱花| 欧美一区在线看| 亚洲欧美日韩国产一区| 国产精品毛片大码女人 | 日韩视频在线永久播放| 国产精品va在线播放我和闺蜜| 99精品久久久| 亚洲天堂成人在线观看| 国产亚洲精品久久久久久| 篠田优中文在线播放第一区| 正在播放欧美视频| 国产精品久久久久久久久久直播| 欧美制服丝袜| 欧美一区二区三区啪啪| 亚洲大胆人体视频| 欧美国产丝袜视频| 免费成人激情视频| 亚洲人精品午夜| 亚洲激情视频| 欧美日韩福利| 亚洲曰本av电影| 久久www成人_看片免费不卡| 亚洲精品久久久久久久久久久久 | 国产一区二区三区久久久久久久久 | 欧美在线亚洲一区| 免播放器亚洲| 午夜精品视频在线观看| 久久女同互慰一区二区三区| 亚洲第一中文字幕在线观看| 99精品国产一区二区青青牛奶| 欧美色一级片| 午夜精品短视频| 久久在线免费观看视频| 91久久在线播放| 亚洲一区国产精品| 国产一区二区日韩| 亚洲欧洲日本在线| 国产一区二区毛片| 亚洲精品一区二区在线观看| 国产一区二区三区无遮挡| 亚洲精品日本| 精品盗摄一区二区三区| 亚洲福利视频一区二区| 欧美日韩在线不卡| 欧美在线高清| 欧美日本韩国一区| 午夜一区二区三区不卡视频| 男人插女人欧美| 亚洲影视综合| 免费观看不卡av| 久久av免费一区| 欧美日韩免费精品| 蜜月aⅴ免费一区二区三区 | 亚洲黄色有码视频| 国内成+人亚洲+欧美+综合在线| 欧美成人首页| 国产欧美精品在线| 欧美激情亚洲另类| 国产亚洲欧美日韩美女| 一本久道久久综合婷婷鲸鱼| 亚洲国产精品va在线看黑人动漫| 99亚洲伊人久久精品影院红桃| 亚洲国产第一页| 香蕉久久国产| 亚洲精品影视| 午夜精品在线观看| 亚洲一区二区欧美日韩| 久久精品盗摄| 欧美一级免费视频| 欧美三级乱码| 91久久精品国产91久久| 在线看国产一区| 欧美一区二区在线免费播放| 亚洲欧美日韩成人| 久久在线视频| 久久亚洲私人国产精品va| 欧美日本国产视频| 亚洲国产精品成人| 亚洲高清免费| 久久精品国产久精国产一老狼| 欧美永久精品| 国产精品一国产精品k频道56| 欧美国产激情| 在线看欧美日韩| 久久精品亚洲国产奇米99| 亚洲性夜色噜噜噜7777| 欧美日本在线播放| 亚洲国产精品一区二区尤物区| 亚洲高清激情| 两个人的视频www国产精品| 老牛影视一区二区三区| 韩国av一区二区三区| 欧美一区免费| 久久久精彩视频| 国产精品久久久久7777婷婷| 日韩网站免费观看| 一区二区三区欧美亚洲| 久久亚洲综合色| 欧美成年人网站| 亚洲第一福利社区| 麻豆精品精华液| 欧美激情精品久久久久久免费印度 | 另类图片综合电影| 黄色日韩精品| 久久久久久国产精品mv| 亚洲欧美日韩精品久久奇米色影视 | 午夜精品婷婷| 国产美女一区| 欧美一区二区三区播放老司机| 久久精品欧洲| 国产精品理论片| 亚洲一区免费网站| 久久成人免费电影| 国产自产女人91一区在线观看| 欧美在线999| 久久夜色精品国产欧美乱极品| 黄色一区二区在线观看| 女仆av观看一区| 亚洲精品免费观看| 亚洲精品在线免费| 欧美日韩专区在线| 亚洲四色影视在线观看| 久久成人人人人精品欧| 精品成人免费| 欧美高清不卡在线| 一区二区冒白浆视频| 欧美一区二区视频97| 伊人久久亚洲影院| 久久久久成人精品| 亚洲国产va精品久久久不卡综合| 9久草视频在线视频精品| 欧美精品日韩一本| 亚洲区中文字幕| 亚洲影院污污.| 国产一区二区三区久久| 久久综合伊人| 一二三区精品福利视频| 久久激情综合| 亚洲精品一级| 国产精品视频久久一区| 亚洲女人天堂成人av在线| 午夜精品久久久久久| 精品成人一区二区三区| 欧美破处大片在线视频| 午夜电影亚洲| 欧美激情中文字幕一区二区| 亚洲一区二区三区涩| 国产一区二区三区久久精品| 欧美韩国在线| 午夜精品久久久久久99热软件| 欧美a级大片| 亚洲欧美国产三级| 亚洲成色999久久网站| 欧美日韩精品综合| 久久国产直播| 99视频一区二区| 免费成人性网站| 亚洲一区二区三区色| 亚洲第一在线综合在线| 国产精品美女一区二区在线观看| 开心色5月久久精品| 亚洲小少妇裸体bbw| 亚洲第一精品福利| 性一交一乱一区二区洋洋av| 91久久久亚洲精品| 国产日韩亚洲欧美综合| 久久精品天堂| 一区二区三区日韩欧美| 欧美成人免费在线观看| 午夜欧美视频| 日韩一区二区免费高清| 韩国一区二区三区美女美女秀| 欧美四级在线| 欧美va天堂| 久久se精品一区精品二区|