基本套路
- 題目描述
- 往往非常簡單,如:設計一個XX系統。或者:你有沒有用過XXX,給你看一下它的界面和功能,你來設計一個。
- 闡述題意
- 面試者需向面試官詢問系統的具體要求。如,需要什么功能,需要承受的流量大小,是否需要考慮可靠性,容錯性等等。
- 面試者提供一個初步的系統設計
- 面試官這對初步的系統中提出一些后續的問題:如果要加某個功能怎么辦,如果流量大了怎么辦,如何考慮一致性,如果機器掛了怎么辦。
- 面試者根據面試官的后續問題逐步完善系統設計
- 完成面試
總體特點是以交流為主,畫圖和代碼為輔。
根據我們面試別人和參與面試的經驗,先從面試官的角度給出一些考量標準:
- 適應變化的需求(Adapt to the changing requirements )
- 設計干凈,優美,考慮周到的系統(Produce a system that is clean, elegant, well thought )
- 解釋為何這么實現(Explain why you choose this implementation )
- 對自己的能力水平很熟練(Be familiar with your experience level to make decisions )
- 在一些高層結構和復雜性方面有設計(Answer in high level of scale and complexity )
按照評分體系的化,分成下面4個等級
其實大家大可不必追求完美,在真正的面試中,沒有人能對答如流,往往面試官也會給出善意的提示,就算你沒回答某個子問題,在面試后的評價中也會綜合衡量,跟其他的面試者比較,最終打出一個分數
解題策略
Abstractions, Object and Decoupling
通常,關于OOP,面試官會讓面試者設計一個程序框架,該程序能夠實現一些特定的功能。比如,如何實現一個音樂播放器,如何設計一個車庫管理程序等等。對于此類問題,設計的關鍵過程一般包括抽象(abstraction),設計對象(object)和設計合理的層次/接口(decoupling)。這里,我們舉一個例子簡單說明這些過程分別需要做些什么,在“模式識別”給出更為具體和完整的實例。
繼承/組合/參數化類型
在面向對象中最常用的兩種代碼復用技術就是繼承和組合。在設計對象的時候,“Is-A”表示一種繼承關系。比如,班長“Is-A”學生,那么,學生就是基類,班長就是派生類。在確定了派生關系之后,我們需要分析什么是基類變量(base class variables)什么是子類變量(sub class variables),并由此確定基類和派生類之間的聯系。而“Has-A”表示一種從屬關系,這就是組合。比如,班長“Has-A”眼鏡,那就可以解釋為班長實例中擁有一個眼鏡實例變量(instance variable)。在具體實現的時候,班長類中定義一個眼鏡的基類指針。“在生成班長實例的時候,同時生成一個眼鏡實例,利用眼鏡的基類指針指向這個實例。任何關于眼鏡的操作函數都可以利用這個基類指針實現多態(polymorphism)。注意,多態是OOP相關的一個重要概念,也是面試常考的概念之一。關于多態的解釋請見“工具箱”。
在通常情況下,我們更偏向于“Has-A”的設計模式。因為該模式減少了兩個實例之間的相關性。對于繼承的使用,通常情況下我們會定義一個虛基類,由此派生出多個不同的實例類。在業界的程序開發中,多重繼承并不常見,Java甚至不允許從多個父類同時繼承,產生一個子類。
此外,我們還要提及參數化類型。參數化類型,或者說模版類也是一種有效的代碼復用技術。在C++的標準模版庫中大量應用了這種方式。例如,在定義一個List的變量時,List被另一個類型String所參數化。
設計模式著重于代碼的復用,所以在選擇復用技術上,有必要看看上述三種復用技術優劣。
繼承
- 通過繼承方式,子類能夠非常方便地改寫父類方法,同時
- 保留部分父類方法,可以說是能夠最快速地達到代碼復用。
- 繼承是在靜態編譯時候就定義了,所以無法再運行時刻改寫父類方法。
- 因為子類沒有改寫父類方法的話,就相當于依賴了父類這個方法的實現細節,被認為破壞封裝性。<