天天看點

設計模式-通路者模式(Visitor Pattern)

推薦:​​Java設計模式彙總​​

通路者模式

定義

将作用于某種資料結構中的各元素的操作分離出來封裝成獨立的類,使其在不改變資料結構的前提下可以添加作用于這些元素的新的操作,為資料結構中的每個元素提供多種通路方式,它将對資料的操作與資料結構進行分離。

類型

行為型。

UML類圖

設計模式-通路者模式(Visitor Pattern)

角色

  • 通路者(Visitor)角色 :接口或抽象類,它定義了對每一個元素(Element)通路的接口。
  • 具體通路者(ConcreteVisitor)角色 :具體的通路者,它需要實作對每一個元素類通路時所産生的具體行為 。
  • 元素(Element)角色 :接口或抽象類,它定義了一個接受通路的方法​

    ​accept()​

    ​。
  • 具體元素(ConcreteElement)角色 :它提供接受通路方法的具體實作,而這個具體的實作,通常情況下是使用通路者提供的通路該元素類的方法。
  • 資料結構(ObjectStructure)角色 :定義程式當中所使用的資料結構,對象結構是一個抽象表述,它内部管理了元素集合,并且可以疊代這些元素供通路者通路。

例子

慕課網有免費課和實戰課,每個使用者可以相當于一個通路者,通路這些課程資訊。

而慕課網的從業人員也可以相當于一個通路者,不過這個通路者還可以得到這些課程所産生的利潤,為了簡單,這個就不實作了,隻是為了說明通路者模式。

IVisitor接口(通路者角色),定義了兩個接口,用來通路兩種不同類型的課程(免費課和實戰課)。

這裡不符合依賴倒置原則,抽象層依賴了具體層,這是通路者模式的一個缺點。

package com.kaven.design.pattern.behavioral.visitor;

public interface IVisitor {
    void visit(FreeCourse freeCourse);
    void visit(CodingCourse codingCourse);
}      

Course類(元素角色),定義了一個接受通路的方法​

​accept()​

​。

package com.kaven.design.pattern.behavioral.visitor;

public abstract class Course {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract void accept(IVisitor visitor);
}      

FreeCourse類(具體元素角色),免費課程類。

package com.kaven.design.pattern.behavioral.visitor;

public class FreeCourse extends Course {
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}      

CodingCourse類(具體元素角色),實戰課程類,實戰課程有一個價格屬性。

package com.kaven.design.pattern.behavioral.visitor;

public class CodingCourse extends Course {
    private int price;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}      

Visitor類(具體通路者角色),實作了對每一個元素類通路時所産生的具體行為 。

package com.kaven.design.pattern.behavioral.visitor;

public class Visitor implements IVisitor{
    public void visit(FreeCourse freeCourse) {
        System.out.println("免費課程:"+freeCourse.getName());
    }

    public void visit(CodingCourse codingCourse) {
        System.out.println("實戰課程:"+codingCourse.getName()+" 價格:"+codingCourse.getPrice());
    }
}      

資料結構角色就不寫了,在應用層代碼中用​

​List​

​和一些操作代替了。

應用層代碼:

package com.kaven.design.pattern.behavioral.visitor;

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        List<Course> courseList = new ArrayList<Course>();

        FreeCourse freeCourse = new FreeCourse();
        freeCourse.setName("SpringMVC資料綁定");

        CodingCourse codingCourse = new CodingCourse();
        codingCourse.setName("Java設計模式");
        codingCourse.setPrice(299);

        courseList.add(freeCourse);
        courseList.add(codingCourse);

        for(Course course : courseList){
            course.accept(new Visitor());
        }
    }
}      

輸出:

免費課程:SpringMVC資料綁定
實戰課程:Java設計模式 價格:299      

這裡便完成了一個簡單的通路者模式的例子。

适用場景

  • 對象結構中對象對應的類很少改變,但經常需要在此對象結構上定義新的操作。
  • 需要對一個對象結構中的對象進行很多不同的并且不相關的操作,并且需要避免讓這些操作"污染"這些對象的類,也不希望在增加新操作時修改這些類。

優點

  • 各個角色職責分離,符合單一職責原則。
  • 使得資料結構和作用于結構上的操作解耦,使得操作集合可以獨立變化。
  • 優秀的擴充性。
  • 靈活性高。
  • 具體元素對通路者公布細節,違反了迪米特原則。
  • 具體元素變更時導緻修改成本大。
  • 違反了依賴倒置原則,為了達到差別對待,而依賴了具體類,而不是抽象。

繼續閱讀