前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式(二十四) 访问者模式

设计模式(二十四) 访问者模式

作者头像
乐百川
发布2018-01-08 18:31:15
1.1K0
发布2018-01-08 18:31:15
举报

访问者模式提供了一种方法,将算法和数据结构分离。假设我们需要对一个数据结构进行不同的操作,就可以考虑使用访问者模式。访问者模式的要点在于,需要一个访问者接口,提供了一些重载方法来访问具体对象。对于每个具体对象,又提供了一个accept方法来回调访问者。

首先来看看访问者。

代码语言:javascript
复制
public interface Visitor {
    void visit(House house);

    void visit(Kitchen kitchen);

    void visit(LivingRoom livingRoom);

    void visit(BedRoom bedRoom);
}

class HouseVisitor implements Visitor {
    public void visit(House house) {
        System.out.println("访问了房子");
    }

    public void visit(BedRoom bedRoom) {
        System.out.println("访问了卧室");
    }

    public void visit(LivingRoom livingRoom) {
        System.out.println("访问了客厅");
    }

    public void visit(Kitchen kitchen) {
        System.out.println("访问了厨房");
    }
}

然后是要访问的对象,这里是一间屋子。

代码语言:javascript
复制
public class House {
    private LivingRoom livingRoom;
    private Kitchen kitchen;
    private BedRoom bedRoom;

    public House() {
        livingRoom = new LivingRoom();
        kitchen = new Kitchen();
        bedRoom = new BedRoom();
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
        livingRoom.accept(visitor);
        bedRoom.accept(visitor);
        kitchen.accept(visitor);
    }
}

class LivingRoom {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class Kitchen {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class BedRoom {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

然后客户端就可以简单的访问屋子了。

代码语言:javascript
复制
    public void run() {
        Visitor visitor = new HouseVisitor();
        House house = new House();
        visitor.visit(house);
    }

这就是访问者模式了。可能会同学会有疑问,为什么我要这么写?如果让屋子对象层次全部都实现Visitor接口,然后客户端直接调用这些visit方法不是也可以吗?一开始我也有这个疑问,后来看了知乎轮子哥的一篇文章ParserGen生成预定义好的各种visitor,感觉茅塞顿开。

其实Visitor模式讲的就是在不需要扩充新的子类的时候,如何添加新的虚函数而不需要修改原有代码。当然虚函数也有它的好处,就是添加新的子类的时候不需要修改原有代码。所以看你的业务逻辑,到底是添加新子类多,还是添加新虚函数多,从而选择要不要把程序写成基于Visitor模式的样子。 对于编译器来说,整个处理流程那么复杂,所以等于需要经常添加虚函数,因此就都把本来是虚函数的东西改成了各种Visitor。这个时候,如果你修改了语法,那么每一个Visitor都会曝出语法错误,所以这等于变相通知你所有需要修改的东西在哪里——如果你能坚持不因为偷懒而使用dynamic_cast的话。

所谓设计模式,都需要在特定的环境中才有用。所以现在我们已经了解了什么情况下应该使用访问者模式。假如接口中的方法固定,但是需要添加新的实现类,那么就使用普通的继承方式。如果接口方法经常变动,就可以把接口改写为访问者。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年04月06日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档