今天,我们一起来探讨最后一个、最复杂的设计模式 访问者模式;它表示一个作用于某个对象结构中的各个元素的操作。它使你可以在不改变个元素的类前提下,定义作用于这些元素的新操作。这个地方要注意:1.需要有个对象结构类用于存储循环遍历的方法的方式;2.访问者模式是对元素的操作;3.可以任意添加对这些元素的新操作。确实有点复杂,我们先看看其结构图:
代码部分:
Visitor类抽象声明了对各种类型元素的访问方法;
abstract class Visitor
{
public abstract void VisitConcreteElementA(ConcreteElementA elementA);
public abstract void VisitConcreteElementB(ConcreteElementB elementB);
}
ConcreteVisitor1 和ConcreteVisitor2 分别定义两种不同访问状态下的对各种元素的实际操作;
class ConcreteVisitor1:Visitor
{
public override void VisitConcreteElementA(ConcreteElementA elementA)
{
Console.WriteLine("1元素{0}被{1}访问",elementA.GetType().Name,this.GetTye().name);
}
public override void VisitConcreteElementB(ConcreteElementB elementB)
{
Console.WriteLine("1元素{0}被{1}访问",elementB.GetType().Name,this.GetTye().name);
}
}
class ConcreteVisitor2:Visitor
{
public override void VisitConcreteElementA(ConcreteElementA elementA)
{
Console.WriteLine("2元素{0}被{1}访问",elementA.GetType().Name,this.GetTye().name);
}
public override void VisitConcreteElementB(ConcreteElementB elementB)
{
Console.WriteLine("2元素{0}被{1}访问",elementB.GetType().Name,this.GetTye().name);
}
}
Element是对元素的抽象类,声明了元素根据传入的访问状态进行的操作方法;
abstract class Element
{
public abstract void Accept(Visitor visitor);
}
具体的元素类:ConcreteElementA、ConcreteElementB ;具体的定义了元素访问方式;这个地方我们要提到二次分派的技术。什么是二次分派?就是先方法状态以参数的形式传输给具体的元素类,然后又根据传入的访问状态的方法并将自身以参数的形式传入;
class ConcreteElementA : Element
{
public override void Accept(Visitor visitor)
{
//这个地方用药2次分派的技术,让操作与数据结构的分离
visitor.VisitConcreteElementA(this);
}
//其他方法的定义
public void OperationA()
{
}
}
class ConcreteElementB : Element
{
public override void Accept(Visitor visitor)
{
//这个地方用药2次分派的技术,让操作与数据结构的分离
visitor.VisitConcreteElementB(this);
}
//其他方法的定义
public void OperationB()
{
}
}
class ObjectStructure
{
private IList<Element> list=new List<Element>();
public void Attach(Element element)
{
list.Add(element);
}
public void Detach(Element element)
{
list.Delete(element);
}
public void Accept(Visitor visitor)
{
foreach(Element a in list)
{
a.Accept(visitor);
}
}
}
static void Main(string[] arg)
{
ObjectStructure o=new ObjectStructure();
o.Attach(new ConcreteElementA());
o.Attach(new ConcreteElementB());
ConcreteVisitor1 v1=new ConcreteVisitor1();
ConcreteVisitor2 v2=new ConcreteVisitor2();
o.Accept(v1);
o.Accept(v2);
//如果新增加操作则如以下代码
//ConcreteVisitor3 v3=new ConcreteVisitor3();
//o.Accept(v3);
}
好了,现在想想啥时候我们用这种模式?一般在数据结构相对比较稳定的时候,我们采用此模式进行编码;这种模式最大的好处在于把数据结构和作用于上的操作直接耦合性降低了;方便我们新增对元素的操作;但是这个设计模式也有弊端:要求数据结构元素的类型必须相对稳定。