<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國際加速解決方案。 廣告
                第19章 適配器模式 19.1 業務發展——上帝才能控制 有這樣一句名言:“智者千慮必有一失,愚者千慮必有一得”[[1]](#),意思是說不管多聰明的人,經過多少次的思考,也總是會出現一些微小的錯誤,“智者”都是如此,何況我們這些平庸之輩呢!我們在進行系統開發時,不管之前的可行性分析、需求分析、系統設計處理得多么完美,總會在關鍵時候、關鍵場合出現一些“意外”。對于這些“意外”,該來的還是要來,躲是躲不過去的,那我們怎么來彌補這些“意外”呢?這難不倒我們的設計大師,他們創造出了一些補救模式,今天我們就來講一個補救模式,這種模式可以讓你從因業務擴展而系統無法迅速適應的苦惱中解脫而出。 2004年我帶了一個項目,做一個人力資源管理項目,該項目是我們總公司發起的,公司一共有700多號人。這個項目還是比較簡單的,分為三大模塊:人員信息管理、薪酬管理、職位管理。當時開發時業務人員明確指明:人員信息管理的對象是所有員工的所有信息,所有的員工指的是在職的員工,其他的離職的、退休的暫不考慮。根據需求我們設計了如圖19-1所示的類圖。 ![](https://box.kancloud.cn/2016-08-14_57b00365e7d63.jpg) 圖19-1 人員信息類圖 非常簡單,有一個對象UserInfo存儲用戶的所有信息(實際系統上還有很多子類,不多說了),也就是BO(Business Object,業務對象),這個對象設計為貧血對象(Thin Business Object),不需要存儲狀態以及相關的關系,本人是反對使用充血對象(Rich Business Object),這里提到兩個名詞:貧血對象和充血對象,這兩個名詞很簡單,在領域模型中分別叫做貧血領域模型和充血領域模型,有什么區別呢?一個對象如果不存儲實體狀態以及對象之間的關系,該對象就叫做貧血對象,對應的領域模型就是貧血領域模型,有實體狀態和對象關系的模型就是充血領域模型。看不懂沒關系,都是糊弄人的東西,屬于專用名詞。扯遠了,我們繼續說我們的人力資源管理項目,這個UserInfo對象,在系統中很多地方使用,你可以查看自己的信息,也可以修改,當然這個對象是有setter方法的,我們這里用不到就隱藏掉了。先來看接口,員工信息接口如代碼清單19-1所示。 代碼清單19-1 員工信息接口 public?interface?IUserInfo?{ ?????//獲得用戶姓名 ?????public?String?getUserName(); ?????//獲得家庭地址 ?????public?String?getHomeAddress(); ?????//手機號碼,這個太重要,手機泛濫呀 ?????public?String?getMobileNumber(); ?????//辦公電話,一般是座機 ?????public?String?getOfficeTelNumber(); ?????//這個人的職位是什么 ?????public?String?getJobPosition(); ?????//獲得家庭電話,這有點不好,我不喜歡打家庭電話討論工作 ?????public?String?getHomeTelNumber(); } 員工信息接口有了,就需要設計一個實現類來容納數據,如代碼清單19-2所示。 代碼清單19-2 實現類 public?class?UserInfo?implements?IUserInfo?{ ?????/*? ??????*?獲得家庭地址,下屬送禮也可以找到地方 ??????*/ ?????public?String?getHomeAddress()?{ ?????????????System.out.println("這里是員工的家庭地址..."); ?????????????return?null; ?????} ?????/*? ??????*?獲得家庭電話號碼 ??????*/ ?????public?String?getHomeTelNumber()?{ ?????????????System.out.println("員工的家庭電話是..."); ?????????????return?null; ?????} ?????/*? ??????*?員工的職位,是部門經理還是普通職員 ??????*/ ?????public?String?getJobPosition()?{ ?????????????System.out.println("這個人的職位是BOSS..."); ?????????????return?null; ?????} ?????/*? ??????*?手機號碼 ??????*/ ?????public?String?getMobileNumber()?{ ?????????????System.out.println("這個人的手機號碼是0000..."); ?????????????return?null; ?????} ?????/*? ??????*?辦公室電話,煩躁的時候最好"不小心"把電話線踢掉 ??????*/ ?????public?String?getOfficeTelNumber()?{ ?????????????System.out.println("辦公室電話是..."); ?????????????return?null; ?????} ?????/*? ??????*?姓名,這個很重要 ??????*/ ?????public?String?getUserName()?{ ?????????????System.out.println("姓名叫做..."); ?????????????return?null; ?????} } 這個項目是2004年年底投產的,運行到2005年年底還是比較平穩的,中間修修補補也很正常,2005年年底不知道是哪股風吹的,很多公司開始使用借聘人員的方式引進人員,我們公司也不例外,從一個勞動資源公司借用了一大批的低技術、低工資的人員,分配到各個子公司,總共有將近200人,然后人力資源部就找我們部門老大談判,說要增加一個功能:借用人員管理,老大一看有錢賺呀,一拍大腿,做! 老大命令一下來,我立馬帶人過去調研,需求就一句話,但是真深入地調研還真不是那么簡單。借聘人員雖然在我們公司干活,和我們一個樣,干活時沒有任何的差別,但是他們的人員信息、工資情況、福利情況等都是由勞動服務公司管理的,并且有一套自己的人員管理系統,人力資源部門就要求我們系統同步勞動服務公司的信息,當然是只要在我們公司工作的人員信息,其他人員信息是不需要的,而且還要求信息同步,也就是:勞動服務公司的人員信息一變更,我們系統就應該立刻體現出來,為什么要即時而不批量呢?是因為我們公司與勞動服務公司之間是按照人頭收費的,甭管是什么人,只要我們公司借用,就這個價格,我要一個研究生,你派了一個高中生給我,那算什么事?因此,了解了業務需求用后,項目組決定采用RMI(Remote Method Invocation,遠程對象調用)的方式進行聯機交互,但是深入分析后,一個重大問題立刻顯現出來:勞動服務公司的人員對象和我們系統的對象不相同,他們的對象如下所示。 ![](https://box.kancloud.cn/2016-08-14_57b0036608a21.jpg) 圖19-2 勞動服務公司的人員信息類圖 勞動服務公司是把人員信息分為了三部分:基本信息、辦公信息和個人家庭信息,并且都放到了HashMap中,比如人員的姓名放到BaseInfo信息中,家庭地址放到HomeInfo中,這也是一個可以接受的模式,我們來看看他們的代碼,接口如代碼清單19-3所示。 代碼清單19-3 勞動服務公司的人員信息接口 public?interface?IOuterUser?{?????? ?????//基本信息,比如名稱、性別、手機號碼等 ?????public?Map?getUserBaseInfo(); ?????//工作區域信息 ?????public?Map?getUserOfficeInfo(); ?????//用戶的家庭信息 ?????public?Map?getUserHomeInfo(); } 勞動服務公司的人員信息是這樣存放的,如代碼清單19-4所示。 代碼清單19-4 勞動服務公司的人員實現 public?class?OuterUser?implements?IOuterUser?{ ?????/*? ??????*?用戶的基本信息 ??????*/ ?????public?Map?getUserBaseInfo()?{ ?????????????HashMap?baseInfoMap?=?new?HashMap(); ?????????????baseInfoMap.put("userName",?"這個員工叫混世魔王..."); ?????????????baseInfoMap.put("mobileNumber",?"這個員工電話是..."); ?????????????return?baseInfoMap; ?????} ?????/*? ??????*?員工的家庭信息 ??????*/ ?????public?Map?getUserHomeInfo()?{ ?????????????HashMap?homeInfo?=?new?HashMap(); ?????????????homeInfo.put("homeTelNumbner",?"員工的家庭電話是..."); ?????????????homeInfo.put("homeAddress",?"員工的家庭地址是..."); ?????????????return?homeInfo; ?????} ?????/*? ??????*?員工的工作信息,比如,職位等 ??????*/ ?????public?Map?getUserOfficeInfo()?{ ?????????????HashMap?officeInfo?=?new?HashMap(); ?????????????officeInfo.put("jobPosition","這個人的職位是BOSS..."); ?????????????officeInfo.put("officeTelNumber",?"員工的辦公電話是..."); ?????????????return?officeInfo; ?????} } 看到這里,咱不好說他們系統設計得不好,問題是咱的系統要和他們的系統進行交互,怎么辦?我們不可能為了這一小小的功能而對我們已經運行良好系統進行大手術,那怎么辦?我們可以轉化,先拿到對方的數據對象,然后轉化為我們自己的數據對象,中間加一層轉換處理,按照這個思路,我們設計了如圖19-3所示的類圖。 ![](https://box.kancloud.cn/2016-08-14_57b003661c6f5.jpg) 圖19-3 增加了中轉處理的人員信息類圖 大家可能會問,這兩個對象都不在一個系統中,你如何使用呢?簡單!RMI已經幫我們做了這件事情,只要有接口,就可以把遠程的對象當成本地的對象使用,這個大家有時間可以去看一下RMI文檔,不多說了。OuterUserInfo可以看做是“兩面派”,實現了IUserInfo接口,還繼承了OuterUser,通過這樣的設計,把OuterUser偽裝成我們系統中一個IUserInfo對象,這樣,我們的系統基本不用修改,所有的人員查詢、調用跟本地一樣。 注意 我們之所以能夠增加一個OuterUserInfo中轉類,是因為我們在系統設計時嚴格遵守了依賴倒置原則和里氏替換原則,否則即使增加了中轉類也無法解決問題。 說得口干舌燥,下邊我們來看具體的代碼實現,中轉角色OuterUserInfo如代碼清單19-5所示。 代碼清單19-5 中轉角色 public?class?OuterUserInfo?extends?OuterUser?implements?IUserInfo?{ ?????private?Map?baseInfo?=?super.getUserBaseInfo();??//員工的基本信息 ?????private?Map?homeInfo?=?super.getUserHomeInfo();?//員工的家庭信息 ?????private?Map?officeInfo?=?super.getUserOfficeInfo();?//工作信息 ?????/*? ??????*?家庭地址 ??????*/ ?????public?String?getHomeAddress()?{ ?????????????String?homeAddress?=?(String)this.homeInfo.get("homeAddress"); ?????????????System.out.println(homeAddress); ?????????????return?homeAddress; ?????} ?????/*? ??????*?家庭電話號碼 ??????*/ ?????public?String?getHomeTelNumber()?{ ?????????????String?homeTelNumber?=?(String)this.homeInfo.get("homeTelNumber"); ?????????????System.out.println(homeTelNumber); ?????????????return?homeTelNumber; ?????} ?????/*? ??????*職位信息 ??????*/ ?????public?String?getJobPosition()?{ ?????????????String?jobPosition?=?(String)this.officeInfo.get("jobPosition"); ?????????????System.out.println(jobPosition); ?????????????return?jobPosition; ?????} ?????/*? ??????*?手機號碼 ??????*/ ?????public?String?getMobileNumber()?{ ?????????????String?mobileNumber?=?(String)this.baseInfo.get("mobileNumber"); ?????????????System.out.println(mobileNumber); ?????????????return?mobileNumber; ?????} ?????/*? ??????*?辦公電話 ??????*/ ?????public?String?getOfficeTelNumber()?{ ?????????????String?officeTelNumber?=?(String)this.officeInfo.get("officeTelNumber"); ?????????????System.out.println(officeTelNumber); ?????????????return?officeTelNumber; ?????} ?????/*? ??????*?員工的名稱 ??????*/ ?????public?String?getUserName()?{ ?????????????String?userName?=?(String)this.baseInfo.get("userName"); ?????????????System.out.println(userName); ?????????????return?userName; ?????} } 大家看到沒?中轉的角色有很多的強制類型轉換,就是(String)這個東西,如果使用泛型的話,就可以完全避免這個轉化(當然了,泛型當時還沒有誕生)。我們要看看這個中轉是否真的起到了中轉的作用,我們想象這樣一個場景:公司大老板想看看我們自己公司年輕女孩子的電話號碼,那該場景類就如代碼清單19-6所示。 代碼清單19-6 場景類 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????//沒有與外系統連接的時候,是這樣寫的 ?????????????IUserInfo?youngGirl?=?new?UserInfo(); ?????????????//從數據庫中查到101個 ?????????????for(int?i=0;i<101;i++){ ????????????????????youngGirl.getMobileNumber(); ?????????????} ?????} } 這老板比較色呀。從數據庫中生成了101個UserInfo對象,直接打印出來就成了。老板回頭一想,不對呀,兔子不吃窩邊草,還是調取借用人員看看,于是要查詢出借用人員中美女的電話號碼,如代碼清單19-7所示。 代碼清單19-7 查看勞動服務公司人員信息場景 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????//老板一想不對呀,兔子不吃窩邊草,還是找借用人員好點 ?????????????//我們只修改了這句話 ?????????????IUserInfo?youngGirl?=?new?OuterUserInfo();?? ?????????????//從數據庫中查到101個 ?????????????for(int?i=0;i<101;i++){ ????????????????????youngGirl.getMobileNumber(); ?????????????} ?????} } 大家看,使用了適配器模式只修改了一句話,其他的業務邏輯都不用修改就解決了系統對接的問題,而且在我們實際系統中只是增加了一個業務類的繼承,就實現了可以查本公司的員工信息,也可以查人力資源公司的員工信息,盡量少的修改,通過擴展的方式解決了該問題。這就是適配模式。 [[1]](#)出自《史記·卷九十二》。
                  <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>

                              哎呀哎呀视频在线观看