<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                #面向對象六大原則 ##概述 在工作初期,我們可能會經常會有這樣的感覺,自己的代碼接口設計混亂、代碼耦合較為嚴重、一個類的代碼過多等等,自己回頭看的時候都覺得汗顏。再看那些知名的開源庫,它們大多有著整潔的代碼、清晰簡單的接口、職責單一的類,這個時候我們通常會捶胸頓足而感嘆:什么時候老夫才能寫出這樣的代碼! ##相關資料 ###iOS [AFNetworking2.0源碼解析](http://blog.cnbang.net/tech/2320/) [AFNetworking源碼](https://github.com/AFNetworking/AFNetworking) ##單一原則(Single Responsibility Principle) ###簡述 SRP:就一個類而言,應該僅有一個引起它變化的原因。 單一職責的劃分界限并不是如馬路上的行車道那么清晰,很多時候都是需要靠個人經驗來界定。當然最大的問題就是對職責的定義,什么是類的職責,以及怎么劃分類的職責。**如果一個類承擔的職責過多,就等于把這些職責耦合在一起,一個職責的變化可能會削弱或者抑制這個類完成其他職責的能力。這種耦合會導致脆弱的設計,當變化發生時,設計會遭受到意想不到的破壞**。 **當然,軟件設計真正要做的許多內容,就是發現職責并把那些職責相互分離,就是抽象的能力。其實要去判斷是否應該分離出類來,也不難,那就是如果你能想到多于一個的動機去改變一個類,那么這個類就具有多于一個的職責**。 ###示例 /** * An HTTP stack abstraction. */ public interface HttpStack { /** * 執行Http請求,并且返回一個HttpResponse */ public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; } HttpStack中這個函數的職責就是執行網絡請求并且返回一個Response。它的職責很單一,這樣在需要修改執行網絡請求的相關代碼時我們只需要修改實現HttpStack接口的類,而不會影響其它的類的代碼。如果某個類的職責包含有執行網絡請求、解析網絡請求、進行gzip壓縮、封裝請求參數等等,那么在你修改某處代碼時你就必須謹慎,以免修改的代碼影響了其它的功能。但是當職責單一的時候,你修改的代碼能夠基本上不影響其它的功能。這就在一定程度上保證了代碼的可維護性。**注意,單一職責原則并不是說一個類只有一個函數,而是說這個類中的函數所做的工作必須要是高度相關的,也就是高內聚**。 ##里氏替換原則(Liskov Substitution Principle) ###簡述 肯定有不少人跟我剛看到這項原則的時候一樣,對這個原則的名字充滿疑惑。其實原因就是這項原則最早是在1988年,由麻省理工學院的一位姓里的女士(Barbara Liskov)提出來的。 定義1:如果對每一個類型為 T1的對象 o1,都有類型為 T2 的對象o2,使得以 T1定義的所有程序 P 在所有的對象 o1 都代換成 o2 時,程序 P 的行為沒有發生變化,那么類型 T2 是類型 T1 的子類型。 定義2:所有引用基類的地方必須能透明地使用其子類的對象。 問題由來:有一功能P1,由類A完成。現需要將功能P1進行擴展,擴展后的功能為P,其中P由原有功能P1與新功能P2組成。新功能P由類A的子類B來完成,則子類B在完成新功能P2的同時,有可能會導致原有功能P1發生故障。 解決方案:當使用繼承時,遵循里氏替換原則。類B繼承類A時,除添加新的方法完成新增功能P2外,盡量不要重寫父類A的方法,也盡量不要重載父類A的方法。 繼承包含這樣一層含義:**父類中凡是已經實現好的方法(相對于抽象方法而言),實際上是在設定一系列的規范和契約,雖然它不強制要求所有的子類必須遵從這些契約,但是如果子類對這些非抽象方法任意修改,就會對整個繼承體系造成破壞。而里氏替換原則就是表達了這一層含義**。 **繼承作為面向對象三大特性之一,在給程序設計帶來巨大便利的同時,也帶來了弊端。比如使用繼承會給程序帶來侵入性,程序的可移植性降低,增加了對象間的耦合性,如果一個類被其他的類所繼承,則當這個類需要修改時,必須考慮到所有的子類,并且父類修改后,所有涉及到子類的功能都有可能會產生故障**。 里氏替換原則通俗的來講就是:子類可以擴展父類的功能,但不能改變父類原有的功能。它包含以下4層含義: * 子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法。 * 子類中可以增加自己特有的方法。 * 當子類的方法重載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬松。 * 當子類的方法實現父類的抽象方法時,方法的后置條件(即方法的返回值)要比父類更嚴格。 ###示例 還是以HttpStack為例,Volley定義了HttpStack來表示執行網絡請求這個抽象概念。在執行網絡請求時,我們只需要定義一個HttpStack對象,然后調用performRequest即可。至于HttpStack的具體實現由更高層的調用者給出。示例如下 : ``` public static RequestQueue newRequestQueue(Context context, HttpStack stack) { File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); String userAgent = "volley/0"; // 代碼省略 // 1、構造HttpStack對象 if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { // Prior to Gingerbread, HttpUrlConnection was unreliable. // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } // 2、將HttpStack對象傳遞給Network對象 Network network = new BasicNetwork(stack); // 3、將network對象傳遞給網絡請求隊列 RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start(); return queue; } ``` BasicNetwork的代碼如下: ``` /** * A network performing Volley requests over an {@link HttpStack}. */ public class BasicNetwork implements Network { // HttpStack抽象對象 protected final HttpStack mHttpStack; protected final ByteArrayPool mPool; public BasicNetwork(HttpStack httpStack) { this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE)); } public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) { mHttpStack = httpStack; mPool = pool; } } ``` 上述代碼中,BasicNetwork構造函數依賴的是HttpStack抽象接口,任何實現了HttpStack接口的類型都可以作為參數傳遞給BasicNetwork用以執行網絡請求。這就是所謂的里氏替換原則,任何父類出現的地方子類都可以出現,這不就保證了可擴展性嗎? ###減少LSP妨礙 ####契約(Contracts) 處理 LSP 過分妨礙的一個策略是使用契約,契約清單有 2 種形式:執行說明書(executable specifications)和錯誤處理,在執行說明書里,一個詳細類庫的契約也包括一組自動化測試,而錯誤處理是在代碼里直接處理的,例如在前置條件,后置條件,常量檢查等,可以從 Bertrand Miller 的大作《契約設計》中查看這個技術。雖然自動化測試和契約設計不在本篇文字的范圍內,但當我們用的時候我還是推薦如下內容: 檢查使用測試驅動開發(Test-Driven Development)來指導你代碼的設計 設計可重用類庫的時候可隨意使用契約設計技術 對于你自己要維護和實現的代碼,使用契約設計趨向于添加很多不必要的代碼,如果你要控制輸入,添加測試是非常有必要的,如果你是類庫作者,使用契約設計,你要注意不正確的使用方法以及讓你的用戶使之作為一個測試工具。 契約(Contracts) 處理 LSP 過分妨礙的一個策略是使用契約,契約清單有 2 種形式:執行說明書(executable specifications)和錯誤處理,在執行說明書里,一個詳細類庫的契約也包括一組自動化測試,而錯誤處理是在代碼里直接處理的,例如在前置條件,后置條件,常量檢查等,可以從 Bertrand Miller 的大作《契約設計》中查看這個技術。雖然自動化測試和契約設計不在本篇文字的范圍內,但當我們用的時候我還是推薦如下內容: 檢查使用測試驅動開發(Test-Driven Development)來指導你代碼的設計 設計可重用類庫的時候可隨意使用契約設計技術 對于你自己要維護和實現的代碼,使用契約設計趨向于添加很多不必要的代碼,如果你要控制輸入,添加測試是非常有必要的,如果你是類庫作者,使用契約設計,你要注意不正確的使用方法以及讓你的用戶使之作為一個測試工具。 ####避免繼承 避免 LSP 妨礙的另外一個測試是:如果可能的話,盡量不用繼承,在Gamma的大作《Design Patterns – Elements of Reusable Object-Orineted Software》中,我們可以看到如下建議: Favor object composition over class inheritance 盡量使用對象組合而不是類繼承 有些書里討論了組合比繼承好的唯一作用是靜態類型,基于類的語言(例如,在運行時可以改變行為),與 JavaScript 相關的一個問題是耦合,當使用繼承的時候,繼承子類型和他們的基類型耦合在一起了,就是說基類型的改變會影響到繼承子類型。組合傾向于對象更小化,更容易向靜態和動態語言語言維護。 與行為有關,而不是繼承 到現在,我們討論了和繼承上下文在內的里氏替換原則,指示出 JavaScript 的面向對象實。不過,里氏替換原則(LSP)的本質不是真的和繼承有關,而是行為兼容性。JavaScript 是一個動態語言,一個對象的契約行為不是對象的類型決定的,而是對象期望的功能決定的。里氏替換原則的初始構想是作為繼承的一個原則指南,等價于對象設計中的隱式接口。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看