在前面組合模式和迭代器模式中,講了如何把公司組織架構(gòu)樹搭建起來(lái),并且遍歷它。現(xiàn)在有這樣一個(gè)需求,要把公司的所有人員信息打印匯報(bào)。

這個(gè)類圖還是比較簡(jiǎn)單的,使用了一個(gè)模版方法模式,把所要的信息都打印出來(lái),我們先來(lái)看一下抽象類:
public abstract class Employee {
? ? public finial static int MAL = 0;? ? //男性
? ? public finial static int FEMAL = 1;? ? //女性
? ? // 姓名
? ? private String name;
? ? // 薪水
? ? private int salary;
? ? // 性別
? ? private int sex;
? ? get、set...
? ? // 打印員工信息
? ? 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();
}
普通員工:
public class CommonEmployee extends Employee {
????//工作內(nèi)容,這個(gè)非常重要,以后的職業(yè)規(guī)劃就是靠這個(gè)了
????private String job;
????public String getJob() {
????????return job;
????}
????public void setJob(String job) {
????????this.job = job;
????}
????protected String getOtherInfo(){
????????return "工作:"+ this.job + "\t";
????}
}
經(jīng)理級(jí)人物:
public class Manager extends Employee {
????//這類人物的職責(zé)非常明確:業(yè)績(jī)
????private String performance;
????public String getPerformance() {
????????return performance;
????}
????public void setPerformance(String performance) {
????????this.performance = performance;
????}
????protected String getOtherInfo(){
????????return "業(yè)績(jī):"+ this.performance + "\t";
????}
}
invoker 類:
public class Client {
????public static void main(String[] args) {
????????for(Employee emp:mockEmployee()){
????????????emp.report();
????????}
????}
????//模擬出公司的人員情況,我們可以想象這個(gè)數(shù)據(jù)室通過(guò)持久層傳遞過(guò)來(lái)的
????public static List<Employee> mockEmployee(){
????????????List<Employee> empList = new ArrayList<Employee>();
????????????//產(chǎn)生張三這個(gè)員工
????????????CommonEmployee zhangSan = new CommonEmployee();
????????????zhangSan.setJob("編寫Java程序,絕對(duì)的藍(lán)領(lǐng)、苦工加搬運(yùn)工");
????????????zhangSan.setName("張三");
????????????zhangSan.setSalary(1800);
????????????zhangSan.setSex(Employee.MALE);
????????????empList.add(zhangSan);
????????????//產(chǎn)生李四這個(gè)員工
????????????CommonEmployee liSi = new CommonEmployee();
????????????liSi.setJob("頁(yè)面美工,審美素質(zhì)太不流行了!");
????????????liSi.setName("李四");
????????????liSi.setSalary(1900);
????????????liSi.setSex(Employee.FEMALE);
????????????empList.add(liSi);
? ??????????//再產(chǎn)生一個(gè)經(jīng)理
????????????Manager wangWu = new Manager();
????????????wangWu.setName("王五");
????????????wangWu.setPerformance("基本上是負(fù)值,但是我會(huì)拍馬屁呀");
????????????wangWu.setSalary(18750);
????????????wangWu.setSex(Employee.MALE);
????????????empList.add(wangWu);
????????????return empList;
? ? ? ? }
? ? }
運(yùn)行結(jié)果:
姓名:張三 性別:男 薪水:1800 工作:編寫Java程序,絕對(duì)的藍(lán)領(lǐng)、苦工加搬運(yùn)工
姓名:李四 性別:女 薪水:1900 工作:頁(yè)面美工,審美素質(zhì)太不流行了!
姓名:王五 性別:男 薪水:18750 業(yè)績(jī):基本上是負(fù)值,但是我會(huì)拍馬屁呀
結(jié)果出來(lái)了,也非常正確。我們來(lái)想一想這個(gè)實(shí)際的情況,人力資源部門拿這這份表格會(huì)給誰(shuí)看呢?那當(dāng)然是大老板了,大老板關(guān)心的是什么?關(guān)心部門經(jīng)理的業(yè)績(jī)!小兵的情況不是他要了解的。
?大老板就看部門經(jīng)理的報(bào)表,小兵的報(bào)表可看可不看;
? 多個(gè)大老板,“嗜好”是不同的,主管銷售的,則主要關(guān)心的營(yíng)銷情況;主管會(huì)計(jì)的,則主要關(guān)心企業(yè)的整體財(cái)務(wù)運(yùn)行狀態(tài);主管技術(shù)的,則主要看技術(shù)的研發(fā)情況;
綜合成一句話,這個(gè)報(bào)表會(huì)有修改:數(shù)據(jù)的修改以及報(bào)表的展現(xiàn)修改,按照開(kāi)閉原則,項(xiàng)目分析的時(shí)候已經(jīng)考慮到這些可能引起變更的隱私,就需要在設(shè)計(jì)時(shí)考慮通過(guò)擴(kuò)展來(lái)來(lái)避開(kāi)未來(lái)需求變更而引起的代碼修改風(fēng)險(xiǎn)。我們來(lái)想一想,每個(gè)普通員工類和經(jīng)理類都一個(gè)方法 report,那是否可以把這個(gè)方法提取到另外一個(gè)類中來(lái)實(shí)現(xiàn)呢?
原有的示意圖如下:

這兩個(gè)類都一個(gè)相同的方法 report(),但是要實(shí)現(xiàn)的內(nèi)容不相同,而且還有可能會(huì)發(fā)生變動(dòng),那我們就讓其他類來(lái)實(shí)現(xiàn)這個(gè) report 方法,好,看示意圖圖的變更:

兩個(gè)類的 report 方法都不需要了,只有 Visitor 類來(lái)實(shí)現(xiàn)了 report 的方法

在抽象類 Employee 中增加了 accept 方法,這個(gè)方法是定義我這個(gè)類可以允許被誰(shuí)來(lái)訪問(wèn),也就定義一類訪問(wèn)者,在具體的實(shí)現(xiàn)類中調(diào)用訪問(wèn)者的方法。我們先看訪問(wèn)者接口 IVisitor 程序:
public interface IVisitor {?
????//首先定義我可以訪問(wèn)普通員工
????public void visit(CommonEmployee commonEmployee);
????//其次定義,我還可以訪問(wèn)部門經(jīng)理
????public void visit(Manager manager);
}
訪問(wèn)者的實(shí)現(xiàn)類:?
public class Visitor implements IVisitor {
????//訪問(wèn)普通員工,打印出報(bào)表
????public void visit(CommonEmployee commonEmployee) {
????????System.out.println(this.getCommonEmployee(commonEmployee));
????}
????//訪問(wèn)部門經(jīng)理,打印出報(bào)表
????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;
????}
????//組裝出部門經(jīng)理的信息
????private String getManagerInfo(Manager manager){
????????String basicInfo = this.getBasicInfo(manager);
????????String otherInfo = "業(yè)績(jī):"+manager.getPerformance() + "\t";
????????return basicInfo + otherInfo;
????}
????//組裝出普通員工信息
????private String getCommonEmployee(CommonEmployee commonEmployee){
????????String basicInfo = this.getBasicInfo(commonEmployee);
????????String otherInfo = "工作:"+commonEmployee.getJob()+"\t";
????????return basicInfo + otherInfo;
????}
}
在具體的實(shí)現(xiàn)類中,定義了兩個(gè)私有方法,作用就是產(chǎn)生需要打印的數(shù)據(jù)和格式,然后在訪問(wèn)者訪問(wèn)相關(guān)的對(duì)象時(shí),產(chǎn)生這個(gè)報(bào)表。繼續(xù)看 Employee 抽象類:
public abstract class Employee {
????public final static int MALE = 0; //0代表是男性
????public final static int FEMALE = 1; //1代表是女性
????//甭管是誰(shuí),都有工資
????private String name;
????//只要是員工那就有薪水
????private int salary;
????//性別很重要
????private int sex;
? ? get、set...
? ??//我允許一個(gè)訪問(wèn)者過(guò)來(lái)訪問(wèn)
????public abstract void accept(IVisitor visitor);
}
刪除了 report 方法,增加了 accept 方法,需要實(shí)現(xiàn)類來(lái)實(shí)現(xiàn)。繼續(xù)看實(shí)現(xiàn)類:
普通員工:
public class CommonEmployee extends Employee {
????//工作內(nèi)容,這個(gè)非常重要,以后的職業(yè)規(guī)劃就是靠這個(gè)了
????private String job;
????public String getJob() {
????????return job;
????}
????public void setJob(String job) {
????????this.job = job;
????}
????//我允許訪問(wèn)者過(guò)來(lái)訪問(wèn)
????@Override
????public void accept(IVisitor visitor){
????????visitor.visit(this);
????}
}
經(jīng)理級(jí)人物:
public class Manager extends Employee {
????//這類人物的職責(zé)非常明確:業(yè)績(jī)
????private String performance;
????public String getPerformance() {
????????return performance;
????}
????public void setPerformance(String performance) {
????????this.performance = performance;
????}
????//部門經(jīng)理允許訪問(wèn)者訪問(wèn)
????@Override
????public void accept(IVisitor visitor){
????????visitor.visit(this);
????}
}
public class Client {
????public static void main(String[] args) {
????????for(Employee emp:mockEmployee()){
????????????emp.accept(new Visitor());
????????}
????}
????//模擬出公司的人員情況,我們可以想象這個(gè)數(shù)據(jù)室通過(guò)持久層傳遞過(guò)來(lái)的
????public static List<Employee> mockEmployee(){
????????List<Employee> empList = new ArrayList<Employee>();
????????//產(chǎn)生張三這個(gè)員工
????????CommonEmployee zhangSan = new CommonEmployee();
????????zhangSan.setJob("編寫Java程序,絕對(duì)的藍(lán)領(lǐng)、苦工加搬運(yùn)工");
????????zhangSan.setName("張三");
????????zhangSan.setSalary(1800);
????????zhangSan.setSex(Employee.MALE);
????????empList.add(zhangSan);
????????//產(chǎn)生李四這個(gè)員工
????????CommonEmployee liSi = new CommonEmployee();
????????liSi.setJob("頁(yè)面美工,審美素質(zhì)太不流行了!");
????????liSi.setName("李四");
????????liSi.setSalary(1900);
????????liSi.setSex(Employee.FEMALE);
????????empList.add(liSi);
????????//再產(chǎn)生一個(gè)經(jīng)理
????????Manager wangWu = new Manager();
????????wangWu.setName("王五");
????????wangWu.setPerformance("基本上是負(fù)值,但是我會(huì)拍馬屁呀");
????????wangWu.setSalary(18750);
????????wangWu.setSex(Employee.MALE);
????????empList.add(wangWu);
????????return empList;
? ? }
}
看運(yùn)行結(jié)果:
姓名:張三 性別:男 薪水:1800 工作:編寫Java程序,絕對(duì)的藍(lán)領(lǐng)、苦工加搬運(yùn)工
姓名:李四 性別:女 薪水:1900 工作:頁(yè)面美工,審美素質(zhì)太不流行了!
姓名:王五 性別:男 薪水:18750 業(yè)績(jī):基本上是負(fù)值,但是我會(huì)拍馬屁呀
? 首先通過(guò)循環(huán)遍歷所有元素;
? 其次,每個(gè)員工對(duì)象都定義了一個(gè)訪問(wèn)者;
? 再其次,員工對(duì)象把自己做為一個(gè)參數(shù)調(diào)用訪問(wèn)者 visit 方法;
? 然后,訪問(wèn)者調(diào)用自己內(nèi)部的計(jì)算邏輯,計(jì)算出相應(yīng)的數(shù)據(jù)和表格元素;
? 最后,訪問(wèn)者打印出報(bào)表和數(shù)據(jù);
訪問(wèn)者模式通用類圖:
