Visitor访问者模式

来源:互联网 发布:c语言算法教程 编辑:程序博客网 时间:2024/06/08 11:09

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       //备课.NET12    }13 14 }15 16 17 public class SoftTeacher : Teacher18 {19    public override void PrepareLesson()20    {21       //备课JAVA22    }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 : Teacher10 {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 : Teacher24 {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 : BehaviorVisitor10 {11    public override void Visit(VisiualTeacher visualTeacher)12    {13       //授课.NET14    }15    16    public override void Visit(SoftTeacher softTeacher)17    {18       //授课JAVA19    }20 }21 22 public abstract class Teacher23 {24    public abstract void PrepareLesson();25    26    public abstract void Accept(BehaviorVisitor behaviorVisitor);27 28 }29 30 public class VisualTeacher : Teacher31 {32    public override void PrepareLesson()33    {34       //备课.NET35    }36    37    public override void Accept(BehaviorVisitor behaviorVisitor)38    {39       behaviorVisitor.Visit(this);40    }41 42 }43 44 public class SoftTeacher : Teacher45 {46    public override void PrepareLesson()47    {48       //备课JAVA49    }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)"