其他分享
首页 > 其他分享> > 访问者模式Visitor —— 不出手则已,出手就所向披靡!

访问者模式Visitor —— 不出手则已,出手就所向披靡!

作者:互联网

大多情况下,都不需要使用访问者模式,但是一旦需要使用它时,那就真的需要使用了。

一、什么出手? 

既然一出手这么牛逼,那到底啥时候才会出手呢?

简单的说,就是当系统中存在一个结构比较稳定的对象,但是对它访问的者会经常改变,且不同的访问者并对其访问的操作也不同的时候,可以使用访问者模式。

 举个例子:前一阵赘婿比较火哈,就好比选女婿,女婿分为金龟婿(有钱的)和经济适用男(人品好可靠的),丈母娘和女朋友选择的标准是不一样的,丈母娘现实一点也希望自己的女儿以后衣食无忧,就会更关注女婿是否买的起房买得起车是否有钱,那女朋友一般就相信爱情一些,更看重男朋友人品可靠度一些。

这种场景就满足访问者模式的使用场景了,这里要选的女婿就是被访问者,那丈母娘和女朋友就是访问者,女婿无外乎就是有钱、人品、颜值这些可供参考的指标,也就是说上面说的被访问者的对象结构比较稳定,但是它有多个访问者(丈母娘、女朋友、老板。。。),且丈母娘、女朋友、老板关注的重点都不一样,也就是上面说的不同的访问者并对其访问的操作也不同。

二、什么是访问者模式?

为什么说上面的场景访问者模式就可以出手了呢?

如果说上面的场景,现在丈母娘和女朋友标准不一样,每个心里都有一个评分表,这样的逻辑要实现若不用访问者模式会怎样?

那必然会有if、else这样的语句,因为你要去判断是哪个访问者,然后去返回这个访问者关注的标准,也就是通过if、else来对不同访问者进行判别来进行分开处理。但是这样问题也很明显:类的职责重,大量的if-else代码一定不优雅,一旦访问者或者被访问对象需要修改/添加/移除等操作,这种方式基本就毫无扩展性而言。

那如果是访问者模式,它会去除if-else将各个不同的操作封装到不同的访问者对象类中去。为了方便扩展,对元素和访问者都提供了抽象层,而元素层,我们还需要通过一个对象结构(可以就理解为是一个集合,来定义这些元素的结构的)来对元素的结构进行组织。结构如下:

三、代码实现

用访问者模式来实现上面选女婿的代码:

/**
 * 抽象女婿类 —— 抽象元素
 */
public abstract class SonInLaw {

    private String name;
    // 有钱与否
    private String money;
    // 人品如何
    private String personality;

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

    public abstract void accept(Visitor visitor);
}
/**
 * 具体女婿类,有钱金龟女婿 —— 具体元素
 */

public class RichSonInLaw extends SonInLaw{

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

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public String getMoney(){
        return "每年挣一亿¥";
    }

}
/**
 * 具体女婿类,人品好的女婿 —— 具体元素
 */
public class PersonalitySonInLaw extends SonInLaw {


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

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public String getPersonality(){
        return "人品爆表";
    }
}
/**
 * 抽象访问者接口
 */
public interface Visitor {
    void visit(PersonalitySonInLaw personalitySonInLaw);

    void visit(RichSonInLaw richSonInLaw);
}
/**
 * 评分表 —— ObjectStructure,这个结构应该相对稳定,不经常修改
 */
public class ScoreTable {
    private List<SonInLaw> sonInLaws = new ArrayList<>();

    public ScoreTable() {
        sonInLaws.add(new RichSonInLaw("女婿一:金龟婿"));
        sonInLaws.add(new RichSonInLaw("女婿二:金龟婿"));
        sonInLaws.add(new PersonalitySonInLaw("女婿三:靠谱婿"));
        sonInLaws.add(new PersonalitySonInLaw("女婿四:靠谱婿"));
    }

    public void showScoredTable(Visitor visitor) {
        for (SonInLaw sonInLaw : sonInLaws) {
            sonInLaw.accept(visitor);
        }
    }
}
/**
 * 具体访问者 —— 丈母娘
 */
public class MotherInLaw implements Visitor{
    @Override
    public void visit(PersonalitySonInLaw personalitySonInLaw) {
        Console.log("我是丈母娘,人品都是浮云,重要的是要有钱!");
    }

    @Override
    public void visit(RichSonInLaw richSonInLaw) {
        Console.log(richSonInLaw.getMoney() + "的金龟婿我喜欢!");
    }
}
/**
 * 抽象访问者 —— 女朋友
 */
public class GirlFriend implements Visitor{
    @Override
    public void visit(PersonalitySonInLaw personalitySonInLaw) {
        Console.log(personalitySonInLaw.getPersonality() + "我喜欢!");
    }

    @Override
    public void visit(RichSonInLaw richSonInLaw) {
        Console.log("爱情价更高!");
    }
}
public class Client {
    public static void main(String[] args) {

        ScoreTable scoreTable = new ScoreTable();
        scoreTable.showScoredTable(new MotherInLaw());
        Console.log("====================");
        scoreTable.showScoredTable(new GirlFriend());
    }
}

重载的 visit 方法会对元素进行不同的操作,而通过注入不同的 Visitor 又可以替换掉访问者的具体实现,使得对元素的操作变得更灵活,可扩展性更高,同时也消除了类型转换、if-else 等“丑陋”的代码。

访问者模式最大的优点就是增加访问者非常容易,我们从代码中可以看到,如果要增加一个访问者,只要新实现一个 Visitor 接口的类,从而达到数据对象与数据操作相分离的效果。如果不实用访问者模式,而又不想对不同的元素进行不同的操作,那么必定需要使用 if-else 和类型转换,这使得代码难以升级维护。

四、适用场景

适用场景:

上面已经说过,当系统中存在一个结构比较稳定的对象,但是对它访问的者会经常改变,且不同的访问者并对其访问的操作也不同的时候,可以使用访问者模式。

具体的

访问者使用的条件较为苛刻,结构也很复杂,所以实际应用使用的频率不高。当你系统中存在一个比较复杂的对象结构,并且存在着不同的访问者并对其访问的操作也不同的时候,可以使用访问者模式。

现有的一些实际应用:XML文档解析,编译器设计等。

标签:出手,Visitor,void,元素,visit,public,访问者
来源: https://blog.csdn.net/weixin_41231928/article/details/116309814