访问者模式
场景:部队招人时的面试官以及工厂招人的面试官是visitor,被面试的男人和女人是被访问的Element,
要点:
1. 抽象的Person(又叫Element)里有个accept(visitor)函数,该函数里调用了visitor.visit(this)。
2. 抽象的Visitor(抽象面试官)里分别定义了visit(Man)和visit(Women)两个抽象方法。方法名相同,但参数不同,应该叫做重载吧。
3. 具体的ConcreteVisitor(例如ArmyVisitor和FactoryVisitor)根据自己的逻辑对visit(Man)和visit(Women)进行了实现。这个没啥。
下面这个UML图我觉得不标准,Visitor应该有虚线的依赖具体的Main和Woman,而抽象的Person应该有虚线的依赖接口Visitor
有几个疑问,为什么不能在使用程序里(比如Main()函数)直接调用visitor.visit(man),而非要通过man.accept(visitor)来绕一圈呢?有啥好处?
---------分割线以下的是我后来想明白了补充的-----------------------------------------------------------------------
如果你用的语言支持函数重载,那么就像我的疑问里提的,完全可以直接在使用程序里直接调用visitor.visit(man),没必要用访问者模式,用了也没啥好处,反而降低了代码的可读性。
但是有一些语言不支持函数重载(像C,python,javascript),这种情况下的访问者模式就不能像上面那么写了。应该咋写呢?看下图
区别只有一点,对于不支持函数重载的语言,visitor只能定义不同的函数名来访问不同的具体Element了。(支持重载的语言里,visitor是通过相同的函数名传入不同的具体Element参数,通过函数重载实现的。)
这时候,有这么一种场景:有一个person的list,list里有多个对象(男人1,男人2,女人1,女人2,男人3,男人4,男人5,女人3……)。
如果不使用访问者模式,遍历访问list的时候,应该对list里的每个元素先判断一下是男人还是女人,如果是男人则调用visitor.visitMan(),是女人则调用visitor.visitWoman()。总之比较麻烦啦。
而用了访问者模式了呢?只需要对list里的persion们挨个调用一下persion.accept(visitor)即可。
最后总结一下不适用场景
1. 被访问的Element可以有多个具体实例,但Element的子类必须是固定的。
如果不是固定的,时不时多加个子类,那么没添加一个子类,Visitor就必须要添加一个visit函数,并且visitor所有的子类也要跟着修改。太麻烦了。
打个比方,比如在Man和Woman的基础上又添加个机器人,那么Visitor接口就必须要添加一个visit(Robot)函数,并且ArmyVisitor和FactoryVisitor也要实现这个函数。如果还有其他的visitor改的更多。