簡介
訪問者模式(Visitor Pattern)是一種行為型模式。它封裝一個訪問者類,把各元素類的操作集合起來,目的是將數據結構與數據操作分離。在不改變原有元素類數據結構的前提下,改變了元素類的執(zhí)行算法。
當某些較為穩(wěn)定的東西(數據結構或算法),不想直接被改變但又想擴展功能,這時候適合用訪問者模式。訪問者模式的使用頻率并不是很高,大多數情況下,你并不需要使用訪問者模式,但是當你一旦需要使用它時,那你就是需要使用它了。
訪問者模式有以下幾個角色:
- 結構對象(ObjectStructure):結構對象角色,這是訪問者模式的基礎角色,包含多個類或者接口.
- 抽象元素(Element):定義一個接受訪問操作accept(),以一個訪問者Visitor作為參數。
- 具體元素(ConcreteElement):實現抽象節(jié)點的accept()方法和處理操作,調用Vistor的訪問方法實現具體功能。
- 抽象訪問者(Visitor):定義一個抽象接口,聲明一個或多個訪問操作,使得所有具體訪問者都必須實現。
- 具體訪問者(ConcreteVisitor):具體訪問者角色,實現Visitor聲明的接口。
作用
- 在數據基礎類里面有一個方法接受訪問者,將自身引用傳入訪問者,從而把不變的固定起來,把變化的開放出去。
- 通過隔離類中變化的東西,固定不變的東西,符合單一職責原則,同時具備較好的擴展性和靈活性。
實現步驟
- 先創(chuàng)建基本元素抽象類Element,確定accept()抽象方法。
- 分別創(chuàng)建幾個具體的元素類,實現抽象元素的accept方法。
- 在創(chuàng)建Visitor抽象接口,定義visit方法,調用具體元素。
- 創(chuàng)建1個或多個Visitor類,繼承抽象接口,客戶將以此去訪問具體元素。
- 再創(chuàng)建對象結構類,這是核心入口類,負責組合各種元素,以及傳遞訪問者Visitor。
- 客戶調用時先創(chuàng)建對象結構類,再指定訪問者類,通過訪問這類調用具體元素類
UML
?文章來源:http://www.zghlxwxcb.cn/news/detail-433233.html
Java代碼
結構對象
// ObjectStructure.java 結構對象(ObjectStructure)
public class ObjectStructure {
// 可以想象為一臺電腦,聚合了各種設備元素
private String name = "Computer Structure";
private List<Element> elements = new ArrayList<Element>();
// 結構對象初始化聚合了其他元素
public ObjectStructure() {
addElement(new ConcreteElementA());
addElement(new ConcreteElementB());
}
public void addElement(Element element) {
elements.add(element);
}
// 傳入訪問者分發(fā)給其他元素
public void accept(Visitor visitor) {
System.out
.println("ObjectStructure::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = "
+ visitor.getName() + "]");
for (Element element : elements) {
element.accept(visitor);
}
}
public String getName() {
return this.name;
}
}
抽象訪問者類
// Visitor.java 訪問者Visitor抽象接口,定義不同的visit方法
public interface Visitor {
public void visit(ConcreteElementA concreteElementA);
public void visit(ConcreteElementB concreteElementB);
public String getName();
}
具體訪問者
// ConcreteVisitorA.java 具體訪問者A
public class ConcreteVisitorA implements Visitor {
// 假如由不同廠商是程序的訪問者
private String name = "Google Visitor";
@Override
public void visit(ConcreteElementA concreteElementA) {
System.out.println(
"ConcreteVisitorA::visit() [Element.class = " + concreteElementA.getClass().getSimpleName()
+ " Element.name = "
+ concreteElementA.getName() + "]");
concreteElementA.operate();
}
@Override
public void visit(ConcreteElementB concreteElementB) {
System.out.println("ConcreteVisitorA::visit() [Element.class = " + concreteElementB.getClass().getSimpleName()
+ " Element.name = "
+ concreteElementB.getName() + "]");
concreteElementB.operate();
}
public String getName() {
return this.name;
}
}
// ConcreteVisitorB.java 具體訪問者B
public class ConcreteVisitorB implements Visitor {
// 假如由不同廠商是程序的訪問者
private String name = "Apple Visitor";
@Override
public void visit(ConcreteElementA concreteElementA) {
System.out.println(
"ConcreteVisitorB::visit() [Element.class = " + concreteElementA.getClass().getSimpleName()
+ " Element.name = "
+ concreteElementA.getName() + "]");
concreteElementA.operate();
}
@Override
public void visit(ConcreteElementB concreteElementB) {
System.out.println(
"ConcreteVisitorB::visit() [Element.class = " + concreteElementB.getClass().getSimpleName()
+ " Element.name = "
+ concreteElementB.getName() + "]");
concreteElementB.operate();
}
public String getName() {
return this.name;
}
}
抽象元素類
// Element.java 抽象元素(Element),定義accept方法,傳入抽象訪問者
abstract class Element {
public abstract void accept(Visitor visitor);
}
具體元素實現類
// ConcreteElementA.java 具體的元素實現者A
public class ConcreteElementA extends Element {
// 可以設想為顯示器
private String name = "Monitor Element";
@Override
public void accept(Visitor visitor) {
System.out
.println(
"ConcreteElementA::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = "
+ visitor.getName() + "]");
visitor.visit(this);
}
public void operate() {
System.out.println("ConcreteElementA::operate() [" + this.getName() + "]");
}
public String getName() {
return this.name;
}
}
// ConcreteElementB.java 具體的元素實現者B
public class ConcreteElementB extends Element {
private String name = "Keyboard Element";
@Override
public void accept(Visitor visitor) {
System.out.println(
"ConcreteElementB::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = "
+ visitor.getName() + "]");
visitor.visit(this);
}
public void operate() {
System.out.println("ConcreteElementB::operate() [" + this.getName() + "]");
}
public String getName() {
return this.name;
}
}
測試調用
/**
* 訪問者模式是當客戶需要訪問具體各元素Element時,先建立一個訪問者Visitor作為媒介
* 客戶基于對象結構ObjectStructure,調用accept(),接受傳入的訪問者
* 對象結構向其他元素負責分發(fā)訪問者,元素對象接受之后會將自己回傳給訪問者,從而訪問者可以訪問具體元素
*/
ObjectStructure structure = new ObjectStructure();
// 接受訪問者A,把訪問者傳遞給具體元素
structure.accept(new ConcreteVisitorA());
System.out.println("====");
// 接受訪問者B,把訪問者傳遞給具體元素
structure.accept(new ConcreteVisitorB());
Go代碼
結構對象
// ObjectStructure.go 結構對象(ObjectStructure)
type ObjectStructure struct {
name string
elements []Element
}
func (o *ObjectStructure) AddElement(e Element) {
o.elements = append(o.elements, e)
}
// 傳入訪問者分發(fā)給其他元素
func (o *ObjectStructure) Accept(v Visitor) {
fmt.Println(
"ObjectStructure::Accept() [Visitor.name = " +
v.GetName() + "]")
// 通知全部元素成員接受訪問者
for i := 0; i < len(o.elements); i++ {
o.elements[i].Accept(v)
}
// for _, ele := range o.elements {
// ele.Accept(v)
// }
}
func (o *ObjectStructure) GetName() string {
o.name = "Computer Structure"
return o.name
}
// 結構對象的初始化函數
func (o *ObjectStructure) Init() {
// 可以想象為一臺電腦,聚合了各種設備元素
fmt.Println("ObjectStructure::Init() ", o.GetName())
// 定義一個對象數組,長度可選
o.elements = make([]Element, 0, 100)
// 結構對象初始化聚合了其他元素
o.AddElement(&ConcreteElementA{})
o.AddElement(&ConcreteElementB{})
}
抽象訪問者類
// Visitor.go 訪問者Visitor抽象接口,定義不同的visit方法
type Visitor interface {
VisitA(e *ConcreteElementA)
VisitB(e *ConcreteElementB)
GetName() string
}
具體訪問者
// ConcreteVisitorA.go 具體訪問者A
type ConcreteVisitorA struct {
name string
}
func (v *ConcreteVisitorA) GetName() string {
v.name = "Google Visitor(struct=ConcreteVisitorA)"
return v.name
}
func (v *ConcreteVisitorA) VisitA(e *ConcreteElementA) {
fmt.Println(
"ConcreteVisitorA::VisitA() [Element.name = " + e.GetName() + "]")
e.Operate()
}
func (v *ConcreteVisitorA) VisitB(e *ConcreteElementB) {
fmt.Println(
"ConcreteVisitorA::VisitB() [Element.name = " + e.GetName() + "]")
e.Operate()
}
// ConcreteVisitorB.go 具體訪問者B
type ConcreteVisitorB struct {
name string
}
func (v *ConcreteVisitorB) GetName() string {
v.name = "Apple Visitor(struct=ConcreteVisitorB)"
return v.name
}
func (v *ConcreteVisitorB) VisitB(e *ConcreteElementB) {
fmt.Println(
"ConcreteVisitorB::VisitB() [Element.name = " + e.GetName() + "]")
e.Operate()
}
func (v *ConcreteVisitorB) VisitA(e *ConcreteElementA) {
fmt.Println(
"ConcreteVisitorB::VisitA() [Element.name = " + e.GetName() + "]")
e.Operate()
}
抽象元素類
// Element.go 抽象元素(Element),定義accept方法,傳入抽象訪問者
// go無抽象類,用interface替代
type Element interface {
Accept(v Visitor)
Operate()
GetName() string
}
具體元素實現類
// ConcreteElementA.go 具體的元素實現者A
type ConcreteElementA struct {
name string
}
func (c *ConcreteElementA) GetName() string {
c.name = `Monitor Element(struct=ConcreteElementA)`
return c.name
}
func (e *ConcreteElementA) Accept(v Visitor) {
fmt.Println(
"ConcreteElementA::Accept() [Visitor.name = " + v.GetName() + "]")
v.VisitA(e)
}
func (e *ConcreteElementA) Operate() {
fmt.Println("ConcreteElementA::Operate() [" + e.GetName() + "]")
}
// ConcreteElementB.go 具體的元素實現者B
type ConcreteElementB struct {
name string
}
func (c *ConcreteElementB) GetName() string {
c.name = "Keyboard Element(struct=ConcreteElementB)"
return c.name
}
func (e *ConcreteElementB) Accept(v Visitor) {
fmt.Println(
"ConcreteElementB::Accept() [Visitor.name = " + v.GetName() + "]")
v.VisitB(e)
}
func (e *ConcreteElementB) Operate() {
fmt.Println("ConcreteElementB::Operate() [" + e.GetName() + "]")
}
測試調用
func main() {
fmt.Println("test start:")
/**
* 訪問者模式是當客戶需要訪問具體各元素Element時,先建立一個訪問者Visitor作為媒介
* 客戶基于對象結構ObjectStructure,調用Accept(),接受傳入的訪問者
* 對象結構向其他元素負責分發(fā)訪問者,元素對象接受之后會將自己回傳給訪問者,從而訪問者可以訪問具體元素
*/
structure := src.ObjectStructure{}
structure.Init()
// 接受訪問者A,把訪問者傳遞給具體元素
structure.Accept(&src.ConcreteVisitorA{})
fmt.Println("====")
// 接受訪問者B,把訪問者傳遞給具體元素
structure.Accept(&src.ConcreteVisitorB{})
}
更多語言版本
不同語言設計模式源碼:https://github.com/microwind/design-pattern文章來源地址http://www.zghlxwxcb.cn/news/detail-433233.html
到了這里,關于【訪問者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實現的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!