访问者设计模式






4.89/5 (21投票s)
本文展示了一个案例研究,关于我们如何在日托中心奖励系统中使用访问者模式。
背景
再次来到我最喜欢的地方 - 伊丽莎白的日托中心。
在之前的文章中,我讨论了如何使用策略模式来开发一个医生就诊系统。 在那种情况下,我只关注了Doctor
对象,以说明当策略对象(不同的医生)更改时,这些动态操作将如何受到影响。
在本文中,我将重点关注那些可访问/Kid
对象,这些对象由Doctor
s检查。
在伊丽莎白的日托中心日历上,显示王医生 (EyeDoctor
) 每个月 15 号为所有孩子进行视力筛查,Fong 医生 (SLP
- 语言病理学家) 每个月 28 号进行语言评估。 并且家长可以随时探望他们的孩子。
对于每次访问者的访问,在医生访问后,所有相关的状态都需要更新。 EyeDoctor
将仅更新EyeStatus
,而 SLP 也会更新SpeechStatus
。 家长将同时更新 EyeStatus
和 SpeechStatus
。
请记住,孩子们可能会被不同的访问者访问。 它可以允许任何类型的访问者访问,但是,访问者应该知道在他们访问之后需要为孩子更新什么状态。
引言
访问者模式可以帮助我们解耦特定可访问对象的运算细节与多个访问者对象。 当这些对象需要为 visitableObject
(Kid
) 实现自己的逻辑时,我们将责任隔离在单独的访问者对象(例如 EyeDoctor
、SLP
和 Parent
)中。
本文介绍了我们如何将访问者模式应用于我们的日托中心。
访问者设计模式结构

类图

实现代码
访问者对象
访问者
Visitor
类是我们的基本 abstract
类。 这里声明了一个 abstract public
方法 (Visit
) 以允许子类实现细节。 它将一个 VisitableObject
对象作为参数。 它实际上为子 Visitor
类提供了围绕它工作的能力。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace VisitorDesignPattern
{
public abstract class Visitor
{
abstract public void Visit(VisitableObject akid);
}
}
}
眼科医生
在我的 EyeDoctor
类中,一个子 Visitor
类,它只会更新传入 visitableObject
的 eyestatus
。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace VisitorDesignPattern
{
public class EyeDoctor : Visitor
{
//Visit the visitableObject and update the deserved information
public override void Visit(VisitableObject akid)
{
Kid kid = (Kid)akid;
kid.EyeStatus = "Status updated from EyeDoctor -
Message from Dr.WANG, Eye Infections found for " + kid.Name + ".
Please schedule an appointment asap";
}
}
}
}
SLP
与 EyeDoctor
相同,SLP 类将仅更新传入 visitableObject
的 Speechstatus
。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace VisitorDesignPattern
{
public class SLP : Visitor
{
public override void Visit(VisitableObject akid)
{
Kid kid = (Kid)akid;
kid.SpeechStatus = "Status updated from SLP - This is Dr.FONG, " +
kid.Name + " did a good job on the speech exam.";
}
}
}
}
Parent
与 EyeDoctor
相同,Parent
类将同时更新传入 visitableObject
的 Eyestatus
和 Speechstatus
。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace VisitorDesignPattern
{
public class Parent : Visitor
{
public override void Visit(VisitableObject akid)
{
Kid kid = (Kid)akid;
kid.EyeStatus += Environment.NewLine +
"Status updated from Parent -- This is " + kid.Name +
"'s parent, I updated the EyeStatus.";
kid.SpeechStatus += Environment.NewLine +
"Status updated from Parent -- This is " + kid.Name +
"'s parent, I updated the SpeechStatus.";
}
}
}
}
VisitableObject 类
VisitableObject
VisitableObject
类是一个 abstract
基类,它有一个 public
方法 (AcceptVisitor
)。 AcceptVisitor
方法是我们访问者模式中的关键方法。 它将一个 Visitor
对象作为参数,这将调用其 Visit
函数来访问它自己的 visitableObject
(visitableObject
的一个实例),以便实现访问模式。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace VisitorDesignPattern
{
public abstract class VisitableObject
{
public void AcceptVisitor(Visitor visitor)
{
//allow the incoming visitor to start visiting
visitor.Visit(this);
}
}
}
}
Kid 类
这里的 Kid
类是一个从 VisitableObject
继承的辅助类。 它保存每个孩子的个人信息。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace VisitorDesignPattern
{
public class Kid : VisitableObject
{
public string Name { get; set; }
public int Age { get; set; }
public string EyeStatus { get; set; }
public string SpeechStatus { get; set; }
}
}
}
客户端应用程序
从客户端来看,我创建了两个孩子作为我们的 visitableObject
对象,并将它们添加到日托中心。 而且我还创建了一个访问者集合,它包含一个 EyeDoctor
、一个 SLP
和一个 Parent
。 对于每个孩子,她/他将受到来自访问者集合的每个访问者的访问。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using www.askbargains.com.VisitorDesignPattern;
namespace www.askbargains.com
{
namespace Client
{
class Program
{
static void Main(string[] args)
{
List<kid> dayCare = new List<kid>();
//Kid Elizabeth is created
Kid Elizabeth = new Kid();
Elizabeth.Name = "Elizabeth";
Elizabeth.Age = 3;
//add Elizabeth to daycare
dayCare.Add(Elizabeth);
//Kid Aimee is created
Kid Aimee = new Kid();
Aimee.Name = "Aimee";
Aimee.Age = 4;
//add Aimee to daycare
dayCare.Add(Aimee);
//create Visitors
List<visitor> visitors = new List<visitor>();
visitors.Add(new EyeDoctor());
visitors.Add(new SLP());
visitors.Add(new Parent());
//start looping all the visitors
foreach (Visitor visitor in visitors)
{
//kid start to be visited for each visitor
foreach (Kid oneKid in dayCare)
{
oneKid.AcceptVisitor(visitor);
}
}
//display result
foreach (Kid oneKid in dayCare)
{
Console.WriteLine("Display Status for " + oneKid.Name);
Console.WriteLine(oneKid.EyeStatus);
Console.WriteLine(oneKid.SpeechStatus);
Console.ReadLine();
}
Console.ReadLine();
}
}
}
}
一旦我们启动我们的客户端应用程序,您将看到在输出窗口中每次访问者访问后,对应的状态都已更新。 太棒了!

结论
从本文中,我展示了我们如何使用访问者模式来实现日托访问者的实现。 我还在 我的另一篇文章 中使用日托中心进行装饰器设计模式。