设计模式-访问者模式

时间:2022-07-25
本文章向大家介绍设计模式-访问者模式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

背景

记得去北京旅游的时候,有一件痛苦的事情就是上厕所,真是件非常痛苦的事情,有时候人一多,女厕所人太多了,直接跑到男的这边来了,搞得很无语,第一次看到这种壮观....不过上厕所男女有别倒是类似于访问者,不同的人根据不同的身份访问不同的厕所。

访问者模式是什么?

访问者模式(Visitor Pattern)是一个行为模式,封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。

角色

Visitor:访问者接口,为所有的访问者对象声明一个visit方法,用来代表为对象结构添加的功能,理论上可以代表任意的功能。

ConcreteVisitor :具体访问者,主要是实现方法者的实现;

Element:抽象元素:接口或者抽象类,主要声明顶层的设计,接受访问的操作。

ConcreteElement :具体的元素或对象,提供自数据和功能给访问者使用。

ObjectStruture:对象结构,通常包含多个访问对象。

访问者模式可以干嘛?

访问者模式主要解决的一个问题就是不用区分元素是哪种,而根据访问者的不同信息返回相应的信息,就好比文件夹中有文件,通过访问者的信息来判断你是文件还是文件夹。并也不用改变原有结构而很容易就实现了这种区别。

优点:

遵循设计规则:符合单一职责原则

拓展性强:可以拓展多个元素,不同的访问器

缺点:

保密性不好:对访问者公布了细节,违反了迪米特原则。

个人理解:

访问者就像不同的性别进入不同的厕所,人是元素,性别是访问类型。

访问者模式类图

源码下载:https://gitee.com/hong99/design-model/issues/I1IMES

实现代码

/**
 * @ClassName IVisitor
 * @Author csh
 * @Description 抽象访问者(Visitor)
 * @Date 2020/6/22
 **/
public interface IVisitor {
    void visit(Person person);
}
/**
 * @ClassName Person
 * @Author csh
 * @Description 人 抽象元素(Element)
 * @Date 2020/6/22
 **/
public abstract class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //抽象访问接口
    public abstract void accept(IVisitor visitor);
}

/**
 * @ClassName Male
 * @Author csh
 * @Description 具体元素(ConcreteElement )
 * @Date 2020/6/22
 **/
public class Male extends Person {

    public Male(String name) {
        super(name);
    }

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}
/**
 * @ClassName Woman
 * @Author csh  具体元素(ConcreteElement )
 * @Description
 * @Date 2020/6/22
 **/
public class Woman extends Person {

    public Woman(String name) {
        super(name);
    }

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}
/**
 * @ClassName ManVisitor
 * @Author csh  具体访问者(ConcreteVisitor)
 * @Description
 * @Date 2020/6/22
 **/
public class ManVisitor implements IVisitor {
    @Override
    public void visit(Person person) {
        if(person instanceof Male){
            System.out.println(person.getName()+"进入男厕所!");
        }
    }
}

/**
 * @ClassName WomanVisitor
 * @Author csh  具体访问者(ConcreteVisitor)
 * @Description
 * @Date 2020/6/22
 **/
public class WomanVisitor implements IVisitor {
    @Override
    public void visit(Person person) {
        if(person instanceof Woman){
            System.out.println(person.getName()+"进入女厕所!");
        }
    }
}
/**
 * @ClassName ObjectStructure
 * @Author csh  ObjectStruture(对象结构)
 * @Description
 * @Date 2020/6/22
 **/
public class ObjectStructure {
    private List<Person> personList = new ArrayList<Person>();

    public void action(IVisitor visitor){
        for (Person person : personList) {
            person.accept(visitor);
        }
    }

    public void add(Person person){
        personList.add(person);
    }

    public void remove(Person person){
        personList.remove(person);
    }
}
/**
 * @ClassName Client
 * @Author csh
 * @Description 演示访问者模式,不能人进入不同厕所
 * @Date 2020/6/22
 **/
public class Client {
    public static void main(String[] args) {
        Person man1 = new Male("hong1");
        Person man2 = new Male("hong2");
        Person woman1 =new Woman("min1");
        Person woman2= new Woman("min2");
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.add(man1);
        objectStructure.add(man2);
        objectStructure.add(woman1);
        objectStructure.add(woman2);
        //男厕所
        IVisitor man = new ManVisitor();
        //女厕所
        IVisitor woman = new WomanVisitor();
        //进入男厕所
        objectStructure.action(man);
        //进入女厕所
        objectStructure.action(woman);
    }
}

结果

hong1进入男厕所!
hong2进入男厕所!
min1进入女厕所!
min2进入女厕所!

源码下载:https://gitee.com/hong99/design-model/issues/I1IMES

最后

访问者在实际项目中除了非常稳定的数据结构者会使用,并且该模式相对来说比较绕,一般代码可读性不是很高并且一般都用于系统重构中,最大的好处就是结构统一,在实际应用中,其实还有通过元素本身来做进一步业务处理。

使用到访问者模式的场景

Java8 新特性之集合:forEach(Consumer<? super T> action)