[TOC]
原理
示例
学生(C#实现)
一个班级里有学霸和学渣两种类型的学生。当出成绩时,学霸开心,学渣不开心。当放假时,学霸不开心,学渣开心。
未来不会有第三种类型的学生,但未来可能会有新的事件发生,比如布置作业、春游等。
第一版
伪代码:
1 | class Program |
但这样写明显不符合面向对象的开放封闭原则,怎么改呢?
初步重构
有一个容易想到的方法,就是把出成绩和放假作为一个抽象方法,写到抽象学生类里面,学霸和学渣分别实现这两个方法
1 |
|
这样看上去很符合开放封闭原则,因为如果有新的类型的学生,只需要添加一个新的学生类,让它去实现两个抽象方法即可,不用改其它类的代码。
但仔细看需求,题目说不会有新的类型学生,而是会有新类型的事件!
也就是说,如果现在要春游,就需要在抽象学生类里加一个springOuting()
方法,然后分别在学霸和学渣里实现。一共需要改三个类!一点也不符合开放封闭原则。
所以一定要搞清楚固定的东西是什么,可能会变的东西是什么。
使用访问者模式重构
因为会变的是遍历列表时对学生的访问方法(出成绩、放假、春游),而不是学生类型(学霸、学渣),所以这里就不应该像上面那样将学生的行为抽象,而是应该将访问的方式抽象:
1 | /// <summary> |
这样写好以后,要添加访问方法(出成绩、放假、春游),只需要继承Visitor类,并实现学霸和学渣分别不同的反应即可。比如:
1 | public class ReleaseScoreVisitor : Visitor |
调用:
1 | class Program |
现在要添加访问方法(放假、春游等),就只需要添加访问方式类,而不需要修改写好的类,这样才真正符合开放封闭原则。
在遍历集合时,把访问单个对象的方式抽象出来,这就是访问者模式。
所以说,一定要搞清楚固定的东西是什么,可能会变的东西是什么,才好理解访问者模式的思想。