(相关资料图)
访问者模式(Visitor Pattern)是一种行为型模式。它封装一个访问者类,把各元素类的操作集合起来,目的是将数据结构与数据操作分离。在不改变原有元素类数据结构的前提下,改变了元素类的执行算法。
当某些较为稳定的东西(数据结构或算法),不想直接被改变但又想扩展功能,这时候适合用访问者模式。访问者模式的使用频率并不是很高,大多数情况下,你并不需要使用访问者模式,但是当你一旦需要使用它时,那你就是需要使用它了。
访问者模式有以下几个角色:
// ObjectStructure.java 结构对象(ObjectStructure)public class ObjectStructure { // 可以想象为一台电脑,聚合了各种设备元素 private String name = "Computer Structure"; private List elements = new ArrayList(); // 结构对象初始化聚合了其他元素 public ObjectStructure() { addElement(new ConcreteElementA()); addElement(new ConcreteElementB()); } public void addElement(Element element) { elements.add(element); } // 传入访问者分发给其他元素 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 具体访问者Apublic 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 具体访问者Bpublic 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 具体的元素实现者Apublic 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 具体的元素实现者Bpublic 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(),接受传入的访问者 * 对象结构向其他元素负责分发访问者,元素对象接受之后会将自己回传给访问者,从而访问者可以访问具体元素 */ ObjectStructure structure = new ObjectStructure(); // 接受访问者A,把访问者传递给具体元素 structure.accept(new ConcreteVisitorA()); System.out.println("===="); // 接受访问者B,把访问者传递给具体元素 structure.accept(new ConcreteVisitorB());
// ObjectStructure.go 结构对象(ObjectStructure)type ObjectStructure struct { name string elements []Element}func (o *ObjectStructure) AddElement(e Element) { o.elements = append(o.elements, e)}// 传入访问者分发给其他元素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 具体访问者Atype 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 具体访问者Btype 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 具体的元素实现者Atype 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 具体的元素实现者Btype 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(),接受传入的访问者 * 对象结构向其他元素负责分发访问者,元素对象接受之后会将自己回传给访问者,从而访问者可以访问具体元素 */ structure := src.ObjectStructure{} structure.Init() // 接受访问者A,把访问者传递给具体元素 structure.Accept(&src.ConcreteVisitorA{}) fmt.Println("====") // 接受访问者B,把访问者传递给具体元素 structure.Accept(&src.ConcreteVisitorB{})}
不同语言设计模式源码:https://github.com/microwind/design-pattern