简介
访问者模式(Visitor Pattern)是一种行为型模式。它封装一个访问者类,把各元素类的操作集合起来,目的是将数据结构与数据操作分离。在不改变原有元素类数据结构的前提下,改变了元素类的执行算法。
当某些较为稳定的东西(数据结构或算法),不想直接被改变但又想扩展功能,这时候适合用访问者模式。访问者模式的使用频率并不是很高,大多数情况下,你并不需要使用访问者模式,但是当你一旦需要使用它时,那你就是需要使用它了。
访问者模式有以下几个角色:
- 结构对象(ObjectStructure):结构对象角色,这是访问者模式的基础角色,包含多个类或者接口.
- 抽象元素(Element):定义一个接受访问操作accept(),以一个访问者Visitor作为参数。
- 具体元素(ConcreteElement):实现抽象节点的accept()方法和处理操作,调用Vistor的访问方法实现具体功能。
- 抽象访问者(Visitor):定义一个抽象接口,声明一个或多个访问操作,使得所有具体访问者都必须实现。
- 具体访问者(ConcreteVisitor):具体访问者角色,实现Visitor声明的接口。
作用
- 在数据基础类里面有一个方法接受访问者,将自身引用传入访问者,从而把不变的固定起来,把变化的开放出去。
- 通过隔离类中变化的东西,固定不变的东西,符合单一职责原则,同时具备较好的扩展性和灵活性。
实现步骤
- 先创建基本元素抽象类Element,确定accept()抽象方法。
- 分别创建几个具体的元素类,实现抽象元素的accept方法。
- 在创建Visitor抽象接口,定义visit方法,调用具体元素。
- 创建1个或多个Visitor类,继承抽象接口,客户将以此去访问具体元素。
- 再创建对象结构类,这是核心入口类,负责组合各种元素,以及传递访问者Visitor。
- 客户调用时先创建对象结构类,再指定访问者类,通过访问这类调用具体元素类
UML
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);
- }
- // 传入访问者分发给其他元素
- 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(),接受传入的访问者
- * 对象结构向其他元素负责分发访问者,元素对象接受之后会将自己回传给访问者,从而访问者可以访问具体元素
- */
- 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)
- }
- // 传入访问者分发给其他元素
- 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(),接受传入的访问者
- * 对象结构向其他元素负责分发访问者,元素对象接受之后会将自己回传给访问者,从而访问者可以访问具体元素
- */
- structure := src.ObjectStructure{}
- structure.Init()
- // 接受访问者A,把访问者传递给具体元素
- structure.Accept(&src.ConcreteVisitorA{})
- fmt.Println("====")
- // 接受访问者B,把访问者传递给具体元素
- structure.Accept(&src.ConcreteVisitorB{})
- }
复制代码 更多语言版本
不同语言设计模式源码:https://github.com/microwind/design-pattern
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |