1. 程式人生 > >設計模式(十九)訪問者模式

設計模式(十九)訪問者模式

訪問者模式

訪問者模式的場景:

公司老闆要看報表, 公司有銷售,財務,研發,每個員工有自己獨特的資訊,最常見的做法是: 定義抽象員工,並定義模板方法,每一個員工實現自己角色的個性化方法,通過模板方法report來訪問。
比如是這樣的,

 public abstract Employee{
 private String name;
 private String telephone;
 public String getBasicInfo(){
	return name+"tel: "+telephone;
}
public abstract String getSpecialInfo();
	public void report(){
		System.out.println(getBasicInfo());
		System.out.println(getSpecialInfo());
	}
}

這樣每個員工繼承基類,各自實現自己的特殊資訊就可以了。

但是這樣有一個問題,報表的輸出格式全由report() 方法控制, 如果有一天老闆想換種報表格式,比如不想看員工姓名了怎麼辦?
是不是要修改基類的report方法了, 開閉原則指導要對修改關閉對擴充套件開放, 如果直接改基類report也會出現問題,比如今天一個格式出報表,改下基類,明天又換個格式改報表,又要改基類,還想同時出兩份格式不同的報表怎麼辦?
所以就引出本文中提到的訪問者模式。
首先分析,要為每一個角色個性化自己的報表方法,可以把角色作為引數傳給一個單獨的訪問者物件Visitor, 由Visitor利用多型來實現個性化輸出。並且由Visitor 去負責產生報表格式。 物件和Visitor是弱耦合的,不是繼承關係。 這種實現方式便於擴充套件,需要產生不同格式的報表,多新增一個Visitor完成這個特殊的功能就可以了。

在這裡插入圖片描述

訪問者模式的角色

  • Visitor 抽象訪問者。 宣告哪些元素可以訪問

  • ConcreteVisitor 具體訪問者。 訪問到一個類後,具體怎麼做,做什麼

  • Element 抽象元素。 介面或者抽象類,宣告接受哪一類訪問者訪問。程式中通過accept方法中的引數來定義

  • ConcreteElement 具體元素,實現accept方法

  • ObjectStructure 結構物件。 元素產生者

    public abstract class  Element {
          
          public abstract void doSomething();
          public abstract void accept(IVisitor visitor);
      }
      public class ConcreteElement1 extends Element{
          @Override
          public void doSomething() {
              //業務處理
          }
          //允許哪個訪問者訪問
          @Override
          public void accept(IVisitor visitor) {
              visitor.visit(this);
          }
      }
         public class ConcreteElement2 extends Element{
          @Override
          public void doSomething() {
              //業務處理
          }
          //允許哪個訪問者訪問
          @Override
          public void accept(IVisitor visitor) {
              visitor.visit(this);
          }
      }
    
    
     public interface  IVisitor{
          public void visit(ConcreteElement1 el1);
          public void visit(ConcreteElement2 el2);
      }
      public class Visitor implements IVisitor{
          @Override
          public void visit(ConcreteElement1 el1) {
              el1.doSomething();
          }
          @Override
          public void visit(ConcreteElement2 el2) {
              el2.doSomething();
          }
      }
      public class ObjectStructure{
          public static Element createElement(){
              Random rand=new Random();
              if(rand.nextInt(100)>50){
                  return new ConcreteElement1();
              }else{
                  return new ConcreteElement2();
              }
              
          }
      }
      public class  Client{
          public static void main(String[] args){
              for(int i=0;i<10;i++){
                  Element e=ObjectStructure.createElement();
                  e.accept(new Visitor());
              }
          }
      }
    

訪問者模式優點

  • 符合單一原則。 Visitor負責報表的實現,Employee及其子類負責資料載入
  • 優秀的擴充套件性。 如果需要不同的格式報表,直接新增Visitor或者在Visitor新增方法就可以了。
  • 靈活性高。

訪問者模式的缺點

  • 具體元素對訪問者公佈細節。 違反迪米特法則
  • 具體元素變更比較困難
  • 違背了依賴倒置原則。 放棄介面,依賴實現類,擴充套件比較困難。

訪問者模式的使用場景

  • 需要遍歷不同的物件, 迭代器模式只能訪問同類或同介面的資料,訪問者模式是對迭代器模式的 擴充,可以根據不同的物件,執行不同的操作。

java 靜態多分派,動態單分派。 靜態,動態是一對概念。 單分派和多分派是一個對概念。 根據宗量(引數)的多少分為多分派和單分派。