設計模式學習(十九):訪問者模式
設計模式學習(十九):訪問者模式
作者:Grey
原文地址:
訪問者模式
訪問者模式是一種行為型模式。
訪問者模式在結構不變的情況下動態改變對於內部元素的動作。
舉例說明:
假設我們需要構造一台電腦,有主板( Board ),CPU ,記憶體( Memory ),但是針對企業用戶和個人用戶,電腦組件的價格是不一樣的,我們需要根據不同客戶獲取一台電腦的總價格。
我們先抽象出電腦組件這個類
public abstract class ComputerPart {
abstract void accept(Visitor visitor);
abstract int getPrice();
}
每個具體組件會繼承這個抽象類,以主板( Board )為例
public class Board extends ComputerPart {
@Override
void accept(Visitor visitor) {
visitor.visitBoard(this);
}
@Override
int getPrice() {
return 20;
}
}
抽象出一個訪問者( Visitor )介面,
public interface Visitor {
void visitCPU(CPU cpu);
void visitBoard(Board board);
void visitMemory(Memory memory);
}
每個具體類型的訪問者實現這個介面,然後定義其不同的價格策略,以公司訪問者為例( CorpVisitor )
public class CorpVisitor implements Visitor {
private int totalPrice;
@Override
public void visitCPU(CPU cpu) {
totalPrice += cpu.getPrice() - 1;
}
@Override
public void visitBoard(Board board) {
totalPrice += board.getPrice() - 2;
}
@Override
public void visitMemory(Memory memory) {
totalPrice += memory.getPrice() - 3;
}
public int getTotalPrice() {
return totalPrice;
}
}
個人訪問者( PersonalVisitor )類似
public class PersonalVisitor implements Visitor {
private int totalPrice;
@Override
public void visitCPU(CPU cpu) {
totalPrice += cpu.getPrice() + 1;
}
@Override
public void visitBoard(Board board) {
totalPrice += board.getPrice() + 2;
}
@Override
public void visitMemory(Memory memory) {
totalPrice += memory.getPrice() + 3;
}
public int getTotalPrice() {
return totalPrice;
}
}
主方法調用方式如下
public class Main {
public static void main(String[] args) {
ComputerPart cpu = new CPU();
ComputerPart memory = new Memory();
ComputerPart board = new Board();
PersonalVisitor personalVisitor = new PersonalVisitor();
cpu.accept(personalVisitor);
memory.accept(personalVisitor);
board.accept(personalVisitor);
System.out.println(personalVisitor.getTotalPrice());
ComputerPart cpu2 = new CPU();
ComputerPart memory2 = new Memory();
ComputerPart board2 = new Board();
CorpVisitor corpVisitor = new CorpVisitor();
cpu2.accept(corpVisitor);
memory2.accept(corpVisitor);
board2.accept(corpVisitor);
System.out.println(corpVisitor.getTotalPrice());
}
}
可以看到,不同的訪問者,對於電腦的價格是不一樣的。
上述示例的 UML 圖如下
訪問者模式的應用
Java SE 中的 FileVisitor 使用了訪問者模式,使用示例
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
/**
* @author <a href="mailto:[email protected]">GreyZeng</a>
* @version 1.0, 2022/8/11
*/
public class FileVisitorTest {
public static void main(String[] args) throws IOException {
// 使用FileVisitor對目錄進行遍歷
// 訪問當前目錄的所有文件
Files.walkFileTree(Paths.get("."), new SimpleFileVisitor<Path>() {
// 在訪問子目錄前觸發該方法
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
System.out.println("正在訪問" + dir + "目錄");
return FileVisitResult.CONTINUE;
}
// 在訪問文件時觸發該方法
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("正在訪問" + file + "文件");
return FileVisitResult.CONTINUE;
}
// 在訪問失敗時觸發該方法
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
// 寫一些具體的業務邏輯
return super.visitFileFailed(file, exc);
}
// 在訪問目錄之後觸發該方法
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
// 寫一些具體的業務邏輯
return super.postVisitDirectory(dir, exc);
}
});
}
}
其他應用
-
做編譯器的時候,需要生成 AST ,進行類型檢查 根據抽象語法樹,生成中間程式碼;
-
XML 文件解析;
-
Spring 中的 BeanDefinitionVisitor;