文章目錄
- 訪問者模式簡介
- 分派的分類
- 什么是雙分派?
- 結構
- UML圖
- 具體實現
- UML圖
- 代碼實現
- 優缺點
訪問者模式簡介
- 訪問者模式(visitor pattern)是封裝一些作用于某種數據結構中的元素的操作,它可以在不改變這個數據結構(實現例子中的、男女)的前提下,定義作用于這些原則新的操作(實現例子中的成功、失敗、待定等結果)。
分派的分類
- 靜態分派:就是程序編譯的時候,根據參數類型就可以確定的分派。
- 動態分派:因為參數是父類或者接口,具體由誰執行需要根據接口傳入參數具體類型確定的分派。
什么是雙分派?
- 雙分派:就是經歷兩次上面的分派過程就是雙分派。
結構
- 1.抽象訪問者角色(Visitor):定義了對每一個原色(Element)訪問的行為,他的參數就是可以訪問的元素,他的方法個數理論上和元素個數是一致的,所以訪問者模式要求元素類的個數不能改變。
- 2.具體訪問者角色(Concrete Visitor):給出對每一個元素訪問時所產生的具體行為(demo中的成功、失敗、待定)
- 3.抽象元素角色(Element):定義了一個接受訪問者的方法(accept),其意思就是每一個元素都可以被訪問者訪問。
- 4.具體元素就角色(Concrete Element):提供了接受訪問方法的具體實現,這個具體實現,通常情況下是使用訪問者提供的訪問該元素的方法。
- 5.對象結構角色(Object Structure):可以理解為具體元素的存儲容器。
UML圖
具體實現
例子:好聲音,對男女選手進行評審。
UML圖
代碼實現
- 抽象元素角色
package com.xxliao.pattern.behavioral.visitor.demo;/*** @author xxliao* @description: 抽象元素角色 提供一個方法讓訪問者可以訪問* @date 2024/5/26 0:18*/
public abstract class Person {/*** @description 提供給訪問者訪問的防方法,訪問者通過參數傳遞進來。* @author xxliao* @date 2024/5/26 0:28*/public abstract void result(ActionVisitor actionVisitor);
}
- 具體元素角色
package com.xxliao.pattern.behavioral.visitor.demo;/*** @author xxliao* @description: 具體元素角色,接受一個訪問者方法* @date 2024/5/26 0:18*/
public class Man extends Person{/*** @description 具體元素角色提供給訪問者的防方法,訪問者通過參數傳遞進來* @author xxliao* @date 2024/5/26 0:29*/@Overridepublic void result(ActionVisitor actionVisitor) {// 訪問者對象 獲取 本元素(man)對象的結果,將本對象自己傳遞進去,這里使用了雙分派actionVisitor.getManResult(this);}
}
package com.xxliao.pattern.behavioral.visitor.demo;/*** @author xxliao* @description: 具體元素角色* @date 2024/5/26 0:19*/
public class Woman extends Person{/*** @description 具體元素角色提供給訪問者的防方法,訪問者通過參數傳遞進來* @author xxliao* @date 2024/5/26 0:29*/@Overridepublic void result(ActionVisitor actionVisitor) {// 訪問者對象 獲取 本元素(woman)對象的結果,將本對象自己傳遞進去,這里使用了雙分派actionVisitor.getWomanResult(this);}
}
- 抽象訪問者角色
package com.xxliao.pattern.behavioral.visitor.demo;/*** @author xxliao* @description: 抽象訪問者角色,角色內定義訪問方法,一般來說要包括所有的具體抽象元素* @date 2024/5/26 0:18*/
public abstract class ActionVisitor {/*** @description Man get result* @author xxliao* @date 2024/5/26 0:20*/public abstract void getManResult(Man man);/*** @description Woman get result* @author xxliao* @date 2024/5/26 0:20*/public abstract void getWomanResult(Woman woman);
}
- 具體訪問者角色
package com.xxliao.pattern.behavioral.visitor.demo;/*** @author xxliao* @description: 具體訪問者角色 -成功* @date 2024/5/26 0:22*/
public class SuccessActionVisitor extends ActionVisitor{@Overridepublic void getManResult(Man man) {System.out.println("man --- success");}@Overridepublic void getWomanResult(Woman woman) {System.out.println("woman --- success");}
}
package com.xxliao.pattern.behavioral.visitor.demo;/*** @author xxliao* @description: 具體訪問者角色 -失敗* @date 2024/5/26 0:22*/
public class FailActionVisitor extends ActionVisitor{@Overridepublic void getManResult(Man man) {System.out.println("man --- fail");}@Overridepublic void getWomanResult(Woman woman) {System.out.println("woman --- fail");}
}
- 對象結構角色
package com.xxliao.pattern.behavioral.visitor.demo;import java.util.LinkedList;
import java.util.List;/*** @author xxliao* @description: 對象結構,需要定義存儲具體元素角色的容器,然后* @date 2024/5/26 0:24*/
public class ObjectStructure {// 定義存儲具體元素對象的容器private List<Person> persons = new LinkedList<>();// 添加具體元素對象public void addPerson(Person person) {persons.add(person);}// 移除具體元素對象public void removePerson(Person person) {persons.remove(person);}/*** @description 顯示最后結果* @author xxliao* @date 2024/5/26 0:35*/public void print(ActionVisitor actionVisitor){for (Person person : persons) {person.result(actionVisitor);}}
}
- 測試客戶端
package com.xxliao.pattern.behavioral.visitor.demo;/*** @author xxliao* @description: 訪問者模式 測似客戶端* @date 2024/5/26 0:36*/
public class Client {public static void main(String[] args) {// 創建 對象結構ObjectStructure objectStructure = new ObjectStructure();// 添加具體元素對象objectStructure.addPerson(new Man());objectStructure.addPerson(new Woman());// 創建訪問者具體對象 --成功SuccessActionVisitor successActionVisitor = new SuccessActionVisitor();// 對象結構 顯示最后結果objectStructure.print(successActionVisitor);}
}
- 測試結果
優缺點
- 優點:.在元素個數不變的情況下,增加新功能(具體訪問者對象),做到了開閉原則。
- 缺點:在元素個數要變化的情況下,所有的具體訪問者對象都要修改代碼, 不符合開閉原則。