Visitor Pattern(访问者模式)
书上的定义:
“作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.”
其中对象群指的是一个数据集合,例如一个链表,一个List,一个Collection等等……
先看一下不用该模式之前的代码:
Before Visitor Pattern
public interface ITest1
{
String GetStr1();
}
public interface ITest2
{
String GetStr2();
}
public class Test1 : ITest1
{
public String GetStr1()
{
return "Test1";
}
}
public class Test2 : ITest2
{
public String GetStr2()
{
return "Test2";
}
}
public class Program
{
public static void Main(string[] args)
{
ArrayList list = new ArrayList();
list.Add(new Test1());
list.Add(new Test2());
for (int i = 0; i < list.Count; i++)
{
if (list[i] is ITest1)
{
Console.WriteLine(((ITest1)list[i]).GetStr1());
}
else if (list[i] is ITest2)
{
Console.WriteLine(((ITest2)list[i]).GetStr2());
}
}
}
}
该段代码不难理解,定义了两个接口,然后有两类分别实现这两个接口,这样我们得到了两个完全不同类型的类,然后我们将他们放入到同一个ArrayList当中,然后遍历每一个对象,执行一下里面的操作,这个时候我们发现,当我们遍历他们的时候必须首先要判断他们的类型,才能根据类型调用相应的方法,于是,如果这个ArrayList里面放了过多的不同类型的类时,代码就会变得非常难看,需要非常多的if .. else if.. else if.. … .. else才能够完成这样的操作,Visitor模式就是为了解决这个问题。
下面是用Visitor模式实现的代码,先贴代码:
After Visitor Pattern
public interface ITest1
{
String GetStr1();
}
public interface ITest2
{
String GetStr2();
}
public interface ITest
{
string Accept(IVisitor visitor);
}
/// <summary>
/// Defines override methods for each type.
/// </summary>
public interface IVisitor
{
string VisitorObject(ITest1 t);
string VisitorObject(ITest2 t);
}
/// <summary>
/// Implement override methods for each type.
/// </summary>
public class Visitor : IVisitor
{
public string VisitorObject(ITest1 t)
{
return t.GetStr1();
}
public string VisitorObject(ITest2 t)
{
return t.GetStr2();
}
}
public class Test1 : ITest1, ITest
{
public String GetStr1()
{
return "Test1";
}
public string Accept(IVisitor visitor)
{
return visitor.VisitorObject(this);
}
}
public class Test2 : ITest2, ITest
{
public String GetStr2()
{
return "Test2";
}
public string Accept(IVisitor visitor)
{
return visitor.VisitorObject(this);
}
}
public class Program
{
public static void Main(string[] args)
{
ArrayList list = new ArrayList();
list.Add(new Test1());
list.Add(new Test2());
IVisitor visitor = new Visitor();
for (int i = 0; i < list.Count; i++)
{
((ITest)list[i]).Accept(visitor);
}
}
}
如上面的code所示,我们首先定义一个ITest接口,把所有这些需要放在ArrayList中的类型都集成这个接口,并且实现里面的Accept方法,这个Accept方法是Visitor模式的关键,我们遍历所有的类型,都通过ITest的接口进行调用Accept方法,来达到调用原来通过if else来调用各不相同的方法的目的,怎么实现的呢?
Accept方法里面会调用Visitor类里面的方法,我们会发现,Visitor类里面有非常多的重载方法,针对每一个不同类型的类都有一个对应的重载方法,这个重载方法完成了需要完成的动作,当我们调用Accept方法的时候,根据.NET的机制,实际运行的是那个实例的内部实现的Accept逻辑,当运行到这里的时候,我们就可以知道这个实例的类型了,这个就是Visitor模式实现的依据,在原来不用该模式的时候,我们拿到了list[0],list[1],都只是一些object类型,我们不知道他们的具体类型,但是我们又不想通过if else来判断他们的type,通过这种接口方法的调用,直接调用到该实例的内部,这样子就可以使知道他的具体类型了,然后再这个时候,调用Visitor类里面的重载方法,就可以找到相应的方法来调用相应的逻辑了,这就是Visitor模式,巧妙吧~~