<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                6.4 如何使用開閉原則 開閉原則是一個非常虛的原則,前面5個原則是對開閉原則的具體解釋,但是開閉原則并不局限于這么多,它“虛”得沒有邊界,就像“好好學習,天天向上”的口號一樣,告訴我們要好好學習,但是學什么,怎么學并沒有告訴我們,需要去體會和掌握,開閉原則也是一個口號,那我們怎么把這個口號應用到實際工作中呢? 1. 抽象約束 抽象是對一組事物的通用描述,沒有具體的實現,也就表示它可以有非常多的可能性,可以跟隨需求的變化而變化。因此,通過接口或抽象類可以約束一組可能變化的行為,并且能夠實現對擴展開放,其包含三層含義:第一,通過接口或抽象類約束擴展,對擴展進行邊界限定,不允許出現在接口或抽象類中不存在的public方法;第二,參數類型、引用對象盡量使用接口或者抽象類,而不是實現類;第三,抽象層盡量保持穩定,一旦確定即不允許修改。還是以書店為例,目前只是銷售小說類書籍,單一經營畢竟是有風險的,于是書店新增加了計算機書籍,它不僅包含書籍名稱、作者、價格等信息,還有一個獨特的屬性:面向的是什么領域,也就是它的范圍,比如是和編程語言相關的,還是和數據庫相關的,等等,修改后的類圖如圖6-3所示。 ![](https://box.kancloud.cn/2016-08-14_57b0035fd548e.jpg) 圖6-3 增加業務品種后的書店售書類圖 增加了一個接口IComputerBook和實現類Computer- Book,而BookStore不用做任何修改就可以完成書店銷售計算機書籍的業務。計算機書籍接口如代碼清單6-8所示。 代碼清單6-8 計算機書籍接口 public?interface?IComputerBook?extends?IBook{?????? ?????//計算機書籍是有一個范圍 ?????public?String?getScope(); } 很簡單,計算機書籍增加了一個方法,就是獲得該書籍的范圍,同時繼承IBook接口,畢竟計算機書籍也是書籍,其實現如代碼清單6-9所示。 代碼清單6-9 計算機書籍類 public?class?ComputerBook?implements?IComputerBook?{ ?????private?String?name; ?????private?String?scope; ?????private?String?author; ?????private?int?price;? ?????public?ComputerBook(String?_name,int?_price,String?_author,String?_scope){ ?????????????this.name=_name; ?????????????this.price?=?_price; ?????????????this.author?=?_author; ?????????????this.scope?=?_scope; ?????} ?????public?String?getScope()?{ ?????????????return?this.scope; ?????} ?????public?String?getAuthor()?{ ?????????????return?this.author; ?????} ?????public?String?getName()?{ ?????????????return?this.name; ?????} ?????public?int?getPrice()?{ ?????????????return?this.price; ?????} } 這也很簡單,實現IComputerBook就可以,而BookStore類沒有做任何的修改,只是在static靜態模塊中增加一條數據,如代碼清單6-10所示。 代碼清單6-10 書店銷售計算機書籍 public?class?BookStore?{ ?????private?final?static?ArrayList<IBook>?bookList?=?new?ArrayList<IBook>(); ?????//static靜態模塊初始化數據,實際項目中一般是由持久層完成 ?????static{ ?????????????bookList.add(new?NovelBook("天龍八部",3200,"金庸")); ?????????????bookList.add(new?NovelBook("巴黎圣母院",5600,"雨果")); ?????????????bookList.add(new?NovelBook("悲慘世界",3500,"雨果")); ?????????????bookList.add(new?NovelBook("金瓶梅",4300,"蘭陵笑笑生")); ?????????????//增加計算機書籍 ?????????????bookList.add(new?ComputerBook("Think?in?Java",4300,"Bruce?Eckel","編程語言")); ?????}?? ?????//模擬書店賣書 ?????public?static?void?main(String[]?args)?{ ?????????????NumberFormat?formatter?=?NumberFormat.getCurrencyInstance(); ?????????????formatter.setMaximumFractionDigits(2); ?????????????System.out.println("-----------書店賣出去的書籍記錄如下:-----------"); ?????????????for(IBook?book:bookList){ ???????????????????????System.out.println("書籍名稱:"?+?book.getName()+"\t書籍作者:"?+?book.getAuthor()+?"\t書籍價格:"?+?formatter.format?(book.getPrice()/100.0)+"元"); ?????????????} ?????} } 書店開始銷售計算機書籍,運行結果如下所示。 --------------------書店賣出去的書籍記錄如下:--------------------- 書籍名稱:天龍八部    書籍作者:金庸     書籍價格:¥32.00元 書籍名稱:巴黎圣母院   書籍作者:雨果     書籍價格:¥56.00元 書籍名稱:悲慘世界    書籍作者:雨果     書籍價格:¥35.00元 書籍名稱:金瓶梅     書籍作者:蘭陵笑笑生  書籍價格:¥43.00元 書籍名稱:Think in Java   書籍作者:Bruce Eckel   書籍價格:¥43.00元 如果我是負責維護的,我就非常樂意做這樣的事情,簡單而且不需要與其他的業務進行耦合。我唯一需要做的事情就是在原有的代碼上添磚加瓦,然后就可以實現業務的變化。我們來看看這段代碼有哪幾層含義。 首先,ComputerBook類必須實現IBook的三個方法,是通過IComputerBook接口傳遞進來的約束,也就是我們制定的IBook接口對擴展類ComputerBook產生了約束力,正是由于該約束力,BookStore類才不需要進行大量的修改。 其次,如果原有的程序設計采用的不是接口,而是實現類,那會出現什么問題呢?我們把 BookStore類中的私有變量bookList修改一下,如下面的代碼所示。 private?final?static?ArrayList<NovelBook>?bookList?=?new?ArrayList<NovelBook>(); 把原有IBook的依賴修改為對NovelBook實現類的依賴,想想看,我們這次的擴展是否還能繼續下去呢?一旦這樣設計,我們就根本沒有辦法擴展,需要修改原有的業務邏輯(也就是main方法),這樣的擴展基本上就是形同虛設。 最后,如果我們在IBook上增加一個方法getScope,是否可以呢?答案是不可以,因為原有的實現類NovelBook已經在投產運行中,它不需要該方法,而且接口是與其他模塊交流的契約,修改契約就等于讓其他模塊修改。因此,接口或抽象類一旦定義,就應該立即執行,不能有修改接口的思想,除非是徹底的大返工。 所以,要實現對擴展開放,首要的前提條件就是抽象約束。 2. 元數據(metadata)控制模塊行為 編程是一個很苦很累的活,那怎么才能減輕我們的壓力呢?答案是盡量使用元數據來控制程序的行為,減少重復開發。什么是元數據?用來描述環境和數據的數據,通俗地說就是配置參數,參數可以從文件中獲得,也可以從數據庫中獲得。舉個非常簡單的例子,login方法中提供了這樣的邏輯:先檢查IP地址是否在允許訪問的列表中,然后再決定是否需要到數據庫中驗證密碼(如果采用SSH架構,則可以通過Struts的攔截器來實現),該行為就是一個典型的元數據控制模塊行為的例子,其中達到極致的就是控制反轉(Inversion of Control),使用最多的就是Spring容器,在SpringContext配置文件中,基本配置如代碼清單6-11所示。 代碼清單6-11 SpringContext的基本配置文件 <bean?id="father"?class="xxx.xxx.xxx.Father"?/> <bean?id="xx"?class="xxx.xxx.xxx.xxx"> ?????????<property?name="biz"?ref="father"></property> </bean> 然后,通過建立一個Father類的子類Son,完成一個新的業務,同時修改SpringContext文件,修改后的文件如代碼清單6-12所示。 代碼清單6-12 擴展后的SpringContext配置文件 <bean?id="son"?class="xxx.xxx.xxx.Son"?/> <bean?id="xx"?class="xxx.xxx.xxx.xxx"> ????????<property?name="biz"?ref="son"></property> </bean> 通過擴展一個子類,修改配置文件,完成了業務變化,這也是采用框架的好處。 3. 制定項目章程 在一個團隊中,建立項目章程是非常重要的,因為章程中指定了所有人員都必須遵守的約定,對項目來說,約定優于配置。相信大家都做過項目,會發現一個項目會產生非常多的配置文件。舉個簡單的例子,以SSH項目開發為例,一個項目中的Bean配置文件就非常多,管理非常麻煩。如果需要擴展,就需要增加子類,并修改SpringContext文件。然而,如果你在項目中指定這樣一個章程:所有的Bean都自動注入,使用Annotation進行裝配,進行擴展時,甚至只用寫一個子類,然后由持久層生成對象,其他的都不需要修改,這就需要項目內約束,每個項目成員都必須遵守,該方法需要一個團隊有較高的自覺性,需要一個較長時間的磨合,一旦項目成員都熟悉這樣的規則,比通過接口或抽象類進行約束效率更高,而且擴展性一點也沒有減少。 4. 封裝變化 對變化的封裝包含兩層含義:第一,將相同的變化封裝到一個接口或抽象類中;第二,將不同的變化封裝到不同的接口或抽象類中,不應該有兩個不同的變化出現在同一個接口或抽象類中。封裝變化,也就是受保護的變化(protected variations),找出預計有變化或不穩定的點,我們為這些變化點創建穩定的接口,準確地講是封裝可能發生的變化,一旦預測到或“第六感”發覺有變化,就可以進行封裝,23個設計模式都是從各個不同的角度對變化進行封裝的,我們會在各個模式中逐步講解。
                  <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>

                              哎呀哎呀视频在线观看