既然在春招季,我們舉個簡歷篩選的例子,投簡歷的都是寫本科生、專科生,還有碩士生、高職啊…為了簡單就先取前兩者。求職者的簡歷作為Element實現如下:
abstract class Student {
//提供對於數據域基本操作的函數
private String name;
private String university;
private String rating;
//讓指定的visitor獲得操作該對象的權限
public abstract void accept(Visitor visitor);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUniversity() {
return university;
}
public void setUniversity(String university) {
this.university = university;
}
public String getRating() {
return rating;
}
public void setRating(String rating) {
this.rating = rating;
}
}
class Bachelor extends Student{
@Override
public void accept( Visitor visitor ) {
visitor.visit( this );
}
}
class College extends Student{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
因為我們只定義了兩種學生,所以接口提供了對於兩種Element訪問
interface Visitor{
public void visit ( Bachelor bachelor );
public void visit ( College college );
}
首先篩選簡歷我們看一下大家的簡歷都什麼樣子,那麼需要一個ShowVisitor:
class ShowVisitor implements Visitor {
@Override
public void visit(Bachelor bachelor) {
System.out.println("A bachelor\n");
//TODO 可能會有一些特異的操作,我們為了簡單就省略了
this.printMessage( bachelor );
}
@Override
public void visit(College college) {
System.out.println(" a college student!\n");
//TODO 同上
this.printMessage( college );
}
public void printMessage ( Student student ){
System.out.println( "Name : " + student.getName()+"\n"
+ "University : " + student.getUniversity()+"\n"
+ "Rating : " + student.getRating() + "\n"
);
}
}
要進行測試,我們首先要構造一個數據集合,也就是角色中對應的ObjectStructure,為了簡單我們直接用ArrayList了
public class VisitorEg {
public static void main ( String [] args ){
ArrayList list = new ArrayList();
Bachelor bachelor = new Bachelor();
bachelor.setName("llin");
bachelor.setRating("100");
bachelor.setUniversity("Tianjin University");
College college = new College();
college.setUniversity("Tianjin college");
college.setRating("1");
college.setName("dalinge");
list.add ( bachelor );
list.add ( college );
Visitor visitor = new ShowVisitor();
for ( Student student: list ){
student.accept( visitor );
}
}
}
那麼好像看不出訪問者模式有什麼優勢啊!!!而且好費事啊,但是因為你將數據結構和對數據的操作分離了(解耦),所以當我想添加新的操作時,不需要修改原有的類,只需要重新實現一個visitor就可以了。
所以,我們回到這個例子,這麼多人報名,那麼到底有多少本科生呢(如果人數夠了,可能直接偷懶只面試本科生了),-_-萬惡的這種HR,所以我們需要一個統計的Visitor:
class SumVisitor implements Visitor{
private int totalBachelor;
SumVisitor(){
super();
totalBachelor = 0;
}
@Override
public void visit(Bachelor bachelor) {
totalBachelor++;
}
@Override
public void visit(College college) {
}
public int getTotal_bachelor() {
return totalBachelor;
}
}
public class VisitorEg {
public static void main ( String [] args ){
ArrayList list = new ArrayList();
Bachelor bachelor = new Bachelor();
bachelor.setName("llin");
bachelor.setRating("100");
bachelor.setUniversity("Tianjin University");
College college = new College();
college.setUniversity("Tianjin college");
college.setRating("1");
college.setName("dalinge");
list.add ( bachelor );
list.add ( college );
Visitor visitor = new ShowVisitor();
Visitor visitor1 = new SumVisitor();
for ( Student student: list ){
student.accept( visitor );
student.accept( visitor1);
}
System.out.println( "The total sum of bachelors : "+ ((SumVisitor)visitor1).getTotal_bachelor() );
}
}
達到了要求,卻沒有修改一行代碼,開心!
訪問者是一種集中規整模式,特別適合用於大規模重構的項目,在這一個階段的需求已經非常清晰,原系統的功能點也已經明確,通過訪問者模式可以很容易把一些功能進行梳理,達到最終目的功能集中化
單分派:一個操作是根據請求者的名稱和接收到的參數決定的,在Java有靜態綁定和動態綁定,分別是通過重載和覆寫實現的。
雙分派:雙分派意味著得到執行的操作決定於請求的種類和接收者的類型。正對應於訪問者模式。