DesignPattern_訪問者模式_19

每天只學一點點發表於2020-12-21

訪問者模式

定義

Represent anoperation to be performed on the elements of an object structure. Visitor lets you define a newoperation without changing the classes of the elements on which it operates.
封裝一些作用於某種資料結構中的各元素的操作,它可以在不改變資料結構的前提下定義作用於這些元素的新的操作。

訪問者模式通用類圖

  • Visitor——抽象訪問者
    抽象類或者介面,宣告訪問者可以訪問哪些元素,具體到程式中就是visit方法的引數定義哪些物件是可以被訪問的。
  • ConcreteVisitor——具體訪問者
    它影響訪問者訪問到一個類後該怎麼幹,要做什麼事情
  • Element——抽象元素
    介面或者抽象類,宣告接受哪一類訪問者訪問,程式上是通過accept方法中的引數來定義的。
  • ConcreteElement——具體元素
    實現accept方法,通常是visitor.visit(this),基本上都形成了一種模式了。
  • ObjectStruture——結構物件
    元素產生者,一般容納在多個不同類、不同介面的容器,如List、Set、Map等,在專案中,一般很少抽象出這個角色。

優點

  • 符合單一職責原則
    具體元素角色也就是Employee抽象類的兩個子類負責資料的載入,而Visitor類則負責報表的展現,兩個不同的職責非常明確地分離開來,各自演繹變化
  • 優秀的擴充套件性
    由於職責分開,繼續增加對資料的操作是非常快捷的,例如,現在要增加一份給大老闆的報表,這份報表格式又有所不同,直接在Visitor中增加一個方法,傳遞資料後進行整理列印
  • 靈活性非常高

缺點

  • 具體元素對訪問者公佈細節
    訪問者要訪問一個類就必然要求這個類公佈一些方法和資料,也就是說訪問者關注了其他類的內部細節,這是迪米特法則所不建議的。
  • 具體元素變更比較困難
    具體元素角色的增加、刪除、修改都是比較困難的,就上面那個例子,你想想,你要是想增加一個成員變數,如年齡age,Visitor就需要修改,如果Visitor是一個還好辦,多個呢?業務邏輯再複雜點呢?
  • 違背了依賴倒置轉原則
    問者依賴的是具體元素,而不是抽象元素,這破壞了依賴倒置原則,特別是在物件導向的程式設計中,拋棄了對介面的依賴,而直接依賴實現類,擴充套件比較難。

程式碼實現

/**
 * @author huangqh
 * @create 2020/12/21 17:55
 * @Notes 訪問者模式
 */
public class VisitorModel {
}

/**
 * 抽象員工
 */
@Data
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;

    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();
}

/**
 * 普通員工
 */
@Data
class CommonEmployee extends Employee {
    private String job;

    @Override
    protected String getOtherInfo() {
        return "工作:" + this.job + "\t";
    }
}

/**
 * 管理階層
 */
@Data
class Manager extends Employee {
    //這類人物的職責非常明確:業績
    private String performance;

    @Override
    protected String getOtherInfo() {
        return "業績:" + this.performance + "\t";
    }
}


class Clien {
    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;

    }
}

訪問者模式

/**
 * @author huangqh
 * @create 2020/12/21 17:55
 * @Notes 訪問者模式
 */
public class VisitorModel {
}

/**
 * 抽象員工
 */
@Data
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;

    //我允許一個訪問者訪問
    public abstract void accept(IVisitor visitor);
}

/**
 * 普通員工
 */
@Data
class CommonEmployee extends Employee {
    private String job;

    //我允許訪問者訪問
    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}

/**
 * 管理階層
 */
@Data
class Manager extends Employee {
    //這類人物的職責非常明確:業績
    private String performance;

    //部門經理允許訪問者訪問
    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}

/**
 * 訪問者介面
 */
interface IVisitor {
    //首先,定義我可以訪問普通員工
    public void visit(CommonEmployee commonEmployee);

    //其次,定義我還可以訪問部門經理
    public void visit(Manager manager);
}

/**
 *
 */
class Visitor implements IVisitor {
    //訪問普通員工,列印出報表
    @Override
    public void visit(CommonEmployee commonEmployee) {
        System.out.println(this.getCommonEmployee(commonEmployee));
    }

    //訪問部門經理,列印出報表
    @Override
    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;
    }
}

class Clien {
    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;

    }
}

相關文章