OOD啟思錄

OOD啟思錄

4.4使用關係的經驗原則52 第10章經驗原則和模式的關係169 第11章在面向對象設計中使用經驗原則183

基本信息

原書名: Object-Oriented Design Heuristics
原出版社: Addison-Wesley Professional
作者: (美)Arthur J. Riel [作譯者介紹]

譯者: 鮑志雲
出版社:人民郵電出版社
ISBN:9787115265432
上架時間:2011-11-17
出版日期:2011 年12月
開本:16開
頁碼:358
版次:1-1

內容簡介

《ood啟思錄》提供了改進面向對象設計的真知灼見。
全書共11章,總結出了60多條面向對象設計(ood)的指導原則。這些經驗原則涵蓋了從類到對象(主要強調它們之間的關係,包括關聯、使用、包含、單繼承、多繼承)到面向對象物理設計的重要主題。《ood啟思錄》將幫助你理解經驗原則和“設計模式”這一流行概念之間的相互作用。你可以藉助經驗原則發現設計中所存在的某一方面的問題,而設計模式則提供了解決方案。
《ood啟思錄》對各個層次的開發者都有價值,新手能藉助本書走上通向面向對象編程的快車道,想提升自己的面向對象開發水準的老手則會受益於本書深具洞察力的分析。《ood啟思錄》提供了讓你成為更好的軟體開發者的途徑。
作譯者回到頂部↑本書提供作譯者介紹
Arthur J.Riel從事C和C++編程工作已有超過12年的經驗。目前,他每年在學術界和產業界講授40多次課程。他參與了許多大系統的開發,曾就職於AT&T貝爾實驗室、Draper實驗室、IBM、東北大學。他還在Journal of Object-Oriented Programming、The C++ insider、The C/C++Gazette等刊物上發表了眾多文章。他還經常在OOPSLA、Object Expo、SCOOP、C++ Worm等頂級會議上演講。
鮑志雲 已翻譯出版了《對象揭秘:Java、Effiel和C++》、《套用MDA》和《解析MDA》3本譯著,曾以“紫雲英”為筆名在《程式設計師》、《程式春秋..

目錄

《ood啟思錄》
第1章 面向對象編程的動因 1
1.1 革命家、改革家與面向對象范型 1
1.2 frederick brooks觀點:非根本複雜性與根本複雜性 3
1.3 瀑布模型 4
1.4 疊代模型 5
1.5 構造原型:相同語言與不同語言 6
1.6 軟體復用性 7
1.7 優秀設計者階層 7
術語表 8
第2章 類和對象:面向對象范型的建材 11
2.1 類和對象導引 11
2.2 訊息和方法 14
2.3 類耦合與內聚 18
2.4 動態語義 20
2.5 抽象類 22
2.6 角色與類 23
術語表 24
經驗原則小結 25
第3章 應用程式布局:面向動作與面向對象 27
.3.1 應用程式的不同布局 27
3.2 面向動作范型何時適用 29
3.3 問題:全能類(行為表現) 30
3.4 系統功能不良分布的另一個例子 34
3.5 問題:全能類(數據表現) 36
3.6 問題:泛濫成災的類 38
3.7 代理類的角色 42
3.8 用途考察:單獨實體和控制類 44
術語表 46
經驗原則小結 46
第4章 類和對象的關係 49
4.1 類和對象關係導引 49
4.2 使用關係 49
4.3 實現使用關係的6種不同方法 50
4.4 使用關係的經驗原則 52
4.5 精確調整兩個類之間的協作量 53
4.6 包含關係 55
4.7 類之間的語義約束 58
4.8 屬性與被包含的類 60
4.9 包含關係的更多經驗原則 61
4.10 使用和包含的關係 63
4.11 值包含與引用包含 64
術語表 65
經驗原則小結 66
第5章 繼承關係 69
5.1 繼承關係導引 69
5.2 在派生類中覆寫基類方法 73
5.3 在基類中使用保護區域 75
5.4 繼承層次結構的寬度和深度 77
5.5 c++的劃分:私有、保護和公有繼承 78
5.6 一個現實世界中的特化例子 80
5.7 經驗原則:尋求設計複雜性和靈活性的平衡 81
5.8 一個現實世界中的泛化例子 84
5.9 多態機制 85
5.10 把繼承作為復用機制的一個問題 89
5.11 用繼承實現中斷驅動架構的方案 93
5.12 繼承層次結構與屬性 94
5.13 混淆:繼承的需求與對象動態語義 96
5.14 用繼承來隱藏類的實現 98
5.15 把對象誤當作繼承類 99
5.16 把需概括對象誤作需在運行時創建類 100
5.17 在派生類中禁止基類方法的嘗試 103
5.18 對象可選部分的實現 106
5.19 沒有最優解的問題 108
5.20 復用組件與復用框架 112
術語表 115
經驗原則小結 116
第6章 多重繼承 119
6.1 多重繼承導引 119
6.2 多重繼承的常見誤用 120
6.3 多重繼承的正當使用 122
6.4 不支持多重繼承的語言中的非根本複雜性 123
6.5 用到多重繼承的框架 124
6.6 運用多重繼承:設計mixin 125
6.7 dag多重繼承 126
6.8 可選包含的不良實現造成的不當dag多重繼承 127
術語表 128
經驗原則小結 128
第7章 關聯關係 131
7.1 關聯導引 131
7.2 用引用屬性實現關聯 132
7.3 用第三方類實現關聯 134
7.4 在包含關係和關聯關係間取捨 135
術語表 136
經驗原則小結 137
第8章 與特定類相關的數據及行為 139
8.1 類相關與對象相關數據及行為導引 139
8.2 用元類來表示類相關數據及行為 140
8.3 用語言層面關鍵字來實現類相關與對象相關數據及行為 141
8.4 c++中的元類 141
8.5 有用的抽象類,但不是基類 143
術語表 144
經驗原則小結 145
第9章 面向對象物理設計 147
9.1 面向對象邏輯設計和物理設計的角色 147
9.2 創建面向對象包裝器 150
9.3 面向對象系統中的持久化 153
9.4 面向對象應用程式中的記憶體管理問題 156
9.5 可復用組件的最小公有接口 157
9.6 實現安全的淺拷貝 161
9.7 並行面向對象編程 164
9.8 用非面向對象語言實現面向對象設計 165
術語表 167
經驗原則小結 168
第10章 經驗原則和模式的關係 169
10.1 經驗原則與模式 169
10.2 設計變換模型的傳遞性 171
10.3 設計變換模式的自反性 174
10.4 其他設計變換模式 176
10.5 未來研究 180
第11章 在面向對象設計中使用經驗原則 183
11.1 atm問題 183
11.2 選擇方法學 185
11.3 產生atm對象模型的第一次嘗試 186
11.4 給我們的對象模型增加行為 188
11.5 非根本複雜性帶來的顯式情況分析 192
11.6 在不同地址對象間傳遞訊息 193
11.7 交易處理 194
11.8 回到atm的領域 194
11.9 其他雜類問題 196
11.10 小結 198
附錄a 經驗原則總結 201
附錄b c++中的記憶體泄漏 207
附錄c c++實例精選 229
本書中引用到的其他圖書 355
參考文獻 357

譯者序

擁有豐富面向對象開發經驗,並且願意無保留地告訴你自己的經驗,而且還有這個天分能把這些寶貴經驗講述得深入淺出,這樣的人不多。而本書作者碰巧就是。Arthur J.Riel曾工作于貝爾實驗室、Draper實驗室、IBM、東北大學,他既有豐富的開發經驗,又有豐富的授課經驗。而Authur整理自己開發與授課心得,並參考了眾多面向對象經典著作後寫就的(OOD啟思錄》一書,也確實無愧乎讀者的評價——“面向對象設計領域中的Effective C++”。正如Effective C++能助你邁向C++專家層面,《OOD啟思錄》能助你邁入OOD的殿堂。
這本書並不講述RUP等方法學框架,也不講述UML或者C++語言,而純粹講述設計經驗(其實原書書名中heuristics一詞是啟發式教學的意思)。這樣的書在目前書市中汗牛充棟的00著作中並不多見。而且,和開發方法學著作或者其他00著作中以“bestpractice”(最佳實踐)的方式傳授設計經驗的做法不同,這本書不僅告訴你好的做法,還告訴你不好的做法,並且告訴你如何識別,如何判斷好的(糟糕的)做法,並且教你在面對多種可能的設計方案時如何作出取捨。擁有這些能力正是有經驗的優秀開發者同初學者的區別所在。作者能夠把這些往往“可意會但難言傳”的設計經驗提煉成易學易記易參考的“經驗原則”的形式,而且伴以分析、討論與實際套用例子來幫助你理解和消化這些經驗,這是非常難能可貴的。
書的語言載體是C++。這只是因為寫作時C++恰好是業界最流行的語言,並不意味著這些經驗原則都只適用於C++。其實,這些凝聚著智慧的設計經驗中大多數是跨越語言(並且跨越時代)的,同語言相關的經驗原則只占全書很小一部分。所以,如果您只會Java或者C#,本書對您也依然很有價值並且容易讀懂。這是因為書中的C++代碼是比較樸素的風格,沒有大量採用模板,沒有採用現代的泛型編程技法,看起來和Java、C#的語法差不多。
對國內的讀者,這本書又多了一層含義。任何學過一門程式語言的人,若是想要做一些真正的項目,寫出高質量的代碼,都會有向優秀開發者學習第一手經驗的迫切需求。但偏偏目前國內的軟體開發教學尚有與實踐脫節之處,目前大學計算機系教學計畫中基本都有C++或Java語言課程,但是很少有關於設計經驗的課程,而且高校中也缺乏這樣的師資,在這本書之前也缺乏這樣的教材。若是純粹依靠自己開發摸索來獲得設計經驗,又需要耗費很長時間,而且會走很多彎路,且不夠系統。而《OOD啟思錄》正好填補了這個空白,很適合剛學完程式語言,希望向面向對象設計層面進階的讀者。
說到設計經驗,就不得不提到模式。或許很多讀者看過或者聽說過《設計模式》這本書,並對書中歸納的23個經典模式耳熟能詳或者倒背如流。但不知您是否熟知在怎樣的場合應當使用哪個模式,又為何要使用那個模式?記住模式容易,學以致用難,因為在實踐中場景是千變萬化的,難以判定應當採用某一模式。而這正是本書解決的問題之一。《OOD啟思錄》第10章講述了書中列出的經驗原則同模式的關係:一條經驗原則對應了一個或者多個變換模式——從反模式(糟糕的設計——違反了某條經驗原則)變換成適合設計需要的模式。
現今,糟糕的設計還有另一個暱稱:“bad smell”(見Martin Fowler的《重構》一書)。那么,變換模式所做的也正是以相應經驗原則為指導,把具有bad smell的設計重構成合適的模式。這倒是和後來Joshua Kerievsky的想法“refactoring to Patterns”殊途同歸了。
依照目前的趨勢,可以預言,將會有越來越多的開發工具支持自動識別“bad smells”(Together、PatternTesting等),或者支持自動重構(很多IDE都支持了),甚至兩者皆支持(那就近似可以自動或半自動地改善設計質量了)。事實上,這種做法正是將專家經驗植入開發工具。那么,我們是否還需要看這本書中列出的專家經驗呢?面對內置專家經驗的“智慧型開發工具”的“自動修改或者建議修改你的代碼/設計”的新功能,有3種可能的態度:[1]放棄對代碼的控制權,任工具自動去修改[2]關閉工具的這項功能[3]掌握工具這項功能的背後原理,知道每個修改建議的“所以然”,在自己保有對代碼控制權的同時藉助工具新功能來大幅提高效率。如果您覺得[3]匕較適合您,那么最好還是看一下這本書。
原書印刷版本並未包含網站上的全部代碼,而只是摘選,所以譯本也照此處理。此外,因為網站內容更改容易,書本內容印出來後卻難以實時更新,所以網站上代碼和書中代碼細節之處可能會略有“版本差異”,但不會影響閱讀和理解。
最後,要感謝人民郵電出版社的陳編輯在眾多OO書籍中獨具慧眼地挑出了這一本。雖然書中內容對我而言多屬“溫故而知新”,但在翻譯過程中我還是獲得了不少啟迪,受益良多。希望這個譯本也能帶給您幫助,並且能給您帶來愉快的閱讀體驗。如您發現譯文有不妥之處,請不吝指正。我的E-mail是:
鮑志雲
於南京
2004年7月

前言

在向幾千名學生講授面向對象分析、設計和實現的過程中,我逐漸意識到,業界很需要可以幫助開發者做出正確決定的指導原則。自1987年起我就開始查閱文獻,試圖找到可以適用於不同層次的開發過程的效率和複雜性參考基準,以便改善面向對象應用程式。除了那些從文獻里找出來的指導原則,我還增加了自己的“家釀”原則。這樣,我就得出了大約60條原則。其中有幾條頗有些玩笑意味,但它們同樣值得重視。我曾考慮是否把這些原則命名為“面向對象設計與分析的60條黃金準則”,不過我想起了Dykstra那傳奇般的論文Goto Considered Harmful,該文給用goto語句的人戴上了“異教徒”的帽子(聽起來就好像他們應當被綁在公司大院的木架上施以火刑一樣)。這非常重要,因為該文給業界提出了規則,阻止了使用goto語句的人繼續有意或無意地破壞他們的系統的可維護性。不幸的是,這樣的規則也造成了不良影響:出現了一群心理不太正常的作者,25年來一直在發表文章聲稱“在應用程式的某個詭異角落明智地使用goto語句,能讓代碼的可讀性高於對應的結構化代碼”。當然,這些論文後面還跟著一堆“駁論文”,後面還有“駁一駁論文”,等等。
為了避免類似的宗教戰爭再次發生,我把本書中的60來條指導原則稱為經驗原則(heuristics)。你不必嚴格遵守這些原則,違背它們也不會被處以宗教刑罰。但你應當把這些原則看成警鈴,若違背了其中的某一條,那么警鈴就會響起。你應當嚴肅對待這些警告並細緻檢查。如有必要,你應修改設計以消除警告。當然,如果在某個例子中有一些經驗原則因這樣或那樣的原因而不適用,這也是完全正常的。事實上,在面向對象設計的特定場合下兩條經驗原則常常會互不相容。開發者需要判斷在該場合下哪條經驗原則更重要一些。
雖然“創建一種‘Riel的面向對象分析/設計方法學”’想法聽起來很誘人,但本書沒有發明新的面向對象分析或設計方法學。業界已經有夠多的方法學了,它們提供了類似的或是重複的建議,並且對相同的概念使用完全不同的術語。無論採用何種方法學,面向對象開發者遇到的典型問題出現在設計完成之後。但迄今還沒有人認真地去解決這個問題。這個問題是:“現在我做完設計了,但這個設計是好?是壞?還是好壞參半?”如果去問面向對象專家,那么好的設計獲得的評價是常常是“這個設計‘感覺起來’挺好的”。對開發者來說,這個答案價值不大,但這樣的回答卻有其內在真理。這位面向對象大師會在下意識里讓這個設計走過——個經驗原則列表。這個列表是隨這位大師的設計經歷而積累起來的。如果設計順利通過了這個經驗列表,那么“感覺挺好的”,否則這個設計“感覺不太對”。
本書試圖描述出這個原本存於大師們潛意識中的經驗原則列表,並且以現實例子為支撐。讀者們很快就會意識到,有一些經驗原則比其他的原則更重要。經驗原則的重要程度取決於違反這條原則造成的後果有多嚴重。不過我並不把這些原則按照重要程度排序,因為我覺得在很多情況下優先次序取決於套用領域和用戶需求,是不能在本書中量化的。例如,在設計中有時會遇到兩條經驗原則背道而馳的情況,其中一種常見情況是用複雜性和靈活性之間的取捨。問一下你自己,你最想要的是什麼,是增加靈活性還是降低複雜性。這樣,你就會意識到難以在本書中列出經驗原則的優先次序。這些設計經驗原則是以現實世界中的例子為背景而定義的,這些例子覆蓋了各條經驗原則所屬的領域。實際例子是向初學者解釋面向對象技術的概念的理想平台,因此本書很適合於初學者。藉助本書,初學者可以駛上理解面向對象編程的快車道,而不必徘徊於甚至迷失在充斥於OO世界的時髦用語之間。與此同時,對經驗豐富的面向對象開發者而言,如果他們正在尋求良好的分析和設計經驗原則的話,也會發現本書獨具魅力,能為他們的開發帶來很大幫助。
第1章探討面向對象編程的動因,以Frederick Brooks發表於1987年的《沒有銀彈》一文(見參考文獻)中論及的一些問題入題。我對面向對象編程的看法是,這是面向動作開發之後的自然進步,或稱為演進。軟體變得越來越複雜,所以我們必須達到離機器更遠的一個新抽象層次,這樣才能繼續控制軟體開發過程。正如結構化方法要比自底向上的編程高一個抽象層次,面向對象技術也比結構化方法提高了一個抽象層次。這並不意味著“自底向上編程或者結構化方法是錯誤的,面向對象編程才是正確的”。如果能用的記憶體只有4KB,那么自底向上的編程完全適用;若能用的記憶體有256KB,那么結構化方法非常合適。不過隨著硬體越來越強大且越來越便宜,軟體的複雜性也扶搖直上。在20世紀80年代早期,開發者還不需要考慮圖形用戶界面和多執行緒應用程式的複雜性;那時候司空見慣的是簡單的選單驅動單執行緒套用。但是,在不久的將來,沒人會購買不帶移動視頻和語音識別這類多媒體特性的軟體產品。越複雜的系統就需要越高層次的抽象,面向對象范型就提供了這一抽象。這不是軟體開發的革命,只是正常的演進。
第2章討論了類和對象的概念,它們是面向對象技術的基石。我們把類和對象看作數據及其相關行為的封裝,數據和行為的關係是雙向的。我們通過現實世界中的例子探討了傳送訊息、定義方法、設計協定的表示法。從這個章節開始陸續列出經驗原則。因為到本章為止我們只接觸了面向對象范型的一個小小子集,所以這些經驗原則是較為簡單的,但這並不意味著它們的用處小於稍後章節出現的較複雜的經驗原則。
第3章探討了面向動作和面向對象布局之間的不同。方法學的不同布局昭示了面向對象開發的核心真理。面向動作的開發在很大程度上專注於對任務集合的控制,這些任務是通過功能分解的,控制機制是“中央集權”式的;而面向對象的開發則專注於分散式的互動實體集。我確信,這一“范型遷移”意味著思考方式從集中式模型到分散式模型的轉變。對於我們這些成長於面向動作開發世界的人來說,面向對象開發的學習曲線也就是面向動作開發的遺忘曲線。我們生活的現實世界更接近於對象模型,而非集中控制機制影響下的模型。很容易看出哪些系統的開發者的思維范型尚未遷移:如果系統中有一個位居中央的全能對象,其他對象都退居次要,那么這樣的系統是由依然執著於面向動作布局的開發者創建的。本章提出了很多經驗原則,用來指導應用程式布局的最佳化。
第4章到第7章通過一系列現實世界中的例子探討了5個主要的面向對象關係:使用(第4章)、包含(第4章)、單繼承(第5章)、多繼承(第6章)、關聯(第7章)。面向對象設計者感興趣的大多數經驗原則都可以在這些章節中找到。關於繼承的章節包含了很多常見的誤用繼承關係的例子。對減少“泛濫成災的類”的問題(比如為——個特定的套用設計了太多的類)而言,這些信息至關重要。“泛濫成災的類”的問題是面向對象開發失敗的主要原因之一。
第8章探討了與類相關的數據和行為,這和與對象相關的數據和行為相對。發票類被用作需要與類相關的數據和行為的抽象的例子。我們既描述了SmallTalk元類也描述了C++的關鍵字機制。此外,我們還比較了C++元類(也即模板)和SmallTalk的元類表示法。
第9章討論了在開發面向對象系統中面向對象物理設計的角色。雖然關於物理設計有很多可以說的,但很多都和面向動作范型中討論過的東西是重複的。比如,已經有大量文獻詳細討論了高效實現的粒度問題(例如,為了提高應用程式的速度,在逐條檢測語句之前,請先考慮:替換硬體、替換編譯器、替換機制、替換算法)。因此,本書中討論的物理設計問題要么是只有面向對象范型中才存在的,要么是面向對象范型提供了特殊解決方案的。其中包含:把不友好的(比如,非面向對象的)子系統同面向對象的問題域隔離開的軟體包裝層、空間持久性和時間持久性、面向對象資料庫管理系統和關係資料庫管理系統、記憶體管理和垃圾收集、引用計數、最小公有接口、並行面向對象編程以及用非面向對象語言實現面向對象設計。
1987年,我參加了OOPSLA會議的一個小型研討會,會上討論了面向對象范型的過去、今天和未來。在會議上,KentBeck談及了Christopher Alexander在建築學領域發表的論文。Alexander認為,所有的建築都有“無名的質”,他試圖用稱為“模式”的實體來表述這些“無名的質”。Kent論及了尋找模式(也即已知問題的獨立於領域的解決方案,或者面向對象構架中的有趣結構)的可能性。近來,大量研究正在這個領域展開,模式已經成為對象群體的最活躍前沿。於是,我不得不問自己:“經驗原則和模式之間有什麼關係?”顯然,兩者是相關的,因為尋找它們的方式是類似的。我們研究任何一個在許多不同領域出現的結構或問題,然後試圖用經驗原則或者設計模式的格式來封裝該實體。本書第10章討論了設計模式和它們同設計經驗原則之間的關係。我相信,模式和經驗原則之間最有趣的關係是:經驗原則可以告訴設計者,何時該用幾個設計模式中的某一個了。對普通的設計者而言,模式的尺度超過了能靠直覺掌握的範圍,而經驗原則則正好相反,它們很少超過兩句話的長度,而且很易於套用。這兩者組合起來可以發揮很大的效力。本章也描述了一些設計模式和經驗原則共同具備的有趣特性。
本書中前面幾個例子可能微不足道,或者不屬於計算機科學的領域,但請讀者不要一上來就大加鞭撻。在我的講座中,常常會聽到一小部分參與者不久就開始抱怨,他們低聲說:“這些信息毫無用處,因為我不會去編寫水果籃、有尾巴的狗或者鬧鐘。”既然本書中很大一部分討論的是現實世界中的日常事項,那么我可以給出一個合理的解釋:如果設計經驗原則和模式確實是獨立於領域的,那么我為何不選擇一個簡單的領域來講授它們呢?在我曾講授過的設計課程中,我常常會聽到某個設計小組大口q:“這是蘋果去核問題”或者“這是具有可選尾巴的狗的問題”。一旦理解了一條經驗原則,那么如何把它的運用擴展到別的領域就很簡單了,不管那個領域有多複雜。
我把第11章納入本書,這是為那些想看到更具“真材實料”的設計例子的人準備的。第11章圍繞自動櫃員機(ATM)展開講了一些分析和設計問題。很多敘述面向對象范型的不同書籍都使用了ATM的例子。我選擇這個例子,是因為讀者對它很熟悉,而且這個例子在更加“計算機科學化”的領域中描述了設計經驗原則和模式的使用。此外,因為這是一個分散式系統(ATM和銀行位於不同的地域),所以我可以在這個例子中描述稱為“用代理設計” (design with proxies)的設計技法。這種設計技法使得系統構架師在進行邏輯設計時可以忽略應用程式的分布特性,把這些問題推遲到設計後期。這很重要,因為很多分散式系統的設計缺陷的原因都可以歸結為在邏輯設計完成前就考慮分散式處理。
最後,我要說的是,在我的所有課程上,都注意到班級分成了兩撥人。一撥人喜歡在抽象領域中生活,他們為了設計而討論設計,很少討論實現的問題。另一撥人則難以理解抽象的東西,但是如果你把一段代碼拿給他們看,他們很快就會領會討論的要點。當本書交付審閱時,我請每一位審閱者都指出,這本書是否應當用C++實現描述設計實例。兩位審閱者說,顯然這本書需要那些C++例子,如果沒有這些例子的話讀者會很難理解那些抽象的概念。另外兩位審閱者則說,這是一本關於設計的書,因此同C++或者別的程式語言沒有關係。還有兩位審閱者則站在相對中立的位置。這樣,我就面臨著顯而易見的二難困境,無法讓所有人都感到滿意。我的解決方法是,在正文後面列出了一系列精選的C++實現作為附錄,這些實現所對應的設計例子則在正文中的章節討論。如果你是個抽象主義者,那么你不讀附錄就可以了:如果你習慣於通過研究對抽象概念的實現來學習(在多數時間裡我也是這樣的),那么你或許會想要研究附錄中特定設計問題的實現。這種安排沒有用代碼擾亂正文中對設計的陳述,我希望這種安排也能讓期待看到實現代碼的人滿意。
請注意:所有C++例子都在奔騰100MHz的IBMPC兼容機上用Borland C++4.5編譯測試通過。你常用的C++編譯器也應該可以毫無問題地編譯這些例子。

相關搜尋

熱門詞條

聯絡我們