Visitor设计模式解决的问题是: 当我们需要为一组稳定的继承结构的各类,添加一些方法, 但是我们又不能在这些类里面修改来添加新方法, 也就是为了遵守面向对象设计中的"对扩展开放,对修改关闭"的原则.
下面我们来看一个列子:
就以老师来举例吧, 我们学院有不同的专业, 每个专业的老师上的课也不一样, 比如: 我们可视化专业, 主要是学习.NET知识, 而软件技术专业的主要学习JAVA, 所以每个专业的老师备课就不一样的, 可视化专业的老师备课.NET知识, 软件技术专业的老师备课JAVA知识,这样我们就可以构建一个这样类结构出来:
![]()
看上面的类的关系图, Teacher是一个抽象类父类, 下面继承了2个子类, 一个是VisualTeacher,可视化的老师,一个是SoftTeacher,软件技术的老师;
这个两个子类都实现了自己的备课方法,如下代码:
1 public abstract class Teacher 2 { 3 public abstract void PrepareLesson(); 4 5 } 6 7 public class VisualTeacher : Teacher 8 { 9 public override void PrepareLesson() 10 { 11 //备课.NET 12 } 13 14 } 15 16 17 public class SoftTeacher : Teacher 18 { 19 public override void PrepareLesson() 20 { 21 //备课JAVA 22 } 23 24 }
现在我们要提出新的需求了, 我现在要为每个专业的老师添加一个上课行为, 只要我们有一点儿面向对象分析的能力的都会想到,这个还不容易,在父类Teacher里面添加一个抽象的方法Teach,然后每个子类重写不就实现了吗,类图关系如下:
代码如下:
1 public abstract class Teacher 2 { 3 public abstract void PrepareLesson(); 4 5 public abstract void Teach(); 6 7 } 8 9 public class VisualTeacher : Teacher 10 { 11 public override void PrepareLesson() 12 { 13 //备课.Net.. 14 } 15 16 public override void Teach() 17 { 18 //教授.Net.. 19 } 20 21 } 22 23 public class SoftTeacher : Teacher 24 { 25 public override void PrepareLesson() 26 { 27 //备课JAVA.. 28 } 29 30 public override void Teach() 31 { 32 //教授JAVA.. 33 } 34 35 }
的确实现了, 但是这样违背的面向对象分析与设计的"对扩展开放,对修改封闭", 我们不可能把已经生成好的assembly修改吧, 所以这种解决办法的方式是不行的!
所以这里我们就要引入GoF模式之一的Visitor访问者模式!
首先我们看看这个在GoF模式教程中的类图结构:
下面我们就带着我们刚才提到的问题进行修改,我们刚才的类图:
代码:
1 public abstract class BehaviorVisitor 2 { 3 public abstract void Visit(VisiualTeacher visualTeacher); 4 5 public abstract void Visit(SoftTeacher softTeacher); 6 7 } 8 9 public class TeachVisitor : BehaviorVisitor 10 { 11 public override void Visit(VisiualTeacher visualTeacher) 12 { 13 //授课.NET 14 } 15 16 public override void Visit(SoftTeacher softTeacher) 17 { 18 //授课JAVA 19 } 20 } 21 22 public abstract class Teacher 23 { 24 public abstract void PrepareLesson(); 25 26 public abstract void Accept(BehaviorVisitor behaviorVisitor); 27 28 } 29 30 public class VisualTeacher : Teacher 31 { 32 public override void PrepareLesson() 33 { 34 //备课.NET 35 } 36 37 public override void Accept(BehaviorVisitor behaviorVisitor) 38 { 39 behaviorVisitor.Visit(this); 40 } 41 42 } 43 44 public class SoftTeacher : Teacher 45 { 46 public override void PrepareLesson() 47 { 48 //备课JAVA 49 } 50 51 public override void Accept(BehaviorVisitor behaviorVisitor) 52 { 53 behaviorVisitor.Visit(this); 54 } 55 } 56 57 58 //客户端使用 59 BehaivorVisitor visitor = new TeachVisitor(); 60 Teacher t = new VisualTeacher(); 61 t.Accept(visitor); //调用可视化老师的授课方法. 62 //这样就实现了方法的动态添加, 而不用修改原始的类
看看上面的类图和代码,我们会发现, 在原始的Teacher类,以及它的子类里面多了一个Accept方法,这个方法是最关键的, 他实现动态方法的模板;
然后又多了一个BehaviorVisitor类, 该类定义了动态方法的访问者抽象类, 所有动态方法都从该抽象类进行扩展, 如上面我们扩展了授课的方法的访问者子类(TeachVisitor);
这个BehaviorVisitor抽象类以及它的子类,就在Accept方法中起到了作用.
这样我们就可以 动态的进行扩展更的方法, 再如: 每个专业的老师还会有"开会"的方法, 而可视化专业和软件技术专业的"开会"的方式可能会不一样, 这样我们又可以扩展出会议方法的访问者:MeetingVisitor : BehaviorVisitor. 只要有共同的方法, 而且实现又不相同, 我们就可以进行行为访问者抽象类BehaviorVisitor进行扩展, 这样就遵守了"开放扩展,关闭修改"的原则, 解决了我们最开始提出的问题;
不知道大家注意到没有, 我上面在提出问题的时候, 用红色标出的字体"稳定", 稳定的意思就是说, 继承层次结构是稳定的前提下才能用该设计模式, 例如我们上面提出的例子, Teacher,VisualTeacher,SoftTeahcer, 他们是稳定的, 没有必要再进行扩展出更多的教师类出来, 意思就是只有这么类了. 这个是访问者模式的缺点. 也只有满足了该缺点的情况下才能使用该模式!
还有, 细心的并理解了该设计模式的读者,应该能够发现了, 这里面用到了个多态的地方, 一个是BehaviorVisitor抽象类里面的Visit方法, 一个是Teacher类里面的Accept方法, 这两个方法都父类派生出子类进行多态实现. 这里的多态的行为也叫"多态辨析", 然后在该设计模式中, 这2个方法的多态辨析, 就称为 "双重分发(double dispatch)"
Visitor访问者模式
最新推荐文章于 2024-08-29 17:15:49 发布
Visitor设计模式解决的问题是: 当我们需要为一组稳定的继承结构的各类,添加一些方法, 但是我们又不能在这些类里面修改来添加新方法, 也就是为了遵守面向对象设计中的"对扩展开放,对修改关闭"的原则.
下面我们来看一个列子:
就以老师来举例吧, 我们学院有不同的专业, 每个专业的老师上的课也不一样, 比如: 我们可视化专业, 主要是学习.NET知识, 而软件技术专业的主要学习JAVA, 所以每个专业的老师备课就不一样的, 可视化专业的老师备课.NET知识, 软件技术专业的老师备课JAVA知识,这样我们就可以构建一个这样类结构出来:
![]()
看上面的类的关系图, Teacher是一个抽象类父类, 下面继承了2个子类, 一个是VisualTeacher,可视化的老师,一个是SoftTeacher,软件技术的老师;
这个两个子类都实现了自己的备课方法,如下代码: