python设计模式之访问者模式
意图
- 封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
使用场景
- 假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去
- 一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去
- 访问者模式并不是那么完美,它也有着致命的缺陷:增加新的元素类比较困难。通过访问者模式的代码可以看到,在访问者类中,每一个元素类都有它对应的处理方法,也就是说,每增加一个元素类都需要修改访问者类(也包括访问者类的子类或者实现类),修改起来相当麻烦。也就是说,在元素类数目不确定的情况下,应该慎用访问者模式。所以,访问者模式比较适用于对已有功能的重构
例子
- 这里是个构建车的例子,每个部件都有一个accept的方法接受我上面说的所谓’访问者’,而这个访问者 以参数的方式传进来,但是其实他是一个含有一些功能的类的实例,它拥有很多个visit开头的方法对应不同的部件。 这样就不需要修改这些部件,而只是修改我们的访问者类的相关部分
class Wheel(object):
"""
轮子,引擎, 车身这些定义好了都不需要变动
"""
def __init__(self, name):
self.name = name
def accept(self, visitor):
"""
每个visitor是同样的,但是其中的方法是不一样的,比如这里是visit_wheel,
然后传入了self,想想?他其实想做什么就能做什么
:param visitor:
:return:
"""
visitor.visit_wheel(self)
class Engine(object):
def __init__(self):
self.name = 'enging_name'
def accept(self, visitor):
visitor.visit_engine(self)
class Body(object):
def accept(self, visitor):
visitor.visit_body(self)
class Car(object):
"""
我们要组合成车
"""
def __init__(self):
self.engine = Engine()
self.body = Body()
self.wheels = [Wheel("front left"), Wheel("front right"),
Wheel("back left"), Wheel("back right")]
def accept(self, visitor):
"""
这个也不需要在动,他只是上面部件的组合,只是做了属性的委托
:param visitor:
:return:
"""
visitor.visit_car(self)
self.engine.accept(visitor)
self.body.accept(visitor)
for wheel in self.wheels:
wheel.accept(visitor)
class PrintVisitor(object):
"""
访问者,每次的修改都在这里面
"""
def visit_wheel(self, wheel):
print "Visiting " + wheel.name + " wheel"
def visit_engine(self, engine):
print 'enging_name:{}'.format(engine.name)
print "Visiting engine"
def visit_body(self, body):
print "Visiting body"
def visit_car(self, car):
print "Visiting car"
if __name__ == '__main__':
car = Car()
visitor = PrintVisitor()
car.accept(visitor)
output:
Visiting car
enging_name:enging_name
Visiting engine
Visiting body
Visiting front left wheel
Visiting front right wheel
Visiting back left wheel
Visiting back right wheel