<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國際加速解決方案。 廣告
                第25章 訪問者模式 25.1 員工的隱私何在 我們在前面講過了組合模式和迭代器模式。通過組合模式能夠把一個公司的人員組織機構樹搭建起來,給管理帶來非常大的便利,通過迭代器模式把每一個員工都遍歷一遍,看看是不是 “有人去世了還在領退休金”,“拿高工資而不干活的尸位素餐”等情況,我們今天要做的就是把這些情況統計成一個報表呈報上去,讓領導看看這種惡劣的情況有多嚴重。 我們公司有700名多技術人員,分布在全國各地,組織架構在組合模式中已經介紹過了,是很常見的家長領導型模式,每個技術人員的崗位都是固定的,你在組織機構的哪棵樹下,充當的角色是什么,葉子節點都是非常明確的,每一個員工的信息(如名字、性別、薪水等)都是記錄在數據庫中,現在有這樣一個需求,我要把公司中的所有人員信息都打印匯報上去。我們來看類圖,如圖25-1所示。 ![](https://box.kancloud.cn/2016-08-14_57b00369ea922.jpg) 圖25-1 員工信息類圖 這個類圖還是比較簡單的,我們定義每個員工都有薪水salary、名稱name、性別sex這3個屬性,然后提供了一個抽象方法getOtherInfo由子類進行擴展,同時通過report方法打印出每一個員工的信息,這里使用模板方法模式。我們先來看一下抽象類,如代碼清單25-1所示。 代碼清單25-1 抽象員工 public?abstract?class?Employee?{ ?????public?final?static?int?MALE?=?0;??//0代表是男性 ?????public?final?static?int?FEMALE?=?1;?//1代表是女性 ?????//甭管是誰,都有工資 ?????private?String?name; ?????//只要是員工那就有薪水 ?????private?int?salary; ?????//性別很重要 ?????private?int?sex; ?????//以下是簡單的getter/setter ?????public?String?getName()?{ ?????????????return?name; ?????} ?????public?void?setName(String?name)?{ ?????????????this.name?=?name; ?????} ?????public?int?getSalary()?{ ?????????????return?salary; ?????} ?????public?void?setSalary(int?salary)?{ ?????????????this.salary?=?salary; ?????} ?????public?int?getSex()?{ ?????????????return?sex; ?????} ?????public?void?setSex(int?sex)?{ ?????????????this.sex?=?sex; ?????} ?????//打印出員工的信息 ?????public?final?void??report(){ ?????????????String?info?=?"姓名:"?+?this.name?+?"\t"; ?????????????info?=?info?+?"性別:"?+?(this.sex?==?FEMALE?"女":"男")?+?"\t"; ?????????????info?=?info?+?"薪水:"?+?this.salary??+?"\t";????? ?????????????//獲得員工的其他信息 ?????????????info?=?info?+?this.getOtherInfo(); ?????????????System.out.println(info); ?????} ?????//拼裝員工的其他信息 ?????protected?abstract?String?getOtherInfo(); } 先看小兵的實現類,越卑微的人物越能引起共鳴,因為我們有共同的經歷、思維和苦難。請看實現類,如代碼清單25-2所示。 代碼清單25-2 普通員工 public?class?CommonEmployee?extends?Employee?{ ?????//工作內容,這非常重要,以后的職業規劃就是靠它了 ?????private?String?job; ?????public?String?getJob()?{ ?????????????return?job; ?????} ?????public?void?setJob(String?job)?{ ?????????????this.job?=?job; ?????} ?????protected?String?getOtherInfo(){ ?????????????return?"工作:"+?this.job?+?"\t"; ?????} } 每個實現類都必須實現getOtherInfo信息,通過它獲得用戶個性信息,我們再來看管理階層,如代碼清單25-3所示。 代碼清單25-3 管理階層 public?class?Manager?extends?Employee?{ ?????//這類人物的職責非常明確:業績 ?????private?String?performance; ?????public?String?getPerformance()?{ ?????????????return?performance; ?????} ?????public?void?setPerformance(String?performance)?{ ?????????????this.performance?=?performance; ?????}??? ?????protected?String?getOtherInfo(){ ?????????????return?"業績:"+?this.performance?+?"\t"; ?????} } Performance這個單詞在技術人員的眼里就代表性能,在實際商務英語中可以有Sales Performance(銷售業績)、performance evaluation(業績評估)等。系統的框架都已經具備了,那我們來模擬一下這個過程,如代碼清單25-4所示。 代碼清單25-4 場景類 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????for(Employee?emp:mockEmployee()){ ?????????????????????emp.report(); ?????????????} ?????} ?????//模擬出公司的人員情況,我們可以想象這個數據是通過持久層傳遞過來的 ?????public?static?List<Employee>?mockEmployee(){ ?????????????List<Employee>?empList?=?new?ArrayList<Employee>(); ?????????????//產生張三這個員工 ?????????????CommonEmployee?zhangSan?=?new?CommonEmployee(); ?????????????zhangSan.setJob("編寫Java程序,絕對的藍領、苦工加搬運工"); ?????????????zhangSan.setName("張三"); ?????????????zhangSan.setSalary(1800); ?????????????zhangSan.setSex(Employee.MALE); ?????????????empList.add(zhangSan);????? ?????????????//產生李四這個員工 ?????????????CommonEmployee?liSi?=?new?CommonEmployee(); ?????????????liSi.setJob("頁面美工,審美素質太不流行了!"); ?????????????liSi.setName("李四"); ?????????????liSi.setSalary(1900); ?????????????liSi.setSex(Employee.FEMALE); ?????????????empList.add(liSi); ?????????????//再產生一個經理 ?????????????Manager?wangWu?=?new?Manager(); ?????????????wangWu.setName("王五"); ?????????????wangWu.setPerformance("基本上是負值,但是我會拍馬屁呀"); ?????????????wangWu.setSalary(18750); ?????????????wangWu.setSex(Employee.MALE); ?????????????empList.add(wangWu); ?????????????return?empList; ?????} } 先通過mockEmployee來模擬出一個數組,初始化兩個員工和一個經理,當然在實際項目中這個數組應該由持久層產生。運行結果如下所示: ? | 姓名:張三 |  性別:男 |  薪水:1800 |  工作:編寫Java程序,絕對的藍領、苦工加搬運工 | |-----|-----|-----|-----| | 姓名:李四 |  性別:女 |  薪水:1900 |  工作:頁面美工,審美素質太不流行了! | | 姓名:王五 |  性別:男 |  薪水:18750 |  業績:基本上是負值,但是我會拍馬屁呀 | 結果出來了,非常正確。我們來想一想實際的情況,人力資源部門拿這份表格會給誰看呢?那當然是大老板了!大老板關心的是什么?關心部門經理的業績!小兵的情況不是他要了解的,就像戰爭時期一位將軍說:“我一想到我的士兵也有孩子、妻子、父母,我就痛心疾首……但是這是戰場,我只能認為他們是一群機器……”是啊,其實我們也一樣啊,那問題就出來了: ● 大老板就看部門經理的報表,小兵的報表可看可不看。 ● 多個大老板的“嗜好”是不同的,主管銷售的,則主要關心營銷的情況;主管會計的,則主要關心企業的整體財務運行狀態;主管技術的,則主要看技術的研發情況。 綜合成一句話,這個報表會修改:數據的修改以及報表的展現修改,按照開閉原則,項目分析的時候已經考慮到這些可能引起變更的因素,就需要在設計時考慮通過擴展來避開未來需求變更而引起的代碼修改風險。我們來想一想,每個普通員工類和經理類都用一個方法report(從父類繼承過來的),他無法為每一個子類定制特殊的屬性,簡化類圖如圖25-2所示。 ![](https://box.kancloud.cn/2016-08-14_57b0036a0db3d.jpg) 圖25-2 簡化類圖 我們思考一下,如何提供一個能夠為每個子類定制報表的方法呢?可以這樣思考,普通員工和管理層員工是兩個不同的對象,例如,我邀請一個人過來參觀我的家,參觀者參觀完畢后分別進行描述,那參觀的對象不同,描述的結果也當然不同。好,按照這思路,我們把方法report提取到另外一個類Visitor中來實現,如圖25-3所示。 ![](https://box.kancloud.cn/2016-08-14_57b0036a23c7b.jpg) 圖25-3 改造后的簡化類圖 兩個子類的report方法都不需要了,只有Visitor類來實現了report的方法,這個猛一看還真有點委托(intergration)的意味,我們實現出來你就知道這和委托有非常大的差距。詳細類圖如圖25-4所示。 ![](https://box.kancloud.cn/2016-08-14_57b0036a40a13.jpg) 圖25-4 改造后的詳細類圖 在抽象類Employee中增加了accept方法,該方法是一個抽象方法,由子類實現,其意義就是說我這個類可以允許誰來訪問,也就是定義一類訪問者,在具體的實現類中調用訪問者的方法。我們先看訪問者接口IVisitor程序,如代碼清單25-5所示。 代碼清單25-5 訪問者接口 public?interface?IVisitor?{????? ?????//首先,定義我可以訪問普通員工 ?????public?void?visit(CommonEmployee?commonEmployee); ?????//其次,定義我還可以訪問部門經理 ?????public?void?visit(Manager?manager); } 該接口的意義是:該接口可以訪問兩個對象,一個是普通員工,一個是高層員工。我們來看其具體實現類,如代碼清單25-6所示。 代碼清單25-6 訪問者實現 public?class?Visitor?implements?IVisitor?{ ?????//訪問普通員工,打印出報表 ?????public?void?visit(CommonEmployee?commonEmployee)?{ ?????????????System.out.println(this.getCommonEmployee(commonEmployee)); ?????} ?????//訪問部門經理,打印出報表 ?????public?void?visit(Manager?manager)?{ ?????????????System.out.println(this.getManagerInfo(manager)); ?????} ?????//組裝出基本信息 ?????private?String?getBasicInfo(Employee?employee){ ?????????????String?info?=?"姓名:"?+?employee.getName()?+?"\t"; ?????????????info?=?info?+?"性別:"?+?(employee.getSex()?==?Employee.FEMALE?"女":"男")?+?"\t"; ?????????????info?=?info?+?"薪水:"?+?employee.getSalary()??+?"\t"; ?????????????return?info; ?????} ?????//組裝出部門經理的信息 ?????private?String?getManagerInfo(Manager?manager){ ?????????????String?basicInfo?=?this.getBasicInfo(manager); ?????????????String?otherInfo?=?"業績:"+manager.getPerformance()?+?"\t"; ?????????????return?basicInfo?+?otherInfo; ?????} ?????//組裝出普通員工信息 ?????private?String?getCommonEmployee(CommonEmployee?commonEmployee){ ?????????????String?basicInfo?=?this.getBasicInfo(commonEmployee); ?????????????String?otherInfo?=?"工作:"+commonEmployee.getJob()+"\t"; ?????????????return?basicInfo?+?otherInfo; ?????} } 在具體的實現類中,定義了兩個私有方法,作用就是產生需要打印的數據和格式,然后在訪問者訪問相關的對象時產生這個報表。抽象員工Employee稍有修改,如代碼清單25-7所示。 代碼清單25-7 抽象員工類 public?abstract?class?Employee?{ ?????public?final?static?int?MALE?=?0;??//0代表是男性 ?????public?final?static?int?FEMALE?=?1;?//1代表是女性 ?????//甭管是誰,都有工資 ?????private?String?name; ?????//只要是員工那就有薪水 ?????private?int?salary; ?????//性別很重要 ?????private?int?sex; ?????//以下是簡單的getter/setter ?????public?String?getName()?{ ?????????????return?name; ?????} ?????public?void?setName(String?name)?{ ?????????????this.name?=?name; ?????} ?????public?int?getSalary()?{ ?????????????return?salary; ?????} ?????public?void?setSalary(int?salary)?{ ?????????????this.salary?=?salary; ?????} ?????public?int?getSex()?{ ?????????????return?sex; ?????} ?????public?void?setSex(int?sex)?{ ?????????????this.sex?=?sex; ?????} ?????//我允許一個訪問者訪問 ?????public?abstract?void?accept(IVisitor?visitor); } 抽象員工類有3個變動: ● 刪除了report方法。 ● 增加了accept方法,接受訪問者的訪問。 ● 刪除了getOtherInfo方法。它的實現由訪問者來處理,因為訪問者對被訪問的對象是“心知肚明”的,非常了解被訪問者。 我們繼續來看員工實現類,普通員工代碼清單25-8所示。 代碼清單25-8 普通員工 public?class?CommonEmployee?extends?Employee?{ ?????//工作內容,這非常重要,以后的職業規劃就是靠它了 ?????private?String?job; ?????public?String?getJob()?{ ?????????????return?job; ?????} ?????public?void?setJob(String?job)?{ ?????????????this.job?=?job; ?????} ?????//我允許訪問者訪問 ?????@Override ?????public?void?accept(IVisitor?visitor){ ??????????visitor.visit(this); ?????} } 上面是普通員工的實現類,該類的accept方法很簡單,這個類就把自身傳遞過去,也就是讓訪問者訪問本身這個對象。再看Manager類,如代碼清單25-9所示。 代碼清單25-9 管理層員工 public?class?Manager?extends?Employee?{ ?????//這類人物的職責非常明確:業績 ?????private?String?performance; ?????public?String?getPerformance()?{ ?????????????return?performance; ?????} ?????public?void?setPerformance(String?performance)?{ ?????????????this.performance?=?performance; ?????} ?????//部門經理允許訪問者訪問 ?????@Override ?????public?void?accept(IVisitor?visitor){ ?????????????visitor.visit(this); ?????} } 所有的業務定義都已經完成,我們來看看怎么模擬這個邏輯,如代碼清單25-10所示。 代碼清單25-10 場景類 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????for(Employee?emp:mockEmployee()){ ?????????????????????emp.accept(new?Visitor()); ?????????????} ?????} ?????//模擬出公司的人員情況,我們可以想象這個數據是通過持久層傳遞過來的 ?????public?static?List<Employee>?mockEmployee(){ ?????????????List<Employee>?empList?=?new?ArrayList<Employee>(); ?????????????//產生張三這個員工 ?????????????CommonEmployee?zhangSan?=?new?CommonEmployee(); ?????????????zhangSan.setJob("編寫Java程序,絕對的藍領、苦工加搬運工"); ?????????????zhangSan.setName("張三"); ?????????????zhangSan.setSalary(1800); ?????????????zhangSan.setSex(Employee.MALE); ?????????????empList.add(zhangSan);????? ?????????????//產生李四這個員工 ?????????????CommonEmployee?liSi?=?new?CommonEmployee(); ?????????????liSi.setJob("頁面美工,審美素質太不流行了!"); ?????????????liSi.setName("李四"); ?????????????liSi.setSalary(1900); ?????????????liSi.setSex(Employee.FEMALE); ?????????????empList.add(liSi); ?????????????//再產生一個經理 ?????????????Manager?wangWu?=?new?Manager(); ?????????????wangWu.setName("王五"); ?????????????wangWu.setPerformance("基本上是負值,但是我會拍馬屁呀"); ?????????????wangWu.setSalary(18750); ?????????????wangWu.setSex(Employee.MALE); ?????????????empList.add(wangWu);????? ?????????????return?empList; ?????} } 改動非常少,就黑體那么一行的改動,運行結果如下: ? | 姓名:張三 |  性別:男 |  薪水:1800 |  工作:編寫Java程序,絕對的藍領、苦工加搬運工 | |-----|-----|-----|-----| | 姓名:李四 |  性別:女 |  薪水:1900 |  工作:頁面美工,審美素質太不流行了! | | 姓名:王五 |  性別:男 |  薪水:18750 |  業績:基本上是負值,但是我會拍馬屁呀 | 運行結果也完全相同,那回過頭來看看這個程序是怎么實現的: ● 第一,通過循環遍歷所有元素。 ● 第二,每個員工對象都定義了一個訪問者。 ● 第三,員工對象把自己作為一個參數調用訪問者visit方法。 ● 第四,訪問者調用自己內部的計算邏輯,計算出相應的數據和表格元素。 ● 第五,訪問者打印出報表和數據。 事情的經過就是這個樣子。那我們再來看看上面提到的數據和報表格式都會改變的情況。首先是數據的改變,數據改了當然都要改,說不上兩個方案有什么優劣;其次是報表格式的修改,這個方案絕對是有優勢的,我只要再產生一個IVisitor的實現類就可以產生一個新的報表格式,而其他的類都不用修改,如果你用Spring開發,那就更好了,在Spring的配置文件中使用的是接口注入,我只要把配置文件中的 ref修改一下就行了,其他的都不用修改了!這就是訪問者模式的優勢所在。
                  <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>

                              哎呀哎呀视频在线观看