欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

行为模式之访问者模式

程序员文章站 2022-05-18 18:20:32
访问者模式(Visitor Pattern)的目的是封装一些于某种数据结构元素之上的操作,一旦这些元素需要修改,接受这个操作的数据结构则可以保持不变。 定义: 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义于作用这些元素的新的操作。 访问者模式的类图如下。 访问者模式 ......

访问者模式(visitor pattern)的目的是封装一些于某种数据结构元素之上的操作,一旦这些元素需要修改,接受这个操作的数据结构则可以保持不变。

定义:

  • 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义于作用这些元素的新的操作。

访问者模式的类图如下。

行为模式之访问者模式

访问者模式涉及以下5个角色。

  • 抽象访问者(visitor)角色:该角色声明一个或多个访问操作,定义访问者可以访问哪些元素。
  • 具体访问者(concrete visitor)角色:该角色实现抽象访问者角色中的各个访问操作。
  • 抽象元素(element)角色:声明一个接受操作,接受一个访问者对象。
  • 具体元素(concrete element)角色:实现抽象元素中的接受操作。
  • 结构对象(object structure)角色:该角色有以下责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素,也可以设计一个复合对象或者一个集合,如list或set.

element.java

// 抽象元素角色
public abstract class element {
    // 接受操作
    public abstract void accept(visitor vi);
}

concreteelement1.java

// 具体元素1
public class concreteelement1 extends element {
    @override
    public void accept(visitor vi) {
        vi.visit(this);
    }
    // 业务逻辑方法
    public void operation() {
        system.out.println("访问元素1");
    }
}

concreteelement2.java

//具体元素2
public class concreteelement2 extends element {
    @override
    public void accept(visitor vi) {
        vi.visit(this);
    }
    // 业务逻辑方法
    public void operation() {
        system.out.println("访问元素2");
    }
}

visitor.java

// 抽象访问者
public interface visitor {
    // 可以访问哪些对象
    public void visit(concreteelement1 el1);
    public void visit(concreteelement2 el2);
}

concretevisitor.java

// 具体访问者角色
public class concretevisitor implements visitor {
    // 访问元素1
    @override
    public void visit(concreteelement1 el1) {
        el1.operation();
    }
    // 访问元素2
    @override
    public void visit(concreteelement2 el2) {
        el2.operation();
    }
}

objectstructure.java

// 结构对象角色
public class objectstructure {
    private vector<element> elements;
    // 构造函数
    public objectstructure() {
        this.elements = new vector<element>(); 
    }
    // 执行访问操作
    public void action(visitor vi) {
        for (element e : elements) {
            e.accept(vi);
        }
    }
    // 添加新元素
    public void add(element e) {
        elements.add(e);
    }
    // 元素生成器,这里通过一个工厂方法进行模拟
    public void createelements() {
        random rand = new random();
        for (int i = 0; i < 10; i++) {
            if (rand.nextint(100) > 50) {
                // 添加元素1
                this.add(new concreteelement1());
            } else {
                // 添加元素2
                this.add(new concreteelement2());
            }
        }
    }
    
}

client.java

public class client {
    public static void main(string[] args) {
        // 创建一个结构对象
        objectstructure os = new objectstructure();
        // 生成元素
        os.createelements();
        // 创建一个访问者对象
        visitor vi = new concretevisitor();
        // 访问者对结构进行访问(执行访问)
        os.action(vi);
    }
}

运行结果如下所示。

访问元素1
访问元素1
访问元素1
访问元素2
访问元素2
访问元素2
访问元素1
访问元素1
访问元素1
访问元素2

 优点:

  • 元素(element)角色负责数据加载,visitor负责数据展现。
  • 增加新的操作,直接在visitor中增加一个方法。
  • 集中行为,系统容易维护。

缺点:

  • 具体元素对访问者公布细节,破坏封装性;
  • 具体元素变更变更变得困难。具体元素的增加和修改等,需要具体访问者修改。
  • 违背了依赖倒置原则。访问者依赖的是具体元素,而不是抽象元素,抛弃了对接口的依赖,而直接依赖实现类,扩展比较困难。

应用场景:

  • 一个对象结构包含很多类对象,它们有不同的接口。
  • 需要对一个对象结构中的对象进行很多不同并且不相关的操作,避免操作污染类。
  • 业务规则要求遍历多个不同的对象,这本身也是访问模式的出发点,迭代器模式只能访问同类或同接口的数据,而访问者模式是对迭代器模式的扩充,可以遍历不同的对象,执行不同的操作。

摘自:

青岛东合信息技术有限公司 . 设计模式(java版) .  电子工业出版社,2012,161-166.